News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

increasing a variable every seconds using timer

Started by Yves, May 27, 2021, 03:53 PM

Previous topic - Next topic

Yves

Hello all,

I'm using a 18F25k22 chip running at 20Mz  is it possible to increase a variable accurately every second using one of the timers with or without using the interrupt routines. My routine is taking a little less than 1 second to complete so I would like to trigger the routine at every second and record the seconds. Thank you.

Regards,

Yves
 
Yves

trastikata

How accurate is "accurately"? Do you want to take in consideration the time it takes to execute the interrupt routine? If such an accuracy is not required then this simple program layout can help you. I didn't have time to look at the 18F25k22 datasheet, so I used one of my programs and deleted the unnecessary code but the register should match - so check the datasheet.

Device = 18F26J50

Declare Xtal = 48

Declare FSR_CONTEXT_SAVE = On
Declare LABEL_BANK_RESETS = On
Declare Optimiser_Level = 3
Declare Dead_Code_Remove = On


Symbol TMR0ON = T0CON.7
Symbol TMR0IF = INTCON.2

Dim IntTrigger As Byte              'Marker to check if the interrupt has been called
Dim SecondsCounter As Dword         'Holds the number of times the interrupt has been called, thus the seconds

On_Hardware_Interrupt GoTo Isr
GoTo Main

'########################################################################## ISR 1000 ms
Isr:
    Context Save
        If TMR0IF = 1 Then
            TMR0ON = 0
           
            Inc IntTrigger
            Inc SecondsCounter 
           
            TMR0H = $48 : TMR0L = $E5   
            TMR0IF = 0 : TMR0ON = 1 
        EndIf 
    Context Restore

'########################################################################## Program Start

Main:
    Clear
    TMR0ON = 0 : T0CON = %00000111 : TMR0H = $48 : TMR0L = $E5
    INTCON.7 = 1 : INTCON.5 = 1 : INTCON.2 = 0 : INTCON2.2 = 0 : INTCON2.7 = 1
   
    TMR0ON = 1
   
    While 1 = 1
        GoSub MySubRoutine   
        While IntTrigger < 1 : Wend
        IntTrigger = 0
    Wend

MySubRoutine:
    'Do something
Return

david

#2
Hi Yves,
I recently had a very similar requirement - a measurement loop somewhat less than a second and because I needed to accumulate W.H I needed a 1 second interval.
I didn't use interrupts and just used the following at the start of the loop.  The program waits until the background timer sets its flag.  I used Timer 1 and a software counter of 4 for my 8MHz PIC.  You should use a software count of 10 with the 20MHz clock.   You can fine tune with the preload value.

Dim Timer1 As TMR1L.Word

start:                               'timer 1 preload 3036, prescale 8, 8MHz clock=250mS/4Hz
      For tick=0 To 3                '1/4 software counter
        While PIR1.0=0 :Wend       'wait while TMR1IF is low
        T1CON.0=0                       'stop timer1 when flag goes high
        Timer1=3036                    'preset Tmr1 value   
        PIR1.0=0                          'clear flag
        T1CON.0=1                      'start Tmr1
      Next tick                          '1 sec timer

I'm no expert so I'll leave it to others to comment on how appropriate this might be but it is working nicely for me.  Accuracy is ok (~0.4%) but then I'm using an internal oscillator which is as yet untuned.   You can increment your seconds count in the main loop.
Good luck with yours.

Cheers,
David

Giuseppe

To have a more accurate time precision it is better to use an external quartz

John Drew

Giuseppe,
Yes using a quartz crystal will give best results but if you do that then you need to go to an interrupt driven system for the absolute best results. Interrupts aren't that hard.If you need a hand I'm sure I and others on the forum would help.
Currently I have a 18F25K22 running a slave I2C interrupt on High Priority into a buffer and two time intervals run by a Low priority interrupt. Once you get the hang of it they are straight forward enough.
John

Here's some of the code
'setup the timer1 T1CON
    T1CON = %00110110                   ' setup the timer 1 but not TMR1ON (do in software) 16 bit update
    Symbol TMR1ON = T1CON.0             ' Timer1 enable                            set to 1 to operate interrupt
    Symbol TMR1IF = PIR1.0              ' the overflow bit for timer1 1=overflow   the interrupt flag
    Symbol TMR1IP = IPR1.0              ' timer1 will have low priority if 0       set to 0 so timer is low priority
    Symbol SSP1IP = IPR1.3              ' mssp will have high priority if 1        set to 1 so MSSP1 has high priority
    Symbol TMR1IE = PIE1.0              ' timer1 interrupt overflow bit            sets timer 1 for overflow interrupt
    Symbol IPEN   = RCON.7              ' enable priority interrupts if 1          set to 1

On_Interrupt BringInI2C                 'define the interrupt routine

'high priority interrupt is stripped out
'start of low priority interrupt
DoTimer:
    Context Save
    If TMR1IF = 1 Then
       TMR1L = $0
       TMR1H = $0
       Inc TimerCounter
       If TimerCounter > 54000 then         'set for timeout 30 = 1 sec so 30mins = 54000
          AllowDisplay = 0                  'tell main loop that display should be off
       EndIf
       Inc Keytimeout
       if KeyTimeout > 9000 then            '5 mins
          KeyTimeoutFlag = 1
       EndIf
       TMR1IF = 0
    EndIf
    Context Restore

Initialise:
    'timer1 interrupts
    TMR1IP = 0              'timer1 has low priority in IPR register
    TMR1ON = 1              'turn on timer1
    TMR1IE = 1              'enable timer 1 overflow interrupt
    IPEN = 1                'enable priority interrupts


Just an example. I've only shown the timer part of the code and as I have two interrupts (I2C slave and timer) running the IPEN is set to a 1. If you only have one interrupt running you would make IPEN = 0
The first timer is turning a screen off after 30 minutes while the second timer is used to recover from a keyboard operation if someone on site forgets to drop out of keyboard edit mode after 5 minutes. A keypress keeps both interrupts running so a user can use the keyboard on the graphic display as long as they like - as long as they use the touchpad! I haven't shown how the flags are reset by a keypress etc. Essentially: Timercounter = 0 and AllowDisplay =  0

Just an illustration of one approach.

top204

See the post I added here:

Timer overflow interrupt calculation within the BASIC source code

It shows how to calculate the timing of an overflow interrupt. The tweak constant is there to take into account the small delays that happen when an interrupt fires.

david

Hello John,
Yes no question about using a xtal for better precision but unfortunately in my example I had already maxed out the pin budget and to be honest the precision I required is not that high.  For serious stuff I use a PIC, a $15 GPS module and a 10MHz ovenised oscillator rigged as a long integral, frequency locked loop.

Now I'm not knocking your use of interrupts  but I must question the need for them if the main program loop has some dwell time in it and there no other tasks taking place as the original poster claims.  The actual counter code should have a fixed number of bytes in it so that can be allowed for in the pre-load value as per the attached.
If the program was not a big loop with a generous break in it then I think you have to go for an interrupt driven process.

Cheers,
David

John Drew

Hi David, agree completely.
Sometimes a simple loop is all that's needed. A lot depends on how busy and unpredictable the code flow is.
John

david

Hello John,
As you rightly point out, the non-interrupt code only works if there is no processor activity to interrupt.  It is much the same but doesn't have to break in to the foreground task.
Isn't it great having the compiler developer leap in to the discussions.   I don't ever recall Bill Gates doing that.....

Cheers,
David

top204

"Bill Gates"... I wish. :-)

Unfortunately, I was with people who did not believe in the compilers and did not bother advertising or promoting or having a web site full of information and catchy graphics etc, so they got left behind. :-(