Pic18f45k20 Timer0 RTC

Discussion in 'General Electronics Chat' started by alexm1992, Mar 15, 2014.

  1. alexm1992

    Thread Starter New Member

    Dec 19, 2013
    6
    0
    I am making progress using an external 32Khz crystal to count number of seconds. It appears to work but the timing is well off.

    Please see code:

    Code ( (Unknown Language)):
    1.  
    2.  
    3. /** C O N F I G U R A T I O N   B I T S ******************************/
    4.  
    5. #pragma config FOSC = LP, FCMEN = OFF, IESO = OFF                      
    6. #pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30
    7. #pragma config WDTEN = OFF, WDTPS = 32768
    8. #pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC      
    9. #pragma config STVREN = ON, LVP = OFF, XINST = OFF    
    10. #pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF  
    11. #pragma config CPB = OFF, CPD = OFF    
    12. #pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF              
    13. #pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF                          
    14. #pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF          
    15. #pragma config EBTRB = OFF  
    16.  
    17.  
    18. /** I N C L U D E S **************************************************/
    19. #include "p18f45k20.h"
    20. #include "delay.h"
    21. #include "delays.h"
    22. #include "switch header.h"
    23.  
    24. /** D E C L A R A T I O N S ******************************************/
    25.  
    26.  
    27.  
    28.  
    29.  
    30.  
    31. void main (void)
    32. {
    33.  
    34. int Day =0; // number of days
    35. int Counter =0; // counter
    36. int Sec = 0; // seconds passed
    37.  
    38.  
    39. PORTA = 0x03;            //Preset RA1,RA0 to 1    
    40. TRISA = 0x00;            
    41.    
    42.      
    43.  
    44. INTCON2bits.RBPU = 0;       // enable PORTB internal pullups
    45. WPUBbits.WPUB0 = 1;         // enable pull up on RB0
    46. ANSELH = 0x00;              // AN8-12 are digital inputs (AN12 on RB0)
    47. TRISBbits.TRISB0 = 1;       // PORTB bit 0 (connected to switch) is input (1)
    48.  
    49.     // Init Timer
    50. INTCONbits.TMR0IF = 0;          // clear roll-over interrupt flag
    51. T0CONbits.T08BIT = 0;           // 16bit operation - reduces the need to use prescale 16  
    52. T0CONbits.PSA = 1;           // WDT enabled prescale 1:1
    53. TMR0H = 0xE0;                      // clear timer - always write upper byte first
    54. TMR0L = 0xBF;
    55. T0CONbits.TMR0ON = 1;           // start timer
    56.  
    57. /*Fosc = 32KHz
    58. Fcycle = Fosc/4 = 32KHz/4 = 8KHz
    59. Tcycle = 1/Fcycle = 125us
    60. Cycle count (no prescaler) for one second = 1s/125us = 8000
    61. 16bit overflow value = 0xFFFF (65535 in dec)
    62.  
    63. Calculate TMR0 (H&L) values:
    64.  
    65. 65535-8000 = 57535 (0xE0BF)
    66. */
    67.  
    68.  
    69. while (1)
    70. {
    71.  
    72.  
    73. if(INTCONbits.TMR0IF)       // when overflow occurs increment sec integer
    74. {
    75. Sec ++;
    76.  
    77. }
    78.  
    79. if (Sec==10) // 10 seconds represent one day for now
    80. {
    81. Day ++; // in debug mode I am running cursor here it takes ages to return a value of one for days?
    82. Sec = 0;
    83. }
    84.  
    85.  
    Have I calculated something wrong? As I am using a prescale of 1:1 according to the data sheet the WDT must be enabled, should this be set up in the config files first? Thanks

    in fact when setting the prescaler to WDT to get a prescale of 1:1 the value of days is never incremented.
     
    Last edited: Mar 15, 2014
  2. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988

    Don't you think it would help to mention the time you expect out of the timer for someone to be able to tell you?
     
  3. alexm1992

    Thread Starter New Member

    Dec 19, 2013
    6
    0
    Good point, I forgot that. However by the fact the overflow increments an integer titled sec I think it is fairly self explanatory that I want it to overflow every second.
     
  4. GopherT

    AAC Fanatic!

    Nov 23, 2012
    5,991
    3,736
    I think you need to use the 32kHz oscillator with Timer1, not Timer0
     
  5. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,022
    Several problems here.

    Basics:
    First, are you really running the PIC itself at 32KHz? That's a tough way to get a seconds counter. The PIC is running veeerryyy slow.

    Timer 0 is a poor choice for period timing since it has to be reloaded each time it overflows. Reloading timer 0 clears the prescaler adding a few (unknown) Tcycs to the timing. Timer 1 with a CCP or Timer 2/PR2 is better.

    Specifics:
    Your clock source for TMR 1 is TOCKI (the input pin). Your code suggests that the source should be internal - TOCON is incompletely initialized, the clock source defaults to EXTERNAL. The timer is not running.

    TMR0IF is set when the timer rolls over from FFFF to 0000. You must clear it manually each time. You also must reload TMR0 with the count up value each time. Since the timer runs while you are loading you'll have to take that into account. Add the load value to the timer to account for any accumulated time between detecting the overflow and the load.

    Consider using TMR1/CCP or TMR2/PR2 for an interval timer. Your life will be easier.

    Finally, the code posted is missing braces at the end. Its helpful to post compilable code AND the compiler you are using. I used XC8 with minor mods to check it out.

    That's the usual way to do it. The arithmetic suggests that the PIC itself is running at 32KHz. But yeah, using the built in 32KHz/Timer 1 setup is a good way as well, particularly if you want to sleep the PIC for power savings but keep the timing going. Good call.

    EDIT: The WDT (watchdog timer) is OFF by the pragmas. Unlike some PICs, this one does not share TMR0 prescaler with the WDT.

    Have fun.
     
    Last edited: Mar 15, 2014
    alexm1992 likes this.
  6. alexm1992

    Thread Starter New Member

    Dec 19, 2013
    6
    0
    Thanks! I think I am going to give this another go with Timer1, it sounds a much better option. Does anybody have any sample code for using this?
     
  7. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,022
    Using which implementation?

    For the suggested CCP / TMR1 period timer see those sections in the databook particularly CCPxCON:
    1011 = Compare mode, trigger special event (ECCP resets TMR1 or TMR3, sets CC1IF bit).
    The timer will count off 0-Ncounts then reset and raise TMR1IF.

    For GopherT's 32KHz RTC approach see T1CON:
    bit 3 T1OSCEN: Timer1 Oscillator Enable bit
    1 = Timer1 oscillator is enabled
    .
    That will enable timer 1's oscillator using your 32KHz XTAL BUT! now you'll have to configure another oscillator to run the PIC itself.

    Either way, I would use a real interrupt service routine to increment the various time of day registers so you don't have to poll TMR1IF all the time.

    Sample code depends on which one you want to use.
     
  8. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988
    So you expect everyone to scan through every line of your code to pick that out? And then assume after that? It makes it a lot easier when you provide as much information as possible even when it might seem obvious to you.

    As others have said Timer 1 will be much easier. You can run it off of your external osc, that way you can run the mcu at any speed that you want.

    But does this chip have an RTC? Or is it a roll your own? If it has an RTC then I do not recall having to mess with timers. If it is a roll your own then you are headed in the right direction except for the chosen timer.
     
  9. GopherT

    AAC Fanatic!

    Nov 23, 2012
    5,991
    3,736
    Roll your own is the answer. Or, in the case of this OP, he's just stopping by and hoping he can have a toke from the timers that we rolled and passed around long ago.
     
  10. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988

    Good one :D
     
  11. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    You don't need a 32kHz xtal, or to be limited to any particular timer.

    There's a ton of code on this page;
    http://www.romanblack.com/one_sec.htm

    that shows you how to make ANY period (like one second) from any timer, and any xtal speed.

    The entire code to generate a 1 second period can be as simple as this;
    Code ( (Unknown Language)):
    1. // C code for a 1 second period with a 1MHz timer (4MHz xtal);
    2. // uses 1 variable; unsigned long bres
    3. // gets here every TMR0 int (every 256 ticks)
    4.  
    5. bres += 256;          // add 256 ticks to bresenham total
    6.  
    7. if(bres >= 1000000)   // if reached 1 second!
    8. {
    9.   bres -= 1000000;    // subtract 1 second, retain error
    10.   do_1sec_event();    // update clock, etc
    11. }
    (that code can be put in a free running 8bit TMR0 interrupt, and will make seconds automatically).
    :)
     
Loading...