Author Topic: MPLAB X on PIC10F222, getting started.  (Read 19659 times)

0 Members and 1 Guest are viewing this topic.

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #50 on: December 13, 2015, 11:19:05 pm »
Thanks on the code, but I'm afraid it's not really making sense to me. .
The superloop and sandwich delay code becomes:
Code: [Select]
while(1){
   TMR0=0; // Start sandwich delay: 16.384ms (nominal) 'ticks'

   // tasks go here

   while(!(TMR0&0x80)); // Wait for TMR0 top bit to end sandwich delay
}
So i have set the prescaler to 1:256 (max value, should give longer time?), but the last bit: while(!(TMR0&0x80));  what does the ! and the & do?
Quote
The LED task goes something like:
Code: [Select]
{ // LED blinking task
    static unsigned char LEDtime=0;  // LED timer in complete flickers
    static unsigned char LEDcnt=MAXVOLTS;    // LED counter for flicker

    if(button) LEDtime=5; // five complete flicker cycles per button push

    if(LEDtime) {
        LEDtime--;       
        if(LEDcnt>BattVolts) GPIO=RED else GPIO=BLUE;
        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
    }
}
and of course you'll also need #defines for the bits to output for RED and BLUE and the scaled and offset  ADC count MAXVOLTS corresponding to 3.4V on the LiPO.     
This entire bit went completely over my head. .
Sorry for the n00bishness Ian :/
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: MPLAB X on PIC10F222, getting started.
« Reply #51 on: December 14, 2015, 12:24:23 am »
Irrespective of all the other comments:
Code: [Select]
while (GP3 = 0); //Button pressThat while loop will never execute.  You need an "==" instead of the "=" !
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: MPLAB X on PIC10F222, getting started.
« Reply #52 on: December 14, 2015, 12:39:15 am »
Irrespective of all the other comments:
Code: [Select]
while (GP3 = 0); //Button pressThat while loop will never execute.  You need an "==" instead of the "=" !

 :-+

There are those who have, and those who will!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: MPLAB X on PIC10F222, getting started.
« Reply #53 on: December 14, 2015, 12:59:09 am »
If you *don't* have a copy of K&R 2nd ed, you can get by with The C Book, 2nd ed. by Banahan, Brady & Doran.  Its not as well organised but it covers the essentials fairly thoroughly.

Turn to the sections on logical and bitwise operators (2.6 and 2.9 in K&R, 3.3 and 2.8.2.3 in The C Book) and lookup the bitwise AND and logical negation operators.  You will now be equipped to dissect
Code: [Select]
while(!(TMR0&0x80));.   

* First note the trailing ;, this while() loop has no 'payload' - all it does is spin on the spot while its condition is TRUE.  The comment 'Wait for ....' confirms that is my intention.

* Now look in the innermost bracket.  Unfortunately XC8 doesn't define a bitfield for the highest bit of Timer 0 and, unlike any PIC with interrupts, there is no flag set when it rolls over. We need a bitmask to extract the highest bit.  The mask is 0x80 and after ANDING with Timer 0 we have a value that is either 0 0r 0x80. 

* However the requirement is to keep looping till that bit sets, so outside the inner brackets is the negation (NOT) operator.  That converts 0x80 (or any other non-zero value) to 0 (FALSE) and 0 to 1 (TRUE). 

XC8 is fairly smart, and even the free mode recognises this idiom as a test and loop on a single bit  and optimises it to:
Code: [Select]
    85  1FB                     l392:
    86                           ;main222.c: 6: while(!(TMR0&0x80));
    87                           
    88  1FB  7E1                btfss 1,7 ;volatile
    89  1FC  BFB                goto l392
If I'd used the conceptually much simpler:
Code: [Select]
while(TMR0<0x80);it would use far more instructions as it would need to load the constant into W, compare it with TMR0 and then test a STATUS flag to decide what to do:
Code: [Select]
    85  1F9                     l392:
    86                           ;main222.c: 6: while(TMR0<0x80);
    87                           
    88  1F9  C80                movlw 128
    89  1FA  081                subwf 1,w ;volatile
    90  1FB  703                skipc
    91  1FC  BF9                goto l392
You really have to grok the instruction set to get the best out of XC8 on these tiny devices.

The next chunk had a mistake, a missing semicolon in the if() ... else ...:
Code: [Select]
{ // LED blinking task
    static unsigned char LEDtime=0;  // LED timer in complete flickers
    static unsigned char LEDcnt=MAXVOLTS;    // LED counter for flicker

    if(button) LEDtime=5; // five complete flicker cycles per button push

    if(LEDtime) {
        LEDtime--;       
        if(LEDcnt>BattVolts) GPIO=RED; else GPIO=BLUE;
        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
    }
}
The two static unsigned char variable declarations declare local variables that are initialised on startup then retain their values from one invocation of the task block to the next.

if(button) LEDtime=5;  waits for the flag button to be set by the button task, it then sets the flicker cycke count to five.   The button task will clear the flag on the next pass so this only happens once per debounced press.  Alternatively you could let the flag stay set as long as the button is held and the LED task would keep doing the flicker pattern.

    if(LEDtime) {
        LEDtime--;
checks LEDtime and if TRUE, decrements it to count down flicker cycles remaining.

        if(LEDcnt>BattVolts) GPIO=RED; else GPIO=BLUE; turns on the red LED if the flicker counter is greater than the battery voltage otherwise it turns on the blue LED. It also turns off the other colour LED at the same time.  I'm assuming there are only two output pins and each  LED is on one of them.  Bugfix: inserted ; before else.

        if(!LEDcnt--) LEDcnt=MAXVOLTS; //reset flicker counter
counts down for the flicker level and when it wraps around from zero, does what it says and resets it to MAXVOLTS, which Bruce suggested should be 73 in post#38.


   

« Last Edit: December 14, 2015, 04:19:03 am by Ian.M »
 

Offline step_sTopic starter

  • Regular Contributor
  • *
  • Posts: 138
  • Country: dk
Re: MPLAB X on PIC10F222, getting started.
« Reply #54 on: December 14, 2015, 02:53:23 am »
Thank you for explaining Ian. Much appreciated!
When I'm done with my psychology exams, I will pick up a few books on this  :D
From these last posts, I have made the following code:

Code: [Select]
#define _XTAL_FREQ 80000000UL
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/400000000.0)))
#define delay 1000

unsigned char i;

void main(void) {

   ADCON0bits.ANS = 0b01; //Setting GP0 to analog
   ADCON0bits.CHS = 0b00; //Select channel ANS0
   ADCON0bits.ADON = 1; //Enable ADC
   OPTION = 0b00000110; //Enable GP2, & set TMR0 rate 1:128
   TRISGPIO = 0b00001001; //Set GP0 & 3 to input, GP1 & 2 to input
     
   while (1)
   {
       static unsigned char LEDtime= 0; // Char that stays coded

       GP1 = 0; // Resets LEDS
       GP2 = 0; // Resets LEDS
       
       if (GP3 ==0) LEDtime=252; // Button press
   
       if(LEDtime) // If LEDtime = 0
       {
        LEDtime--; // Decrements LEDtime with 1
          ADCON0bits.GO=1; // Read analog data
          while (ADCON0bits.nDONE); // Wait for A/D to convert 
        // LED color setting, fast switching
         GP1 = 1;   // Turn on BLUE LED
         GP2 = 0;   // Turn off RED LED
         for(i=160; i<ADRES; i++) delay_us(delay);   // Delay, 3.2V ref
         GP1 = 0;   // Turn off BLUE LED
         GP2 = 1;   // Turn on RED LED
         for(i=205; i>ADRES; i--) delay_us(delay);   // Delay, 4.2V ref
         GP1 = 1;   // Turn on BLUE LED
         GP2 = 0;   // Turn off RED LED
         for(i=160; i<ADRES; i++) delay_us(delay);   // Delay, 3.2 V ref
         GP1 = 0;   // Turn off BLUE LED
         GP2 = 1;   // Turn on RED LED
         for(i=205; i>ADRES; i--) delay_us(delay);   // Delay, 4.2V ref
         
         if (ADRES<155) //If V<3.1
         { // Blinks red 4 times if under 3.1V
             LEDtime=LEDtime-62; // Decrements LEDtime with 62
             GP2 = 1; // Turn on RED LED
             delay_us(6000000); // 1sec delay
             GP2 = 0; // Turn off RED LED
             delay_us(6000000); // 1sec delay       
         }
         }
   } 
}
As it says in the descriptions. This will show blue at 4.2V, shift to purple, and end at red at 3.2V, for 2sec when button is pressed. If the battery voltage drops below 3.1V, the LED will blink red 4 times instead.
The LED flicker part with the delay from ADRES is pasted twice, for an easy way to double the time shown.

Please let me know if anything looks silly. Even though this works, that doesn't mean that there isn't room for improvements :)
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: MPLAB X on PIC10F222, getting started.
« Reply #55 on: December 15, 2015, 07:44:37 pm »
Please let me know if anything looks silly. Even though this works, that doesn't mean that there isn't room for improvements :)
It works, but your code is a bit hacky and hard to follow, and may easily break if you have to change it. You can improve readability by converting 'magic' numbers to descriptive identifiers and letting the compiler do the grunt work.

First thing I would do is assign each LED to its GPIO port with a #define, like this:-

#define RedLED_ON  GP2=1
#define RedLED_OFF GP2=0

Then, instead of having to add a comment to remind you what 'GP2 = 1' does, you can just do this:-
 
        RedLED_ON;
 
It's a bit more effort initially, but makes the code more readable and will save a lot of time if you ever need to change it. Also you avoid introducing bugs due to not changing all instances.

Avoid putting comments in places where they aren't necessary, and make sure they match the code! For example,

             delay_us(6000000); // 1sec delay

is obviously not a 1 second delay.

On the other hand, liberally comment code whose operation is not obvious. It took me a while to figure out how you got the Red LED to reliably blink 4 times on low voltage. You subtract 62 from the count and stop when it gets to 0, which only works because it was previously decremented in the fast switching code and the initial count (252) is an exact multiple of 63.

 LEDtime=LEDtime-62; // Decrements LEDtime with 62
 
...is a useless and misleading comment. That it subtracts 62 is obvious, but why 62? Also the code will break if you change LEDtime and don't adjust this line to match.

I would do something like this:-

#define BLINKTIME 63  /* count to subtract from LEDtime when blinking Red LED on low voltage */

 if (GP3 ==0) LEDtime = BLINKTIME*4; // set count to keep showing LED display after button released
...
 LEDtime = LEDtime - (BLINKTIME-1); // -1 to account for decrement in fast switching

Or, change the algorithm it so that on low voltage it avoids the fast switching code altogether. That way you can adjust the timing of each function separately and don't have to worry about interaction between them.   
 
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf