Real time clock + external interrupt in one PIC possible?


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,623


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    Hello,
    I've played around with the code a bit, got it up and running on my EasyPIC7 development board using a 18F45K22 device. It counts, it times, it calculates and it displays (during and after measurement).

    Name:  DSCF2326[1].jpg
Views: 3450
Size:  215.7 KB

    The code I post here are what's running on my device, if you plan to use another device you must:
    A) Replace the CONFIG with correct ones for your device
    B) Make sure the PIC runs at 8MHz using whatever oscillator (external x-tal is probably best for timing accuracy)
    C) Change the aliases to suit the hardware
    D) Change the hardware setup section (TRIS, ANSEL, OSCCON, T1CON etc)

    Code:
    '--- Device configuration - replace with config for selected target ------------
    #CONFIG
        CONFIG FOSC = HSMP	          ; HS oscillator (medium power 4-16 MHz)
        CONFIG  PLLCFG = OFF          ; Oscillator used directly
        CONFIG  PRICLKEN = OFF        ; Primary clock can be disabled by software
        CONFIG  FCMEN = OFF           ; Fail-Safe Clock Monitor disabled
        CONFIG  IESO = OFF            ; Oscillator Switchover mode disabled
        CONFIG  PWRTEN = OFF          ; Power up timer disabled
        CONFIG  BOREN = SBORDIS       ; Brown-out Reset enabled in hardware only (SBOREN is disabled)
        CONFIG  BORV = 190            ; VBOR set to 1.90 V nominal
        CONFIG  WDTEN = ON            ; WDT is always enabled. SWDTEN bit has no effect
        CONFIG  WDTPS = 32768         ; 1:32768
        CONFIG  CCP2MX = PORTC1       ; CCP2 input/output is multiplexed with RC1
        CONFIG  PBADEN = OFF          ; PORTB<5:0> pins are configured as digital I/O on Reset
        CONFIG  CCP3MX = PORTB5       ; P3A/CCP3 input/output is multiplexed with RB5
        CONFIG  HFOFST = ON           ; HFINTOSC output and ready status are not delayed by the oscillator stable status
        CONFIG  T3CMX = PORTC0        ; T3CKI is on RC0
        CONFIG  P2BMX = PORTD2        ; P2B is on RD2
        CONFIG  MCLRE = EXTMCLR       ; MCLR pin enabled, RE3 input pin disabled
        CONFIG  STVREN = ON           ; Stack full/underflow will cause Reset
        CONFIG  LVP = OFF             ; Single-Supply ICSP disabled
        CONFIG  XINST = OFF           ; Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
        CONFIG  DEBUG = OFF           ; Disabled
        CONFIG  CP0 = OFF             ; Block 0 (000800-001FFFh) not code-protected
        CONFIG  CP1 = OFF             ; Block 1 (002000-003FFFh) not code-protected
        CONFIG  CP2 = OFF             ; Block 2 (004000-005FFFh) not code-protected
        CONFIG  CP3 = OFF             ; Block 3 (006000-007FFFh) not code-protected
        CONFIG  CPB = OFF             ; Boot block (000000-0007FFh) not code-protected
        CONFIG  CPD = OFF             ; Data EEPROM not code-protected
        CONFIG  WRT0 = OFF            ; Block 0 (000800-001FFFh) not write-protected
        CONFIG  WRT1 = OFF            ; Block 1 (002000-003FFFh) not write-protected
        CONFIG  WRT2 = OFF            ; Block 2 (004000-005FFFh) not write-protected
        CONFIG  WRT3 = OFF            ; Block 3 (006000-007FFFh) not write-protected
        CONFIG  WRTC = OFF            ; Configuration registers (300000-3000FFh) not write-protected
        CONFIG  WRTB = OFF            ; Boot Block (000000-0007FFh) not write-protected
        CONFIG  WRTD = OFF            ; Data EEPROM not write-protected
        CONFIG  EBTR0 = OFF           ; Block 0 (000800-001FFFh) not protected from table reads executed in other blocks
        CONFIG  EBTR1 = OFF           ; Block 1 (002000-003FFFh) not protected from table reads executed in other blocks
        CONFIG  EBTR2 = OFF           ; Block 2 (004000-005FFFh) not protected from table reads executed in other blocks
        CONFIG  EBTR3 = OFF           ; Block 3 (006000-007FFFh) not protected from table reads executed in other blocks
        CONFIG  EBTRB = OFF           ; Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
    #ENDCONFIG
    
    DEFINE OSC 8                                ' We're running at 8MHz. The code is based on that fact.
    
    DEFINE LCD_DREG PORTB                       ' Set LCD Data port
    DEFINE LCD_DBIT 0                           ' Set starting Data bit (0 or 4) if 4-bit bus
    DEFINE LCD_RSREG PORTB                      ' Set LCD Register Select port
    DEFINE LCD_RSBIT 4                          ' Set LCD Register Select bit
    DEFINE LCD_EREG PORTB                       ' Set LCD Enable port
    DEFINE LCD_EBIT 5                           ' Set LCD Enable bit
    DEFINE LCD_BITS 4                           ' Set LCD bus size (4 or 8 bits)
    DEFINE LCD_LINES 2                          ' Set number of lines on LCD
    DEFINE LCD_COMMANDUS 1500                   ' Set command delay time in us
    DEFINE LCD_DATAUS 40                        ' Set data delay time in us
    
    
    '---------- Variables ------------
    Hours           VAR BYTE                    ' Elapsed time, hours
    Minutes         VAR BYTE                    ' Elapsed time, minutes
    Seconds         VAR WORD                    ' Elapsed time, seconds
    ms              VAR WORD                    ' Elapsed time, milliseconds
    State           VAR BYTE                    ' State machine variable, keeps track of what we're doing
    Distance        VAR WORD                    ' Distance traveled in metres, calculated based on pulsecount
    AverageSpeed    VAR WORD                    ' Final result of measurement, in units of 0.1km/h (123=12.3km/h)
    Temp            var WORD                    ' Used during calculation
    DebounceCount   VAR BYTE                    ' Used to debounce the start/stop button
    LCDSequence     VAR BYTE                    ' Used to update the display step-by-step
    TimeOverflow    VAR BIT                     ' Gets set if the seconds variable grows too big.
    UpdateDisplay   VAR BIT                     ' Flag that is set when it't time to update the LCD
    
    '----------------- Constants ----------------------
    Idle            CON 0
    Starting        CON 1
    Counting        CON 2
    Stopping        CON 3
    Done            CON 4
    Error           CON 5
    
    '------------------- Aliases - change to suit hardware -------------------------
    StartStopButton VAR PORTB.6                 ' Low when pressed
    ReadyIndicator  VAR LATA.0                  ' High when idle/ready
    RunIndicator    VAR LATA.1                  ' High when counting/timing
    ErrorIndicator  VAR LATA.2                  ' High on count or time overflow
    TMR1ON          VAR T1CON.0                 ' Run/stop bit for TMR1
    TMR2ON          VAR T2CON.2                 ' Run/stop bit for TMR2
    TMR1IF          VAR PIR1.0                  ' TMR1 interrupt flag
    TMR2IF          VAR PIR1.1                  ' TMR2 interrupt flag
    
    '--------------- Target setup - change to suit target device -------------------
    ANSELA = 0                                  ' All pins as digital
    ANSELB = 0
    ANSELC = 0
    ANSELD = 0
    ANSELE = 0
    
    TRISA  = %11111000                      ' Status LEDs on RC0-RC2
    LATA   = %00000000
    
    TRISB  = %01000000                      ' LCD on RB0-RB5, Start/Stop on RB6                     
    LATB   = %00000000                      ' All pins low
    
    
    'OSCCON = %01110010                      ' For 18F1320, Internal oscillator, 8MHz
    'T1CON  = %00000010                      ' For 18F1320, External clock on RB6, timer OFF for now.
    T1CON = %10000000                       ' For 18F45K22
    T2CON  = %00000010                      ' 1:16 prescaler, TMR2 off for now
    PR2    = 249                            ' T2 interrupt flag set every 250*16 tick
    
    PAUSE 500
    
    Start:
        State = Idle
        ReadyIndicator = 1
        RunIndicator = 0
        ErrorIndicator = 0
        LCDOUT $FE, 1,   "     Ready"
        LCDOUT $FE, $C0, "Press start/stop"
        
    Main:
        Select CASE State
            
            Case Idle
                If StartStopButton = 0 THEN             ' If the button is pressed we
                    'LCDOUT $FE, 1                       ' Clear the screen
                    Hours = 0
                    Minutes = 0
                    Seconds = 0
                    ms = 0
                    TMR1H = 0                           ' reset the pulse count
                    TMR1L = 0
                    TMR2 = 0                            ' reset the timebase
                    TMR1IF = 0                          ' clear the overflow flag
                    TMR2IF = 0                          ' clear the timebase tick flag
                    TMR1ON = 1                          ' enable the counter to count pulses from the driveshaft
                    TMR2ON = 1                          ' enable the 2ms timer tick
                    ReadyIndicator = 0                  ' update status LEDs
                    RunIndicator = 1
                    ErrorIndicator = 0
                    TimeOverflow = 0                    ' clear overflow flag
                    State = Starting                    ' and move to the next state.
                ENDIF
    '---------------------------------------------------------------------------------------------------            
            CASE Starting
                IF TMR2IF THEN                          ' TMR2IF gets set every 2ms
                    TMR2IF = 0                          ' reset flag
                    GOSUB Update                        ' update our time registers
                    
                    ' Wait for the button to be released before transitioning to the next state.
                    If StartStopButton = 1 THEN         ' Button released?
                        DebounceCount = DebounceCount + 1
                    ELSE
                        DebounceCount = 0               ' Button must be released 10 ticks in a row.
                    ENDIF
                    
                    IF DebounceCount = 9 THEN           ' Button has been released for 10 ticks
                        DebounceCount = 0
                        State = Counting                ' Transition to next state.
                    ENDIF
                ENDIF
    '---------------------------------------------------------------------------------------------------             
            
            Case Counting
                IF TMR2IF THEN                          ' 2ms tick?
                    TMR2IF = 0                          ' clear flag and
                    GOSUB Update                        ' update our time registers
                    
                    If StartStopButton = 0 THEN         ' Button pressed?
                        RunIndicator = 0
                        TMR1ON = 0                      ' Disable pulse counter
                        TMR2ON = 0                      ' Disable timer
                        State = Stopping
                    ENDIF
                 ENDIF
                 
                 IF TMR1IF THEN                         ' Pulse counter overflow
                    TMR1ON = 0                          ' Disable pulse counter
                    TMR2ON = 0                          ' Disable timebase
                    RunIndicator = 0
                    ErrorIndicator = 1
                    State = Error             
                 ENDIF
                 
                 ' Here we can do anything else that needs doing while the
                 ' system is counting but it's very important that it does
                 ' not take longer than 2ms or we will lose time.                    
    '---------------------------------------------------------------------------------------------------              
            CASE Stopping
                ' Wait for the button to released before transitioning to the next state,
                If StartStopButton = 1 THEN             ' Is button released?
                    DebounceCount = DebounceCount + 1
                ELSE
                    DebounceCount = 0
                ENDIF
                
                IF DebounceCount = 10 THEN              ' Button released for duration of debounde time?
                    DebounceCount = 0
                    State = Done                        ' Transition to next state.
                ENDIF
                
                ' The timer is no longer running so we pause here for the same duration.
                PAUSE 2            
    '---------------------------------------------------------------------------------------------------  
            
            CASE Done
                ' This is where we perform the calculations and present the result.
               
                ' Each count from the driveshaft equals 0.6m of car movement.
                ' Lets say the pulse count is 12345 and the seconds count is 503.
                ' We've traveled 12345*0.6=7407 metres in 503 seconds, 7407/503*3.6=53.0km/h
                ' Using the ** operator allows us to effectively multiply by fractions of 65535 so:
                '
                ' 12345 ** 39322 = 7407
                ' 7407 * 36 = 266652
                ' 266652 / 503 = 530 which we interpret as 53.0km/h
                '
                ' 53203 pulses in 1412 seconds,
                ' 53203*0.6/1412*3.6=81.39km/h:
                ' 53202 ** 39322 = 31922
                ' 31922 * 36 = 1149192
                ' 1149192 / 1412 = 813 which we interpret as 81.3km/h
                
                Distance.HIGHBYTE = TMR1H
                Distance.lowbyte = TMR1L
                Distance = Distance ** 39322        ' Multiply by 0.6, Distance is now in metres
                
                Temp = Distance * 36
                AverageSpeed = DIV32 Seconds        ' 215 for 21.5km/h
                
                LCDOUT $FE, 1, DEC Distance/1000, ".", DEC3 Distance//1000, "km in ", DEC2 Minutes, ":", DEC2 Seconds
                LCDOUT $FE, $C0, "Speed: ", DEC AverageSpeed/10,".", DEC AverageSpeed//10, "km/h"
                
                ReadyIndicator = 1
                State = Idle 
    
        
     '------------------------------------------------------------------------------   
            CASE Error
                If TMR1IF THEN                      ' Interrupt flag is set if counter has rolled over
                    LCDOUT $FE, 1, "ERROR Pulse cnt"
                ENDIF
                
                IF TimeOverflow THEN                ' Flag set if seconds variable has rolled over
                    LCDOUT $FE, 1, "ERROR Timer"
                ENDIF     
    
                LCDOUT $FE, $C0, "Restart to clear"
                
                State = Idle
        END SELECT
    
        
    Goto Main
    
    '-------------------------------------- Subroutines ------------------------------------------------
    Update:
        ' Our timebase is 500Hz.
        ms = ms + 2
        If ms = 1000 then
            ms = 0
            seconds = seconds + 1
            
            IF Seconds // 60 = 0 THEN
                Minutes = Minutes + 1
                IF Minutes = 60 THEN
                    Minutes = 0
                    Hours = Hours + 1
                ENDIF
            ENDIF
    
            UpdateDisplay = 1                   ' We're triggering a display update every second         
           
            Distance.HIGHBYTE = TMR1H
            Distance.lowbyte = TMR1L
            Distance = Distance ** 39322        ' Multiply by 0.6, Distance is now in metres
                
            Temp = Distance * 36
            AverageSpeed = DIV32 Seconds        ' 215 for 21.5km/h
            
            ' We're using DIV32 to calculate the average speed. It does not allow the divisor
            ' to be larger than 32767 (which is 9 hours and some minutes so it should be fine)
            ' but since we're good programmers we're going to check for it anyway.
            If Seconds > 32767 THEN
                TimeOverflow = 1
                RunIndicator = 0
                ErrorIndicator = 1
                State = Error
            ENDIF
    
        ENDIF
    
        ' Since we have a 2ms time tick and we're polling the that tick with software
        ' we can not allow ourselves to spend too much time doing anything else.
        ' For this reason we've divided the while display update process in sections
        ' so we do it little by little while still going back checking the timer tick
        ' so that we don't lose track of time.
        IF UpdateDisplay THEN
            Select Case LCDSequence
                Case 1
                    LCDOUT $FE, 128             ' Cursor at first character, first line        
                CASE 2
                    LCDOUT DEC2 Minutes, ":"
                CASE 3
                    LCDOUT DEC2 Seconds//60
                CASE 4
                    LCDOUT "   "
                    IF Distance < 10000 THEN
                        LCDOUT " "
                    ENDIF   
                CASE 5
                    LCDOUT DEC Distance/1000, ".", DEC3 Distance//1000
                CASE 6
                    LCDOUT "km  "
                CASE 7
                    LCDOUT $FE, $C0             ' Cursor at second line
                CASE 8
                    LCDOUT DEC AverageSpeed/10,".", DEC AverageSpeed//10, "km/h  "
                CASE 9
                    LCDOUT "       "
            END SELECT      
        
            LCDSequence = LCDSequence + 1
            IF LCDSequence = 10 THEN
                LCDSequence = 0
                UpdateDisplay = 0
            ENDIF
        ENDIF
    
    RETURN
    /Henrik.

  2. #2
    Join Date
    Jan 2008
    Location
    Selm, Germany
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    hello Henrik,

    wow, you are really fast! I had no time to build anything we drove another Oldtimer-rallye made Place 9 in our class and cups were down to #8, haha so no cup either.

    1 Questions:

    1. I need to calibrate the distanc efactor. You wrote

    Distance = Distance ** 39322 ' Multiply by 0.6, Distance is now in metres

    so I have to change this 39322 am I right?

    I ordered the parts (the PIC has 40 pins and is large) and will fix it on a veroboard.

    Regards

    Mugelpower

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,623


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    Hi,
    You don't have to use the 40-pin 18F45K22. You can use the 28-pin 18F25K22 with very minor changes to the code (CONFIG) or you can use another PIC - as long as it has a TMR1 & TMR2. But, if you want the code to run as-is then 45K22 it is.

    If the distance per pulse is not 0.6m then you need to change the 39322 constant. For 0.61m it would be 39977 and for 0.59m it would be 38666 so as I think you can see you should be able to calibrate very accuratly. The final result will always suffer from truncation in the math routines so the display can be short as much as one count (0.6m or whatever distance one pulse equals) - which I don't think matters much.

    /Henrik.

  4. #4
    Join Date
    Jan 2008
    Location
    Selm, Germany
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    Hello Henrik,

    I guess I´m blind. In the first program you had RB6 as counter input. In the second program RB6 is the start-stop button. Where did the counter input go?

    regards
    Mugelpower

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,623


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    On the 18F1320 (for which I tried to write the original program) the T1CKI is on RB6. On the 18F45K22 the T1CKI is on RC0.

    /Henrik.

  6. #6
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,623


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    Did you ever get it running on your end or did you loose interest?

    I'm cleaning up my desk, can I put the dev board away?
    It's best to ask because if I don't Murphy tells me there will be a new question, bug report or feature request tomorrow :-)

    /Henrik.

  7. #7
    Join Date
    Jan 2008
    Location
    Selm, Germany
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Real time clock + external interrupt in one PIC possible?

    Hello Henrik,
    no I´m not out of interest. I bought some 18F45K22 and 16Mhz crystal generators and then realized my PICKIT2 doesn´t support this device. I really appreciate your help and I´m astonishied about your speed. But I need some more time to get
    into the hardware. I´ll realize that with a 18F1320 because i am already working on a project : a water pump, fuel pump and fan controller. I´m shure the configs for the speedo project will drive me crazy.

Similar Threads

  1. real time clock
    By maria in forum Code Examples
    Replies: 44
    Last Post: - 1st March 2022, 13:13
  2. Real time clock + external interrupt in one PIC possible?
    By Mugelpower in forum mel PIC BASIC
    Replies: 1
    Last Post: - 10th September 2017, 18:11
  3. Real Time Clock
    By in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 2nd June 2012, 05:52
  4. Real time clock
    By PlantBob in forum mel PIC BASIC Pro
    Replies: 8
    Last Post: - 10th February 2011, 14:01
  5. Real Time Clock
    By savnik in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 8th December 2006, 03:02

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