Quick PIC code definition

Discussion in 'Programmer's Corner' started by blah2222, Jun 10, 2011.

  1. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Hi, I just have a question regarding the syntax of this sample code that I was given to learn from. The code essentially is a 4-bit up-counter that lights up LEDs attached to pins RB12-15 on a PIC24HJ32P202 mcu.

    The code is from Reese Micro, and after playing around with this, I thought I knew what was going on, but apparently I don't...

    Anyway this is the code:

    Code ( (Unknown Language)):
    1.  
    2. // 4-bit binary counter on PortB LEDs
    3. // PIC24HJ32GP202 running at ~40 MIPS
    4.  
    5. #include "pic24_all.h"
    6.  
    7. static inline void configure_inputs_from_switches(){
    8.     CONFIG_RA0_AS_DIG_INPUT();
    9.     ENABLE_RA0_PULLUP();   
    10.     CONFIG_RA1_AS_DIG_INPUT();
    11.     ENABLE_RA1_PULLUP();
    12.     CONFIG_RA2_AS_DIG_INPUT();
    13.     ENABLE_RA2_PULLUP();
    14.     CONFIG_RA3_AS_DIG_INPUT();
    15.     ENABLE_RA3_PULLUP();
    16.     CONFIG_RA4_AS_DIG_INPUT();
    17.     ENABLE_RA4_PULLUP();
    18. }
    19.  
    20. static inline void configure_outputs_to_LEDs(){
    21.     CONFIG_RB15_AS_DIG_OUTPUT();
    22.     CONFIG_RB14_AS_DIG_OUTPUT();
    23.     CONFIG_RB13_AS_DIG_OUTPUT();
    24.     CONFIG_RB12_AS_DIG_OUTPUT();
    25. }
    26.  
    27. int main (void)            
    28. {
    29.  
    30.         configure_inputs_from_switches();
    31.         configure_outputs_to_LEDs();
    32.  
    33.     while (1) {                 // Loop forever
    34.  
    35.         PORTB=LATB+1;    // LATB is the current value on Port B
    36.         DELAY_US(100);   // 100 microsecond delay gives approx 0.5
    37.                          //second count period of 4 msb's of PortB
    38.     }
    39. }
    40.  
    I understand why you need to configure the pins, but what do RA0-4 have to do with RB12-15? Also, I tried playing around with the PORTB = LATB+1; line of code. I changed the '1' to a '2' and I thought that the counter would count up by '2' but instead it just sped up, still counting in binary by '1'. I don't really know what the difference between PORTB and LATB are.

    So I guess my main questions are:

    1) What do RA0-4 have to do with RB12-15?
    2) What are PORTB and LATB doing?
    3) What line of code actually causes the counter to... well... count?
    4) Is there a way of just accessing 1 pin at a time?

    I'm a major PIC noob and I realize there are a billion threads regarding PIC's but I am hoping this isn't too big of a mystery to solve.

    Here is the USB PIC board that I'm using:

    [​IMG]

    Cheers!
    J
     
    Last edited: Jun 10, 2011
  2. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    Nothing,PORTA is been used for some sort of input like switch or any signal, and also the pins of PORTA are internally pulled up i.e.. they are connected to Vdd.
    PORTB is an output register (memory),its each bit corresponds to a pin on your mcu.For example the lowest bit of PORTB i.e.. RB0 correspond to one of the pin in your mcu and if you make this bit high i.e. digitally 1 then the corresponding pin will also gets high. Now the LAT (latch register) is just another temporary register. When you want to write any value on any output register you don’t directly write them on output register you write them on LAT register and then transfer the value to the output register, for reading we also do the same, first transfer the value of output register to LAT register and then read it from the LAT in your software, why we do so? Because we may miss some information while reading it directly... in some case not always. Many of us read and write the output register directly, but Microchip doesn’t recommend this.

    Understanding it may be difficult and explaining this is also some how difficult. You should Google for some PIC tutorials, their are a lot which will explain you stuff like registers.

    Code ( (Unknown Language)):
    1. PORTB=LATB+1;
    Access single bit like this...
    Code ( (Unknown Language)):
    1. RB0 = 1; //it makes the lowest bit of PORTB high
    Google for PIC tutorial and start with some 8 bit PIC like 16F84A (for tutorial).Also download the current datasheet for your mcu you will get a lots of information from it.

    Good luck
     
    blah2222 likes this.
  3. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Thanks for the speedy reply! Just going back to the question about how it counts. Why did it speed up the counter period rather than count up by two when I changed the code to:

    Code ( (Unknown Language)):
    1.  
    2. PORTB = LATB+2;
    3.  
    ?
     
  4. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    bump for second question :)
     
  5. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    Because you don't have a LED on RB0. Your LEDs are on RB12-15, so the PIC has to count all the lower significant bits until it finally overflows to change RB12.

    To make it count by two you need to change the increment to 8192. But that also changes the delay in your circuit as the pins now change 8192 times faster then the original program so you would want to change the delay time too, unless you can see a flash of only .0001 seconds.
     
    blah2222 likes this.
  6. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Sorry to sound noobish, by why 8192? How did you come up with that increment?

    I mean what significance does 8192 have? Other than it being 2^{13}, I have no idea why haha

    J
     
  7. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    ErnieM already explained but I will also try....

    To really understand this you need to visualize the count pattern ,in your case the register is of 16 bits and it can count to 65535,which is very large pattern to visualize, so I will go with a very small example a register of 4 bits, we will mark the bits from highest (msb) to the lowest (lsb) i.e.. B3,B2,B1 and B0.And also assume that two LED are connected one at B3 and other at B2.Now when looking at the pattern ,when B3 and B2 will be 1 assume LEDs are on else off.

    First I will start with the case of single increment i.e. +1,also look how many step it takes before it overflows

    Code ( (Unknown Language)):
    1.  
    2. B3 B2 B1 B0  Step
    3.  0  0   0  0     0
    4.  0  0   0  1     1
    5.  0  0   1  0     2
    6.  0  0   1  1     3
    7.  0  1   0  0     4
    8.  0  1   0  1     5
    9.  0  1   1  0     6
    10.  0  1   1  1     7
    11.  1  0   0  0     8
    12.  1  0   0  1     9
    13.  1  0   1  0    10
    14.  1  0   1  1    11
    15.  1  1   0  0    12
    16.  1  1   0  1    13
    17.  1  1   1  0    14
    18.  1  1   1  1    15
    19.  
    Now if you look only at the column B3 and B2 where LEDs are connected ,the count partern is like this,it takes 4 counts from step 0 to 3 for B3 to become 0 and B2 to become 1,then again 4 counts to become B3 = 1 and B2 = 0 i.e.. number 2 and so on,you get a count to number 3 i.e.. in binary 1 1 (B3 = 1,B2 = 1)and the counter overflows.

    Now lets increment it by 2....
    Code ( (Unknown Language)):
    1.  
    2. B3 B2 B1 B0  Step
    3.  0  0   0  0     0
    4.  0  0   1  0     1
    5.  0  1   0  0     2
    6.  0  1   1  0     3
    7.  1  0   0  0     4
    8.  1  0   1  0     5
    9.  1  1   0  0     6
    10.  1  1   1  0     7
    11.  
    it takes only two step 0 and 1 to increment the count is same i.e.. 0,1,2,3 and overflows. So here your counting happens to be the same, just the step (i.e.. time) needed is less, so it counts faster.

    I think now its a bit clear what’s happening try to look at the count patterns and how many steps it takes to complete the pattern.

    if you really want to implement your logic i.e.. count up by '2' then connect your LEDs from RB0 - RB3 (consult your datasheet to see which pin corresponds to RB0 -RB3)

    Code ( (Unknown Language)):
    1.  
    2. // 4-bit binary counter on PortB LEDs
    3. // PIC24HJ32GP202 running at ~40 MIPS
    4. #include "pic24_all.h"
    5. static inline void configure_inputs_from_switches(){
    6. CONFIG_RA0_AS_DIG_INPUT();
    7. ENABLE_RA0_PULLUP();
    8. CONFIG_RA1_AS_DIG_INPUT();
    9. ENABLE_RA1_PULLUP();
    10. CONFIG_RA2_AS_DIG_INPUT();
    11. ENABLE_RA2_PULLUP();
    12. CONFIG_RA3_AS_DIG_INPUT();
    13. ENABLE_RA3_PULLUP();
    14. CONFIG_RA4_AS_DIG_INPUT();
    15. ENABLE_RA4_PULLUP();
    16. }
    17. static inline void configure_outputs_to_LEDs(){
    18. CONFIG_RB3_AS_DIG_OUTPUT();
    19. CONFIG_RB2_AS_DIG_OUTPUT();
    20. CONFIG_RB1_AS_DIG_OUTPUT();
    21. CONFIG_RB0_AS_DIG_OUTPUT();
    22. }
    23. int main (void)
    24. {
    25.         int i = 0; //loop variable
    26.         configure_inputs_from_switches();
    27.         configure_outputs_to_LEDs();
    28. while (1) // Loop forever
    29. {
    30. if(LATB >= 15)
    31. {
    32.    LATB = 0;
    33.    PORTB = LATB;
    34. }
    35. for(i=0;i<5;i++)
    36. {
    37. DELAY_MS(100); //0.5 sec or 500 milli sec delay for counter
    38. }
    39. PORTB=LATB+2; // LATB is the current value on Port B
    40. }
    41.  
    42. }
    43.  
    One thing I don’t know which compiler you are using, so the function DELAY_MS() might not work, check it and tell us.

    Good Luck
     
    Last edited: Jun 10, 2011
    blah2222 likes this.
  8. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Ahhhh! Now that makes perfect sense, thank you for the detailed explanation!. I forgot that I was dealing with a 16-bit register and my LED's are on the 4 MSB's.

    The code you provided compiled but when I bootloaded the hex file none of the LEDs lit up, so I guess it has something to do with the library files.

    Thanks again everyone!
    J
     
  9. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    Have you wait for some time before counter to count 2...

    May be or not,as you are configuring your ports using lib functions it may cause.

    Replace your main function with this and tell us if the LEDs are on or off.
    Code ( (Unknown Language)):
    1.  
    2. int main (void)
    3. {
    4.         configure_inputs_from_switches();
    5.         configure_outputs_to_LEDs();
    6.         LATB = 0xFFFF;
    7.         PORTB = LATB;
    8.         while(1){}
    9. }
    10.  
    if it works,then their may be some problem with the delay function.

    Good Luck
     
    blah2222 likes this.
  10. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Yep, all the LEDs are ON. I guess it is the delay function.
     
  11. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    I guess another question comes to mind, with timing. The MPLAB build says this is running at 40MHz, is that the frequency that the while loop runs and the delay is just increasing the period of each count by 100us in this case?
     
  12. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Anyone have any idea?
     
  13. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    As already written above your code as a comment, if its really correct (I am not sure)
    So it means that your PIC is executing ,approx 40 million instruction per second (MIPS) i.e.. almost each instruction (not all) takes about 25 nano seconds to execute we call this 1 instruction cycle, some instructions like branch or loops takes two or more instruction cycles to execute. So the "while()" loop is not executing at 40MHz its less than that, as their is the delay() for 100 micro seconds. But the count period is not 100 micro sec because it is using the 4 highest MSBs which divides the frequency of the "while()" loop further which actually gives a count period of 0.5 sec or 500 milli sec.

    I am just curious why the delay function didn’t worked so again I am providing you a new code try it. This time I am using delay of micro sec rather milli sec (counter period is still same)

    Code ( (Unknown Language)):
    1.  
    2. int main (void)
    3. {
    4.  int i = 0; //loop variable
    5.  configure_inputs_from_switches();
    6.  configure_outputs_to_LEDs();
    7.  
    8. while (1) // Loop forever
    9. {
    10.    if(LATB >= 0x000F)
    11.     {
    12.      LATB = 0x0000;
    13.      PORTB = LATB;
    14.     }
    15.  
    16.     for(i=0;i<5000;i++)
    17.     {
    18.      DELAY_US(100); //0.5 sec or 500 milli sec delay for counter
    19.     }
    20.  
    21.     PORTB = LATB + 0x0002; // LATB is the current value on Port B
    22. }
    23.  
    24. }
    25.  
    Good Luck
     
    blah2222 likes this.
  14. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Hey I loaded it on the PIC again. Compiled/built with no errors, but nothing lit up on the PIC. Not too sure what that is about...

    Okay, so I have decided to try out assembly operations and I am following a good tutorial. The only thing is that this was made for a different PIC and though there is some similarity in the registers/ports, some of the command addresses seem hard to find.

    For instance, there is a memory schematic on the Tutorial 2 page that shows the memory split into two types, Bank 1 and 2. To access either of the Banks, you have to enable the STATUS registers. I have searched through my PIC's datasheet and am having a hard time finding these registers. TRISA/B and PORTA/B are easy enough to address but these Bank STATUS' are hiding from me. You have also mentioned this LATA/B stuff, is that just a temporary working register similar to the W register in the Tutorial?

    I essentially just want to blink RB15 on and off using this code framework, but I am missing the STATUS address:

    Code ( (Unknown Language)):
    1.  
    2. STATUS equ ??? ; don't know address... need this!
    3. TRISB equ 02C8h ; constants
    4. PORTB equ 02CAh ; constants
    5.  
    6. bsf STATUS,??? ; go to Bank 1
    7. movlw 0000h ; move 0 to w
    8. movwf TRISB ; move w to TRISB
    9. bcf STATUS,??? ; go back to Bank 0
    10.  
    11. Start movlw 8000h ; move 8*(16^3) to w
    12.        movwf PORTB ; turn on RB15
    13.        movlw 0000h ; move 0 to w
    14.        movwf PORTB ; reset PORTB
    15.        goto Start ; repeat
    16.  
     
  15. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    You have a 16 bit PIC,which have many different features than many 8 bit PIC.The addressing mode is different you don’t have to set the status register to select banks to config the port's pin and its value. Here is an example from your datasheet look at page 96,



    Your code will not blink the LED.

    Because, you turn on the LED on RB15 then you turn it off, you didn’t gave any delay between that, so the on and off action will happen very fast ,you will not able to visualize that. You need some kind of delay...


    No,W registers are different than LAT registers. In old days and also still today in many microcontrollers and microprocessors the temporary register used by the ALU is called accumulator register which is used to store result for arithmetic and logic stuff and also move content to memory i.e.. a temporary register used for ALU's operation.
    Microchip named their accumulator register as working register. You have a 16 bit PIC which have 16 working registers W0,W1,W2.........W15,In many 8 bit PIC you will get only one i.e... W.

    LAT registers are different, they belongs to some PORT register(like for PORTB their is LATB), they can only be used for writing and reading from a PORT. They shouldn’t be used for any other purpose.

    In page 95 of your datasheet you will find

    Why the delay is not working I dont have any idea,but later I will try to simulate the delay stuff and will post the result.

    Good Luck​
     
    blah2222 likes this.
  16. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Thanks again! Very well explained, I can't thank you enough! Might the delay be too short, and it doesn't give the LED enough time to light up?

    J
     
  17. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    <PARTY CRASHER>

    Sorry to say that the line:
    Code ( (Unknown Language)):
    1. // PIC24HJ32GP202 running at ~40 MIPS
    does absolutely nothing to set the speed the core is running at. Further more, MPLAB doesn't have a check that the speed in that box is actually the speed the processor is running at.

    Now there may well be code inside that "pic24_all.h" include file that sets the configuration bits so that this thing does indeed run at 40MHz, but without loading the project here I can't see that. (And I have yet to use a PIC24, I jumped from the PIC18's right to the PIC32's.)

    I peeked a bit at the libs you downloaded but they are unreadable in notepad and my MPLAB is busy right now.

    Inside MPLAB, if you hit "Configure | Configuration Bits..." and see a mess of bits that should get set in code. These can be very complex to understand and one good reason to stick to C and these header files.

    </PARTY CRASHER>
     
  18. blah2222

    Thread Starter Well-Known Member

    May 3, 2010
    554
    33
    Ah, so there is no really way to quantify the frequency accurately?

    Also, I came across this code segment for creating a delay in assembly, I am just curious what the instruction subroutine waiting is doing specifically line by line.

    Code ( (Unknown Language)):
    1.  
    2. 1 - a_delay:
    3. 2 -             mov #0x0400, W1
    4. 3 - waiting:       
    5. 4 -                dec W1, W1
    6. 5 -             bra NZ, waiting
    7. 6 -             return
    8.  
    Here is my guess:

    1 - name of delay subroutine
    2 - move 1024 to w1
    3 - name of waiting subroutine
    4 - decrement value of w1 by 1, and store in w1
    5 - if w1 is nonzero, go back to waiting
    6 - else (if zero), return to calling subroutine, exit a_delay

    I just don't really get what 'bra' is doing and how that is connected to w1's value if it doesn't have w1 in that line.

    Thanks!
    J
     
  19. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    No there is,it depends on your system clock i.e.. the type of oscillator you are using and the configuration for the oscillator.See at page no 84 in your datasheet...

    bra is an instruction for branch operation,their are many format of branch instruction check the datasheet for instruction set.In your case its related to Z flag,the instruction (bra NZ, waiting) says that if Z flag is zero than branch i.e.. goto "waiting" else execute the next instruction.

    Now how Z flag is set ?
    Simple when you do a "dec" (dec W1, W1) operation and if the result is not zero the Z flag will be cleared i.e.. 0.

    Good Luck
     
  20. debjit625

    Well-Known Member

    Apr 17, 2010
    790
    186
    As I said when I will get time I will try to simulate the code so I did and got the problem I think so i.e.. why my given code was not running properly.

    In PIC24HJ32GP202 you have many different peripheral which share the out ports pins, when a peripheral is enabled the associated out ports pin is disabled. In your case my last code (in post #7) is a 4 bit counter with the LED connected from RB0 - RB3,in that code we configure PORTB as digitally output port but we forgot that RB0-RB3 are associated with ADC peripheral and we need to disable the ADC peripheral.

    Actually I didn’t forgot about that, it’s that you were using some helper function to configure your ports, I thought those configuration functions would configure the ports properly. Any way here is how to disable ADC peripheral pin configuration. You need to configure "AD1PCFGL" register. See page 173 of your datasheet.

    You can disable the AN2-AN5 which are associated with RB0-RB3 ,just add this inside the configuration function or at the place your configuration function are called in the main function.
    Code ( (Unknown Language)):
    1.  
    Code ( (Unknown Language)):
    1.  
    Code ( (Unknown Language)):
    1.  
    2. [COLOR=black][FONT=Verdana]AD1PCFGL = 0x003C;[/FONT][/COLOR]
    3. [COLOR=black][FONT=Verdana][/FONT][/COLOR]


    Or disable all the ADC channels and set the PORT as digitally output port.
    Code ( (Unknown Language)):
    1. AD1PCFGL = 0xFFFF;


    Good Luck
     
Loading...