RTC via TMR0 + HSERIN and 16F916


Closed Thread
Results 1 to 6 of 6
  1. #1
    Join Date
    Jan 2007
    Posts
    39

    Default RTC via TMR0 + HSERIN and 16F916

    Hello,
    I am designing the application which should wait for the serial data and based on this do something. Also I should have in the same chip the clock and each minute perform some tasks. So I implemented the clock using tmr0 interrupt and I have a loop, which is waiting for the serial commands. It is working quite well, but I have problem, that my clock are not ticking well it is loosing each hour approx. 2 minutes. But I don't know why. Here is my code, I am using 16F916 with 4 Mhz external crystal resonator.

    I have tmr0 prescaller in OPTION_REG = $d7 so I think, that tmr0 overflow happens 15 times per second. But seems, that it is not like this. Any suggestion?

    DEFINE OSC 4
    'hserin definition
    DEFINE HSER_RCSTA 90h
    DEFINE HSER_TXSTA 24h
    DEFINE HSER_SPBRG 12 'DEFINE HSER_BAUD 19200 on 4 Mhz
    DEFINE HSER_CLROERR 1
    'variables for timer
    day VAR BYTE ' Define day in the week
    hour var byte ' Define hour variable
    minute var byte ' Define minute variable
    second var byte ' Define second variable
    ticks var word ' Define pieces of seconds variable

    'put port A to input output
    ANSEL = 0
    CMCON0= 255
    ' interrupt for timer
    OPTION_REG = $d7
    INTCON = $a0 'enable TMR0 interrupts and global interrupt
    PIE1 = 0
    On Interrupt Goto intManagement
    clear

    enable
    while 1
    if (manageIntSecond == 1) then
    manageIntSecond = 0
    second = second + 1
    If second > 59 Then
    second = 0
    gosub manageIntMinute
    ENDIF
    endif
    if (PIR1.5==1) then
    HSERIN 10, main, [wait ("GET /"), COMMAND]
    'do something here
    HSEROUT ["Here I am..."]
    main:
    endif
    wend
    end

    disable
    intManagement:
    if (INTCON.2 == 1) then
    ticks = ticks + 1 ' Count pieces of seconds
    If ticks >= 15 Then
    if (ACTIVITY_LED == 1) then
    low ACTIVITY_LED
    else
    high ACTIVITY_LED
    endif
    ticks = 0 'One second elasped - update time
    manageIntSecond = 1
    endif
    INTCON.2 = 0
    endif
    INTCON.7 = 1
    resume

    enable
    manageIntMinute:
    minute = minute + 1 ' manage time update
    If minute > 59 Then
    minute = 0
    hour = hour + 1
    If hour > 23 Then
    hour = 0
    day = day + 1
    if day > 6 THEN day = 0
    Endif
    Endif
    return

  2. #2
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    Timer 0 doesn't overflow 15 times per second...
    Timer 0 overflows 15.2587890625 times per second.
    15.2587890625 * 4 = 61.03515625
    61.03515625 - 60 = 1.03515625 minutes in error.
    That accounts for 1 minutes of error.
    I think it would be fairly reasonable to say that another 1% or so could possibly be accounted for with the resonator, and maybe another fraction could be accounted for by using a stopwatch and watching an LED.

    Do a search on the Olympic Timer here.
    Either that or you could keep track of the extra .2587890625 ticks per second in different variables and add them into the 'ticks' variable as appropriate...
    Code:
    subtick var word
    .......
    ......
    disable
    intManagement:
    if (INTCON.2 == 1) then
    subtick=subtick + 2587
    if subtick => 10000 then
    subtick=subtick-10000
    ticks=ticks+1
    endif
    ticks = ticks + 1 ' Count pieces of seconds
    ..............
    ticks = ticks - 15 (ticks = 0) 'One second elasped - update time <-just in case you miss one somewhere, don't zero it, just subtract 15
    ........
    .......
    That just might take care of .2587 of the .258790625 of the error.

  3. #3
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    AND you have to add the ON INTERRUPT latency

    Darrel's Elapsed timer? Why not? Or at very least DT Interrupts!
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  4. #4
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by mister_e View Post
    AND you have to add the ON INTERRUPT latency
    But in this case, latency shouldn't really matter, 'cause the interrupt stubs isn't going to take anywhere near the total period of the interrupt (well, shouldn't anyways), T0 isn't being stopped by anything...

    And yes, DT's INTs and Elapsed Timer...always a good plan...

  5. #5
    Join Date
    Jan 2007
    Posts
    39


    Did you find this post helpful? Yes | No

    Default OPTION_REG = $d5 and ticks => 61

    Hello Skimask,
    thanks a lot for your help, I see.
    I am thinking that the easyest way to solve my problem is to use

    OPTION_REG = $d5

    disable
    intManagement:
    if (INTCON.2 == 1) then
    ticks = ticks + 1 ' Count pieces of seconds
    If ticks >= 61 Then
    if (ACTIVITY_LED == 1) then
    low ACTIVITY_LED
    else
    high ACTIVITY_LED
    endif
    ticks = 0 'One second elasped - update time
    manageIntSecond = 1
    endif
    INTCON.2 = 0
    endif
    INTCON.7 = 1
    resume

  6. #6
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    All other things being equal, that would give you roughly 49-50 seconds of slow error per day. Add one second every half hour, and you'll practically be dead on.

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts