Clock using Instant Interrupts


+ Reply to Thread
Results 1 to 4 of 4
  1. #1
    Join Date
    Feb 2009
    Posts
    6

    Default Clock using Instant Interrupts

    I am new to PIC programming and had a question regarding using Interrupts. I had tried using the "Standard" way, but I stumbled upon Darrel's instant interrupts and they seemed much easier and more reliable, so I gave them a try. My goal is to make a programmable clock using a PIC16F627A using a Sony remote and TSOP receiver. I have made simple IR comms work and display, along with a clock, but my issue is that I was having trouble interrupting the clock function when I press my program key on the remote. It just wanted to keep timing and ignore my command, so I gave instant interrupts a try.

    My goal in the end is to have my main routine looking for IR pulses, and the interrupt generating the time, but for now I just wanted to make sure I am using the interrupt right, so I am trying to use the interrupt to generate 1/10th second counts. Here is my code.

    Code:
    '****************************************************************
    '*  Name    : UNTITLED.BAS                                      *
    '*  Author  : [select VIEW...EDITOR OPTIONS]                    *
    '*  Notice  : Copyright (c) 2009 [select VIEW...EDITOR OPTIONS] *
    '*          : All Rights Reserved                               *
    '*  Date    : 2/11/2009                                         *
    '*  Version : 1.0                                               *
    '*  Notes   :                                                   *
    '*          :                                                   *
    '****************************************************************
    ; Initialize your hardware first
    
    INCLUDE "DT_INTS-14.bas"     ; Base Interrupt System
    INCLUDE "ReEnterPBP.bas"     ; Include if using PBP interrupts
    Include "modedefs.bas"
    
    Define OSC
    DEFINE LOADER_USED 1     ' Using boot-loader for initial prototype
    DEFINE DEBUG_REG PORTB
    DEFINE DEBUG_BIT 0 
    DEFINE DEBUG_BAUD 19200
    define DEBUG_MODE 0 ' 1 = inverted, 0 = true 
    
    
    
    Second    var     byte
    Minute2   VAR     BYTE    ' Ones column for minutes
    Minute1   VAR     BYTE    ' Tens column for minutes
    Hour2     VAR     BYTE    ' Ones column for hours
    Hour1     VAR     BYTE    ' Tens column for hours
    AMPM      VAR     BIT     ' 1 when PM
    Counts    VAR     BYTE    ' Counts for timer
    
    Second = 0
    Minute1 = 0
    Minute2 = 0
    Hour1 = 1
    Hour2 = 2
    AMPM = 0
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   TMR1_INT,   ReloadTMR1,   ASM,  no    ; MUST be first
            INT_Handler   TMR1_INT,   _T1handler,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    
    ;--- Change these to match the desired interrupt frequency -------------------
    ;--- See http://DarrelTaylor.com/DT_INTS-14/TimerTemplate.html for more Info.
    @Freq       = 10                  ; Frequency of Interrupts in Hz
    @Prescaler  = 2                   ; Timers Prescaler setting
    T1CON = $10                       ; $30 = Prescaler 1:8, TMR1 OFF
    ; $00=1:1, $10=1:2, $20=1:4, $30=1:8 --  Must match @Prescaler value
    
    @ INT_ENABLE  TMR1_INT            ; enable Timer 1 interrupts
    GOSUB StartTimer                  ; Start the Timer
    
    Main:
     
    IF counts = 10 then  
    Second = Second + 1      'Calculate time and change values
    
    If Second = 60 then 
       Minute2 = Minute2 +1
       Second = 0
         IF Minute2 = 10 THEN
         Minute1 = Minute1 + 1
         Minute2 = 0
            IF Minute1 = 6 then
            Hour2 = Hour2 + 1
            Minute1 = 0
               IF Hour2 = 10 THEN
               Hour1 = 1 
               Hour2 = 0
               endif
            endif   
         endif
    endif
                  
    IF Hour1 = 1 AND HOUR2 = 3 THEN      'Roll clock over to 1 from 12
       Hour1 = 0
       Hour2 = 1
       IF AMPM = 0 THEN                  'Establish AM and PM times
          AMPM = 1
       endif 
         IF AMPM = 1 THEN
            AMPM = 0
         ENDIF
    endif
    
    If Hour1 = 0 then                    'If hour 1 is 0 then do not display it
       Hour1 = 20                        'SLED-C4 will not display anything if the
    Endif                                'value is above 10
           
    DEBUG "D", Hour1,Hour2,Minute1,Minute2 ' Display time
    DEBUG "P",12,"~"                       ' Display Colon
    
    Else
    
    GOTO Main
    ENDIF
     
    
    T1handler:
    
    Counts = Counts + 1  ;   Increase the 1/10th sec count
      
    @ INT_RETURN
    
    ;---[TMR1 reload - interrupt handler]-----------------------------------------
    ASM                               ; Calculate Timer Reload Constant
    ReloadInst  = 8                   ; # of Intructions used to reload timer
      if ((Prescaler == 1)||(Prescaler == 2)||(Prescaler == 4)||(Prescaler == 8))
    MaxCount    = 65536 + (ReloadInst / Prescaler)
    TimerReload = MaxCount - (OSC*1000000/4/Prescaler/Freq)
        if ((TimerReload < 0) || (TimerReload > (65535-ReloadInst)))
            error Invalid Timer Values - check "OSC", "Freq" and "Prescaler"
        endif
      else
          error Invalid Prescaler
      endif
    ENDASM
    
    @Timer1 = TMR1L                   ; map timer registers to a word variable
    Timer1       VAR WORD EXT
    TimerReload  CON EXT              ; Get the External Constant
    TMR1ON       VAR T1CON.0          ; Alias the Timers ON/OFF bit
    
    ;---Reload Timer1------
    ASM
    ReloadTMR1
        MOVE?CT  0, T1CON, TMR1ON     ;  1     stop timer
        MOVLW    LOW(TimerReload)     ;  1     Add TimerReload to the 
        ADDWF    TMR1L,F              ;  1     value in Timer1
        BTFSC    STATUS,C             ;  1/2
        INCF     TMR1H,F              ;  1
        MOVLW    HIGH(TimerReload)    ;  1
        ADDWF    TMR1H,F              ;  1
        MOVE?CT  1, T1CON, TMR1ON     ;  1     start timer
      INT_RETURN
    ENDASM
    
    ;---Start/Stop controls -----
    StartTimer:
        Timer1  = TimerReload         ; Load Timer
        TMR1ON = 1                    ; start timer
    RETURN
    
    StopTimer:
        TMR1ON = 0                    ; stop timer
    RETURN
    Basically the code sits at the default 12:00 and never moves. Judging from this, it would seem that it gets to the display time DEBUG statement, or I would have a display of 8888, but I'm not really sure what happens after that. I am assuming the PIC is fast enough to get through the clock routine when Counts = 10 before it is interrupted, but again, not sure where I am hanging up.

    Any suggestions from some of the PIC veterans out there?

    Another quick question. I don't think I saw how to disable instant interrupts from occuring when I get to a point that I dont want them?

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Hi PICpocket ... good name

    I think the biggest problem is the IF block ...
    Code:
    IF counts = 10 then
        ; counts time here
    ELSE
        GOTO MAIN
    ENDIF
    
    T1handler:
     ...
    When counts gets to 10, it adds to the time, then bypasses the GOTO Main and falls into the interrupt handler which has nowhere to return to.

    Also, counts wasn't initialized to 0, so it may have to go all the way to 255 then rollover to 0, before making it to ten. Then once it gets to 10, you'll need to set counts to 0, or it will count all the way up again.

    The timekeeping part would be better inside the interrupt handler. Depending on what else you add to the Main loop, it could lose time.

    Any Software timed commands like DEBUG will be disturbed by interrupts.
    To send data via RS232, you should use the USART with HSEROUT.
    Or, you can disable the interrupts when sending data, but it can mess up the time if your not careful.

    To disable the interrupt ...
    @ INT_DISABLE TMR1_INT
    To enable the int ...
    @ INT_ENABLE TMR1_INT

    Which brings us to the IR signal (code not included).
    Trying to read that using PAUSEs or similar methods won't work reliably because the timing will be disrupted by the interrupts. You can probably use another timer for the IR reception.

    hth,
    DT

  3. #3
    Join Date
    Jul 2003
    Posts
    2,405

    Default

    If you use Timer2 for your clock it leaves Timer1 free to be used with hardware capture. Then you can use capture to read your IR signal.

    Here's an example tested with the SLED-C4. It only needs to test for the TMR2IF flag to keep time, so no interrupts are used. And you have quite a few instruction cycles to do other things between clock updates.

    Code:
    @ DEVICE LVP_OFF,WDT_OFF,MCLR_OFF,XT_OSC
    
    DEFINE OSC 4
    DEFINE DEBUG_REG PORTB
    DEFINE DEBUG_BIT 0
    DEFINE DEBUG_BAUD 19200
    DEFINE DEBUG_MODE 0 ' SLED-C4 serial mode = true
        
    ' setup vars for clock
    Time VAR WORD      ' accumulates TMR2 to PR2 match counts
    Minutes VAR BYTE   ' minutes
    Hours VAR BYTE     ' hours
    Match VAR PIR1.1   ' TMR2 to PR2 match interrupt flag bit
    
    PORTB.0=1          ' make sure SLED-C4 data input pin idles high        
    TRISB = %00001000  ' RB3 = CCP1 capture input, rest outputs
    CMCON = 7          ' disable comparators
    INTCON = 0         ' not using interupts. Just monitoring int flag bits
    
    PAUSE 250          ' let SLED-C4 power-up
    
    Time = 0           ' clear TMR2 to PR2 match counter
    Hours = 10         ' set clock starting hour here
    Minutes = 03       ' set clock starting minutes here
    
    ' set SLED-C4 start time
    DEBUG "D", Hours DIG 1,Hours DIG 0,Minutes DIG 1,Minutes DIG 0
    
    ' TMR2 increments from 0 until it matches the PR2 register value
    ' and then resets to 0 (on the next increment cycle) so place a
    ' value in PR2 1 cycle short of what you want. Here we want 250 for
    ' 60mS, so we write 249 to PR2.
    PR2 = 249           ' 249 +1 extra cycle for reset = 250*16*15*1uS=60mS
    Match = 0           ' clear match flag
    
    ' setup & start TMR2
    T2CON = %01110110  ' 1:16 prescale, 1:15 postscale, TMR2 on
    
    Main:
       ' every 60mS the TMR2IF flag is set, and this routine is entered.
       ' Plenty of time to do other stuff.
       IF Match THEN          ' has TMR2 matched PR2? (should happen every 60mS)
          Match = 0           ' yes. clear TMR2 to PR2 match flag bit
          Time = Time + 1     ' increment 60mS count    
          IF Time = 1000 THEN ' has 60 seconds (1000*60mS) passed?
             Time = 0         ' yes. clear count
             Minutes = Minutes + 1 ' increment minute count
             IF Minutes = 60 THEN  ' have 60 minutes passed?
                Minutes = 0        ' yes. roll-over minutes from 59 to 00
                Hours = Hours + 1  ' update hour every 60 minutes
                IF Hours = 24 THEN Hours = 0 ' roll-over hours from 24 to 00
             ENDIF                 
             ' print new time only once every minute
             DEBUG "D", Hours DIG 1,Hours DIG 0,Minutes DIG 1,Minutes DIG 0 
          ENDIF    
       ENDIF
       
       GOTO Main
       
       END
    It's pretty decent at keeping time. Ran for 3 hours, and it was spot-on with my PC clock to the second.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  4. #4
    Join Date
    Feb 2009
    Posts
    6

    Default

    Thanks for the help both Darrel and Bruce!

    I kicked myself for not seeing that I wasn't resetting the Counts in my first posting However, things are working well now, and I can read my IR signal as I want by putting the clock routine as my interrupt and the IR PULSIN command as my main (as Darrel suggested). At this point is it just some coding to recognize alarms and different programmable options that I will throw in.

    I don't think I will have a problem with having enough time for tasks between interrupts since I am only doing the initial PULSIN command in my Main. If there was some kind of restriction in the interrupt routine I might have a problem them, but most of the heavy coding will be outside the main and the Interrupt routine. Though the code Bruce posted is very concise. I will try things out with both of them and see how things go.

    Ill post here if I have any more questions.

Similar Threads

  1. Instant Interrupts - Revisited
    By Darrel Taylor in forum Code Examples
    Replies: 790
    Last Post: - 9th January 2019, 16:38
  2. 18F2420, instant interrupts, and TMR0
    By dhickman in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 11th March 2009, 19:33
  3. DT instant interrupts with mister_e keypad
    By Tomexx in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 26th November 2008, 21:02
  4. DT's Instant Interrupts trouble
    By Tomexx in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 24th November 2008, 21:48
  5. Replies: 1
    Last Post: - 1st November 2006, 04:11

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