Use of timer and overflow flag (registers clearing themselves!)

Discussion in 'Embedded Systems and Microcontrollers' started by k1mzz, Aug 6, 2016.

  1. k1mzz

    Thread Starter New Member

    Jul 31, 2016
    7
    0
    Hi,

    I am working Microchip DV164132 evaluation kit (http://www.microchip.com/DevelopmentTools/ProductDetails.aspx?PartNO=dv164132). This is based on the PIC16LF1937 microcontroller.

    I am trying to perform a reaction time test - when an LED lights, the timer starts. When the button is pressed, the TMR0 overflow flag is checked; if the timer hasn't overflowed, you have been successful and a series of LEDs should light up indicating this.

    My code is as follows (unsure as to how to define language - it's C!):

    Code (Text):
    1.  
    2. #include <xc.h>
    3.  
    4. // CONFIG1
    5. #pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    6. #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    7. #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    8. #pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
    9. #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    10. #pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
    11. #pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
    12. #pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
    13. #pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
    14. #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
    15.  
    16. // CONFIG2
    17. #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    18. #pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
    19. #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    20. #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    21. #pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
    22.  
    23. //definition of internal oscillator frequency for use with delay function
    24. #define _XTAL_FREQ 500000
    25.  
    26. //definition of friendly names for pins
    27. #define STATUS1 PORTDbits.RD1   //LED D1
    28. #define STATUS2 PORTEbits.RE2   //LED D2
    29. #define STATUS3 PORTEbits.RE1   //LED D3
    30. #define START   PORTEbits.RE0   //LED D4
    31. #define BUTTON  PORTDbits.RD2   //BUTTON
    32.  
    33. // #pragma config statements should precede project file includes.
    34. // Use project enums instead of #define for ON and OFF.
    35.  
    36. void main(void) {
    37.     //Configure oscillator
    38.     OSCCONbits.SCS1 = 1;
    39.     OSCCONbits.IRCF = 0b0111;
    40.  
    41.     //Configure timer
    42.     OPTION_REGbits.TMR0CS = 0; //Timer mode to instruction clock
    43.     OPTION_REGbits.PSA = 0; //Enable timer prescaler
    44.     OPTION_REGbits.PS = 111; //Timer prescaler to 1:256
    45.  
    46.     //Set direction of RD2 to input
    47.     TRISDbits.TRISD2 = 1;
    48.     //Make RD2 a digital input
    49.     ANSELDbits.ANSD2 = 0;
    50.     //Set direction of RD1 to output
    51.     TRISDbits.TRISD1 = 0;
    52.     //Set direction of PORTE (all output)
    53.     TRISE = 0b00000000;
    54.  
    55.     for(;;)
    56.     {
    57.             //Zero outputs
    58.             STATUS1 = 0;
    59.             STATUS2 = 0;
    60.             STATUS3 = 0;
    61.             START = 0;
    62.  
    63.             //Delay before start
    64.             __delay_ms(2000);
    65.          
    66.             if(BUTTON == 1)     //if button is NOT pressed
    67.             {
    68.                 START = 1;      //indicate ready to start
    69.                 TMR0 = 0;       //reset timer0 register
    70.                 INTCONbits.TMR0IF = 0;  //reset timer0 overflow flag
    71.                 while(BUTTON == 1); //wait until  button low (button press)
    72.                 if(INTCONbits.TMR0IF == 0)
    73.                 {//indicate success if timer didn't overflow (within reaction time)
    74.                     STATUS1 = 1;
    75.                     STATUS2 = 1;
    76.                     STATUS3 = 1;
    77.                 }
    78.                 START = 0;
    79.             }
    80.             //1sec delay so success can be observed
    81.             __delay_ms(1000);
    82.             //wait for button release
    83.             while(BUTTON == 0);
    84.     }
    85.     return;
    86. }
    87.  
    This works, however, the success output is only observed on one LED (STATUS1 (PORTDbits.PORTD1 / LED D1)). The other two (friendly names STATUS2 and STATUS3 briefly flash - not enough to be observed properly!).

    It seems to me that PORTE, bits 1 and 2 are clearing themselves! Not sure why this is happening - I have set the direction of the ports up correctly and am sure the timer routine is configured correctly as PORTD, bit 1 is functioning correctly.

    I am able to light all of the LEDs at once so I don't think it's a power supply issue.

    Has anyone experienced anything similar? Thanks in advance.
     
  2. k1mzz

    Thread Starter New Member

    Jul 31, 2016
    7
    0
    I found a solution! Reading some of the official Microchip forums, a rule of thumb is:

    For writing outputs, use LATx; for reading inputs, use PORTx (and if you need to read what you set an output to, use LATx).

    Taking this into account, I modified the definitions for START1 -> 3 as follows:

    Code (Text):
    1.  
    2. //definition of friendly names for pins
    3. #define STATUS1 LATDbits.LATD1   //LED D1
    4. #define STATUS2 LATEbits.LATE2   //LED D2
    5. #define STATUS3 LATEbits.LATE1   //LED D3
    6. #define START   LATEbits.LATE0   //LED D4
    7. #define BUTTON  PORTDbits.RD2   //BUTTON
    8.  
    This provided the required output. Hope this helps somebody!
     
  3. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,889
    375
    I think this is because you have not set ANSELE.
    As you have discovered writing to LATE will solve the problem.
    As a rule always set the ANSEL registers appropriately for your application, and use LAT registers for setting outputs.
    The problem you found is explained in this part of the data sheet:
    "The state of the ANSELE bits has no effect on digital output functions. A pin with TRIS clear and ANSEL set will still operate as a digital output, but the Input mode will be analog. This can cause unexpected behavior when executing read-modify-write instructions on the affected port."
    When you set one pin of PORTE, the PIC actually reads the port (reads '0' for analog inputs), sets the bit, and writes the result.
     
    k1mzz likes this.
  4. k1mzz

    Thread Starter New Member

    Jul 31, 2016
    7
    0
    Thanks for the explanation @AlbertHall - I have just read this part of the data sheet and experimented with the old code and addition of the following:

    Code (Text):
    1. ANSELEbits.ANSELE = 0b0000;
    This also provides the required output. Thanks again!
     
  5. dannyf

    Well-Known Member

    Sep 13, 2015
    1,771
    358
    You should always read the datasheet thoroughly before getting to the coding part. Or it's massively frustrating, :)

    In general, it is a good idea to reset the pins to their gpio states. For the PIC, it typically means turning off the analog (adc+comparator) features.

    two suggestions to your code:

    1) if you apply an offset to the counter (TMR0 in this case), you can vary the time lag your code can detect. For example:

    Code (Text):
    1.  
    2.   TMR0 = -TMR_PR; //overflow after TMR_PR * prescaler cycles
    3.  
    2) the code's logic could improve a little. I would try something like this:

    Code (Text):
    1.  
    2.   reset the timer / flag / status bits;
    3.   if (button is pressed) {
    4.     while (button remains pressed) continue;
    5.     if (timer flag is set) {
    6.       light up the leds;
    7.       delay a short while;
    8.     }
    9.   }
    10.  
     
Loading...