Can wise men explain this code to me?

Discussion in 'Programmer's Corner' started by Jaden5165, Sep 20, 2011.

  1. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0
    Code ( (Unknown Language)):
    1.  
    2. #include <htc.h>
    3. #define _XTAL_FREQ 4000000
    4. __CONFIG(0x3F39);
    5. void main()
    6. {
    7. [COLOR=darkorange]unsigned char sGPIO=0;  //shadow copy of GPIO[/COLOR]
    8. unsigned char dcnt;     //delay counter
    9. //initialisation
    10.  
    11. [COLOR=darkorange]TRISIO=~(1<<1);  [/COLOR][COLOR=#000000]//configure GP1 (only) as an output[/COLOR]
    12. [COLOR=#ff8c00][/COLOR]
    13. //Main loop
    14. for(;;)
    15. {
    16.  //toggle GP1
    17.  [COLOR=darkorange]sGPIO ^= 1<<1[/COLOR];//flip shadow bit corresponding to GP1
    18.  [COLOR=darkorange]GPIO = sGPIO;//[/COLOR]write to GPIO
    19. //delay 500ms
    20. for(dcnt=0;dcnt<5;dcnt++)
    21. {
    22. __delay_ms(100);
    23. }
    24. }//repeat
    25. }
    26.  


    I got this code from this website
    http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_1.pdf
    it's a pdf file and the code is taken from page[16]


    can you explain to me in a more simple way or modify the code to a more understanfable code.
    especially those highlighted(what shadow and what symbol represent for that ^=1<<1).
    assume if change to using pic16f877a instead of using the same pic as this example.this example is using pic12f629.
    i need to understand this before going to the following page especially page[21] that about switch debounce.
     
    Last edited: Sep 20, 2011
  2. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    Its very simple,its like this......oohh wait I guess I am not wise enough....

    A shadow variable is nothing but a variable which stores the current contents of some register like GPIO1,For example if GPIO1's current value is 100 then
    Code ( (Unknown Language)):
    1.  
    2. unsigned int shadow = 0x00;
    3. shadow = GPIO1;
    4.  
    using this code you can store the value of GPIO1 into shadow variable, so that you can use it later without modifying or accessing GPIO1.Think its like a shadow of some register and here the shadow means the value of that register.

    For that you have to understand binary operations in language C i.e.. you have to learn about bitwise operators. Google for C tutorial and check out about bitwise operators.
    The program flash a LED on GP1 with 50% duty cycle, here is how you can do it with PIC16F877A instead of GP1 which is not their in this PIC I am using RB1

    Code ( (Unknown Language)):
    1.  
    2. #include "htc.h"
    3. #ifndef _XTAL_FREQ
    4. #define _XTAL_FREQ 4000000
    5. #endif
    6. void main()
    7. {
    8.  unsigned int shadow = 0x00;//shadow copy of PORTB
    9.  unsigned int count = 0x00;//delay counter
    10.  PORTB = 0x00;
    11.  TRISB = 0x00; //Config PORTB as outputs
    12.  shadow = PORTB;
    13.  for(;;)
    14.  {
    15.    shadow ^= (1<<1);//toggle bit 1 ,bit 1 of shadow is bit 1 of PORTB i.e.. RB1
    16.    PORTB = shadow;//assign the shadow's value to PORTB.
    17.  
    18.   //make a delay for 1sec
    19.   for(count = 0;count<10;count++)
    20.   {
    21.    __delay_ms(100);
    22.    }
    23.  }
    24. }
    25.  
    Check datasheet for configuration bit settings...

    Good Luck
     
    Last edited: Sep 20, 2011
    Jaden5165 likes this.
  3. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0
    Code ( (Unknown Language)):
    1.  
    2. #include <htc.h>
    3. __CONFIG(0x3F39);
    4. #define _XTAL_FREQ 4000000
    5. void main()
    6. {
    7.  unsigned char shadow = 0x00;//shadow copy of PORTB
    8.  unsigned char count = 0x00;//delay counter
    9.  TRISB = 0x00; //Config PORTB as outputs
    10.  PORTB = 0x00;
    11.  
    12.  shadow = PORTB;
    13.  for(;;)
    14.  {
    15.    shadow^=0b00000010;      //toggle bit 1 ,bit 1 of shadow is bit 1 of PORTB i.e.. RB1
    16.    PORTB = shadow;                //assign the shadow's value to PORTB.
    17.  
    18.   //make a delay for 1sec
    19.   for(count = 0;count<10;count++)
    20.   {
    21.    __delay_ms(100);
    22.    }
    23.  }
    24. }
    25.  

    when i program this code into my pic my led cannot turn on.any problem?but it can be successfully built.
     
  4. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    Have you tried a do-nothing program like this?

    Code ( (Unknown Language)):
    1.  
    2. TRISB = 0x00;
    3. PORTB = 0xFF;
    4. while(1) ;
    5.  
    If the LED doesn't come on, you've got something wrong with your wiring.
     
  5. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0

    @John P
    what do you mean by a do nothing program?
     
  6. GetDeviceInfo

    Senior Member

    Jun 7, 2009
    1,571
    230
    simple loops that aid in troubleshooting but have no real use otherwise.
     
  7. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Geezer, I hope this wasn't code from a instructional tutorial. That is some excellent examples of C code being "write-only" (meaning only the person who wrote it could ever understand it).

    However, I have seen where obscure code such as this actually compiles to fewer steps in the final program, and once where I needed every byte I wrote such code too.

    OK, shadow register was covered, but not the WHY. One thing PICs have a problem with is something called "read-modify-write" (or r-m-w) which is how bits get set. Inside one statement the register is read (read), the value changed (modify), then it is written back (write). Now in some cases the read portion gets the wrong value, especially when the bit is an output pin (it may not have reached it's new value yet, so is read wrong).

    Doing the "real work" on a shadow register then copping the shadow to the read register is a good way around the r-m-w problem.

    Code ( (Unknown Language)):
    1. TRISIO=~(1<<1);
    In pieces: The "<<" is a shift command, "a<<b" means "shift a to the left b times." So 1<<1 means shift 1 left once, so you start with 0000 0001 and you get 0000 0010.

    Next piece is the tilda ~: it means compliment or bitwise inversion. If you put 0000 0010 in you get 1111 1101 out. In PICs setting TRIS to 0 is 0utput and to 1 means 1nput. So that value sets TRISIO1 as output, the rest as input.

    Code ( (Unknown Language)):
    1. sGPIO ^= 1<<1;//flip shadow bit corresponding to GP1
    The ^ thing is a bitwise exclusive or, here using to invert a single bit.

    But before we use that, start from before the equals sign. C has a shorthand for things like:

    A = A + 1;

    By letting you say:

    A += 1;

    So we already covered what 1<<1 means (0000 0010) so sGPIO ^= 0b00000010 will just flip the second bit and leave everything else the same.


    Code ( (Unknown Language)):
    1. GPIO = sGPIO;//write to GPIO
    Note he used the shadow register to create his value, then copies the shadow to the real register.
     
    Jaden5165 likes this.
  8. cheezewizz

    Active Member

    Apr 16, 2009
    82
    10
    "OK, shadow register was covered, but not the WHY."

    That's not entirely true, I really liked these tutorials when starting out, they helped immensely. IIRC they cover both the why and how to use shadow registers, and it does explain fairly early on that's it's not an introduction to C just the specifics concerned with C for microcontrollers...
     
  9. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186

    First of all the code was for PIC16F877A ,I think you are using that.Now to solve this problem we need some more info i.e..
    1) Schematic i.e.. Circuit diagram.
    2) Which programmer you are using and does it confirms about a successful programming
    3) Is your programmer capable to load configuration bit settings from hex file, if not you have to set it in your programmer otherwise it will not work.


    A program which just tests a simple task of the mcu to verify that the circuit for the mcu is ok.In case of John P, he set PORTB as output and set all the pins high so that while running the circuit you could check this simple stuff and be sure the circuit is working properly. If not there is some hardware problem.

    Why we are using this simple code to test, not any other code, because other codes might contain library functions and use of some integrated modules which can lead to complex code and their may be some code bugs (errors) and we can’t be sure of the exact problem i.e.. hardware or software.And with simple PORT test we can be sure that their will be no problem with the software part, but remember many PIC’s PORT pins are multiplexed with other modules so setting them might not be so easy. Like in this case PORTA is multiplexed with ADC module to set the PORTA’s pins you have to disable ADC first.

    Good luck
     
    Jaden5165 likes this.
  10. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0



    finally,my pic can work with the code.thank for your opinions.i check again my programmer and reprogram my pic then it can work.^^
     
  11. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0
    Code ( (Unknown Language)):
    1. GPIO1=GPIO1 ? 0 : 1;
    what is this code mean?


    Code ( (Unknown Language)):
    1. GPIO=GPIO3 ? 0: 0b000010;
    and what about this?
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    More obscure c code, gotta love this. I actually like that format, and once you get comfortable with it you can use it to good advantage in writing some compact code.

    The ? means test, followed by a true and a false value. So:
    Code ( (Unknown Language)):
    1. GPIO1=GPIO1 ? 0 : 1;
    has the same meaning as:
    Code ( (Unknown Language)):
    1. if (GPIO1)
    2.     GPIO1=0;
    3. else
    4.     GPIO1=1;
    Note that "if (GPIO1)" is false when GPIO1 is zero, otherwise true.

    I prefer to use parenthesis to make the intent a bit clearer:
    Code ( (Unknown Language)):
    1. LD0 = (LedState & 0x01) ? LED_ON : LED_OFF;
     
    Jaden5165 likes this.
  13. Jaden5165

    Thread Starter Member

    Sep 9, 2011
    69
    0



    wow,feel good.learn a lot from you guys!!!
     
  14. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    ErnieM already explained how that code works but remember it is not same as "if-else", it is known as ternary operator in language C and its a true operator rather a conditional statement like if-else. The if-else statement will not produce a value but this ternary operator will, it’s like this
    Code ( (Unknown Language)):
    1.  
    2. [COLOR=black][FONT=Verdana]a = (--b) ? (b) : (b = 100) ;[/FONT][/COLOR]
    3.  
    Before explaining the above code you should understand this ,in language C/C++ the value of 0 is taken as false and any other non zero value is taken as true like 1,2,-1 etc.So in the above code a will be assigned to the value of b if the result of decrementing of b is non zero i.e.. true ,else if b becomes zero i.e.. false then a and b both are assigned to 100.Many times people are confused with ternary operators so if you are too ,then no need to use them just use if-else statement like ErnieM showed.

    Good Luck
     
    Last edited: Sep 21, 2011
    Jaden5165 likes this.
Loading...