PIC 16F877A traffic system

Discussion in 'Embedded Systems and Microcontrollers' started by Aamil, Jan 2, 2015.

  1. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    Dear friends,

    I am trying to design a basic traffic system using 16F877A and LEDs.

    Code (Text):
    1.  
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4.  
    5. #define _XTAL_FREQ 2000000
    6. #include <xc.h>
    7.  
    8. // BEGIN CONFIG
    9. #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
    10. #pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)
    11. #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
    12. #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
    13. #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
    14. #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
    15. #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
    16. #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
    17. //END CONFIG
    18.  
    19. int main()
    20. {
    21.     PORTA = 0x00;
    22.     TRISA = 0x00; //RA0 as Output PIN
    23.  
    24.  
    25. while(1)
    26.   {
    27.         RA0 = 1;
    28.     __delay_ms(1000);
    29.        RA0 = 0;RA1 = 1;
    30.         __delay_ms(1000);
    31.     RA1 = 0;RA2 = 1;
    32.         __delay_ms(1000);
    33.     RA2 = 0;
    34.   }
    35.   return 0;
    36. }
    I can download the code to PIC16F877A using pickit3.
    But only first LED which is connected to RA0 blinks. None other LEDs are blinking. All LED s are connected along with a 100 Ohm series resistor


    Can anyone help?
     
  2. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    ANSEL must be configured to make PORTA digital.
     
  3. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    as I understood,
    The 16F877A does not contain the ANSEL or ANSELH registers or the C1ON bit.
     
  4. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    I've had enough problems with PIC processor outputs that I just force myself to be defensive and use "shadow ports" and live with the extra time, code space and memory use that it involves. The trouble is Microchip's worst idea ever, the read-modify-write operation. It means that changing a single bit of a port may unpredictably change other pins. Not saying that's the problem here, but I'd avoid having to worry. Every action on a port pin looks like this:
    Code (Text):
    1.  
    2.   unsigned char porta_shadow;
    3.  
    4.   bit_set(porta_shadow, 0);
    5.   porta = porta_shadow;
    6.  
     
  5. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    Sorry.. I could not understand this ..I read about the read-write-modify issue. But what is this shadow port idea? How can I use it to individual pins?
     
  6. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    Sorry if I wasn't totally clear. You create a variable that holds the "shadow" data. You can set or clear its bits as you need to, but you only write to the actual port by means of a full 8-bit transfer, and you never just set or clear a single pin. I thought my little code sample made this clear.

    Yes, Port A has fewer than 8 bits. That's OK, you can still write to it. The top bits simply won't have any effect.
     
    Aamil likes this.
  7. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Here's some general hints for using PICs:

    1) When an input may be either an analog or a digital input it will *always* default on power up to analog. The reason being is an analog input is more tolerant of wide voltage swings. Thus analog pins must be changed to digital pins.

    2) In the data sheet for each and every device the section on the IO ports will have a "SUMMARY OF REGISTERS ASSOCIATED WITH PORT(X)" It is well worth reading until every register is understood and any conflicts with whatever operation you intend to use. For the '877, note that ADCON1 will enable all 8 analog inputs.

    3) There is a simulator built into MPLAB. Learn to use it. Especially with faults involving the IO pins there is a general catch phrase I use: "if it doesn't sim(ulate) you can't win." If your part works funky use the simulator to see why.
     
    Last edited: Jan 2, 2015
    Aamil likes this.
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    Oops! That's what I get for not verifying the register names. Good catch.
    I'm with John P as well and always shadow ports on midrange.
     
    Aamil likes this.
  9. MagicMatt

    Member

    Sep 30, 2013
    117
    14
    You're using XC8 ... use the Code Configurator plugin and let it write all the setup for you. Much easier!
     
    Aamil likes this.
  10. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    I am not familiar with code configurator plugin..Just started using PIC and XC8...Thanks for your suggestioon :)
     
  11. ke5nnt

    Active Member

    Mar 1, 2009
    384
    15
    Shadowing is to create a variable that mimics the port register. You have PORTA, which is the actual 8-bit port register, then you create an unsigned char data type variable (i.e. "unsigned char PORTAimg") that is an 8-bit variable. You perform the bit operations on the shadow register, then copy the value of the shadow register to the port register. You can do this using bit masking, where if your red traffic light is bit 1 of PORTA, you would:
    Code (Text):
    1. #define REDmask 0b00000010
    If you bitwise OR this mask with the shadow register variable, it will change the value of bit 1 from 0 to 1.
    Mask = 00000010 OR ( | )
    Shadow = 00000000
    Result = 00000010

    Then copying the shadow register to the port register (an 8-bit wide operation) negates r-m-w problems. To turn on red LED, the following demonstrates the above ideals:
    Code (Text):
    1. #define REDmask 0b00000010    //mask red led on bit 1
    2. unsigned char PORTAimg;    //an 8-bit variable that images the PORTA register
    3. ...
    4. ...
    5. PORTAimg |= REDmask;    //perform bitwise OR operator and make PORTAimg equal to the result
    6. PORTA = PORTAimg;     //copy results to PORTA register, an 8-bit operation
    7. ...
    8. ...
    9.  
    Obviously other code would be required for the full program, but this demonstrates what is needed to shadow port registers. Others may have additional thoughts/alternative methods, but this is how I do it.

    Regards
     
    Aamil likes this.
  12. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    You are not resetting your watchdog timer. Either set WDTE to OFF, or reset the WDT before it expires.

    Edit: You also need to set the appropriate values in ADCON1 (see page 128 in the datasheet).
     
    Last edited: Jan 9, 2015
    Aamil likes this.
  13. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    i tried by disabling ADC, using ADCON1=7

    as in the below code
    Code (Text):
    1. int main()
    2. {
    3.   TRISA = 0; //RB0 as Output PIN
    4.   PORTA=0;
    5.   ADCON1=7;
    6.   while(1)
    7.   {
    8.   RA0 = 1;RA1=0;RA2=0;RA4=0;  // LED ON
    9.   __delay_ms(10000); // 1 Second Delay
    10.   RA0 = 0;RA1=1;RA2=0;RA4=0;  // LED ON
    11.   __delay_ms(10000); // 1 Second Delay
    12.   RA0 = 0;RA1=0;RA2=1;RA4=0;  // LED ON
    13.   __delay_ms(10000); // 1 Second Delay
    14.   RA0 = 0;RA1=0;RA2=0;RA4=1;  // LED ON
    15.   __delay_ms(10000); // 1 Second Delay
    16.   RA0 = 0;RA1=0;RA2=0;RA4=0;  // LED ON
    17.   }
    18.   return 0;
    19. }

    The LEDs connected to RA0,RA1 and RA2 turns on . RA4 LED is not turning on.
    After RA2 LED turns on , immediately RA0 LED glows.
     
  14. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    Let me learn that.. Thanks for giving hints :)
     
  15. ke5nnt

    Active Member

    Mar 1, 2009
    384
    15
    Looking at the device datasheet, it seems to me that ADCON1 must be set on bits 3 to 0 for digital I/O. In your code, ADCON1 = 7 is not any way I've ever seen something programmed. Try replacing that with:
    Code (Text):
    1.  
    2. ADCON1 = 0b00001111
    For the watchdog timer, your code from your original post shows the #pragma config WDTE = ON. Turning off the timer is as simple as changing "ON" to "OFF".

    Looks like I'm also noticing your delay macros. __delay_ms(10000) is a 10 second delay, not 1 second, and the compiler should be giving you errors on a value this large, if it lets you compile it at all. 1 second is 1,000mS, a value I know will be allowed by XC8.

    Here is your code with notes:
    Code (Text):
    1.  
    2. int main()                           main program function is "void main(void)" you are defining an integer here
    3. {
    4. TRISA = 0; //RB0 as Output PIN         Should really be defined in binary, not decimal
    5. PORTA=0;                                             Should really be defined in binary, not decimal
    6. ADCON1=7;                     see note in above post
    7. while(1)
    8. {
    9. RA0 = 1;RA1=0;RA2=0;RA4=0; // LED ON
    10. __delay_ms(10000); // 1 Second Delay                change delays to 1000ms for 1 second delay
    11. RA0 = 0;RA1=1;RA2=0;RA4=0; // LED ON
    12. __delay_ms(10000); // 1 Second Delay
    13. RA0 = 0;RA1=0;RA2=1;RA4=0; // LED ON
    14. __delay_ms(10000); // 1 Second Delay
    15. RA0 = 0;RA1=0;RA2=0;RA4=1; // LED ON
    16. __delay_ms(10000); // 1 Second Delay
    17. RA0 = 0;RA1=0;RA2=0;RA4=0; // LED ON
    18. }
    19. return 0;                                      This line of code should not be needed
    20. }
     
    Last edited: Jan 10, 2015
    Aamil likes this.
  16. Aamil

    Thread Starter New Member

    Jan 2, 2015
    23
    0
    Thanks ke5nnt..

    I used the following code and only RA1 LED blinks now. I think I am making some serious silly mistake..

    Code (Text):
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3.  
    4. #define _XTAL_FREQ 2000000
    5. #include <xc.h>
    6.  
    7. // BEGIN CONFIG
    8. #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
    9. #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
    10. #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
    11. #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
    12. #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
    13. #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
    14. #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
    15. #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
    16. //END CONFIG
    17.  
    18. void main(void)
    19. {
    20.   TRISA = 0b00000000; //RA0 as Output PIN
    21.   PORTA=  0b00000000;
    22.   ADCON1 = 0b00001111;
    23.   while(1)
    24.   {
    25.     RA0 = 1;RA1=0;RA2=0;RA3=0;  //RA0 LED ON
    26.     __delay_ms(1000); // 1 Second Delay
    27.     RA0 = 0;RA1=1;RA2=0;RA3=0;  //RA1  LED ON
    28.     __delay_ms(1000); // 1 Second Delay
    29.     RA0 = 0;RA1=0;RA2=1;RA3=0;  //RA2  LED ON
    30.     __delay_ms(1000); // 1 Second Delay
    31.     RA0 = 0;RA1=0;RA2=0;RA3=1;  //RA3  LED ON
    32.     __delay_ms(1000); // 1 Second Delay
    33.     RA0 = 0;RA1=0;RA2=0;RA3=0;  //All LEDs OFF
    34.  
    35.   }
    36. }
    Could you guide me to a simple traffic light LED code? I tried to learn multiple things and getting confused :(
     
  17. John P

    AAC Fanatic!

    Oct 14, 2008
    1,632
    224
    I'm still not seeing any use of a shadow register for the port. Or have you tried it and found that it didn't make any difference?

    If you find that impossible to do, try writing to PortA as a byte rather than one bit at a time. So instead of
    Code (Text):
    1.  
    2. RA0 = 1;RA1=0;RA2=0;RA3=0; //RA0 LED ON
    3. __delay_ms(1000); // 1 Second Delay
    4. RA0 = 0;RA1=1;RA2=0;RA3=0; //RA1 LED ON
    5. etc
    6.  
    you could say
    Code (Text):
    1.  
    2. PORTA = 0b00000001;
    3. __delay_ms(1000); // 1 Second Delay
    4. PORTA = 0b00000010;
    5. etc
    6.  
     
    Aamil likes this.
  18. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    I just pasted your code into MPLAB (with the additions noted above) . I saw exactly what you describe, after soon after RA2 turns on the watchdog timer expires. The watchdog will reset your PIC so the code starts all over so the observed sequence is RA0,RA1, RA2, RA0,RA1, RA2, and so on.

    The fix for this was noted above, either turn the watchdog timer off, or reset it after each of the long delays using the "CLRWDT();" command you will find in the XC8 User's Guide.

    Once you fix the watchdog you should see all 4 LEDs light.

    Note the last state for all off has no delay so you will never see that happen.

    Also note that "ADCON1=7;" is completely correct code. The default radix in C is base 10, so 7 is a binary 00000111. That is a bit different than the 00001111 posted.
     
    Aamil likes this.
  19. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    That makes sense, look at what
    ADCON1 = 0b00001111;
    does by looking, again, on page 128 in the datasheet. It commandeers the I/O function.
     
    Aamil likes this.
  20. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    that doesnt work with older PICs at all
     
    Aamil likes this.
Loading...