Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Version of the arduino MILLIS function (OshonSoft Basic).

DogFlu66

Member
It is a version of the arduino function "MILLIS", it is a general counter that increments every mSec. and that it takes several weeks to restart.

You can download the "_FuncionesPic16F88.bas" functions from this other thread:

Note: updated code improved (3/2023)
Code:
'***********************************************************************
'MILLIS function, long type geneal counter.
'For replacing absolute pauses generated with WaitMs.
'The _MILLIS function increments every mSec. so it takes
'approximately 49.7 days To reinitialize.
'That is, it will pass through a zero value.
'************************************************************************
'Pic16F88, OshonSoft Pic Basic Compiler v.8.42
'By COS, 03/2023
'************************************************************************
#define CONFIG = 0x2f50  'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8  'Clock a 8Mhz
'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation.
Include "_FuncionesPic16F88.bas"
'************************************************************************
main:
    'Pin configuration
    AllDigital
    ConfigPin PORTA = Output
    ConfigPin PORTB = Output
    'Clock internal 8Mhz.
    Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc)
    Call _setup_oscillator(_osc_8mhz)
    'Initialize Timer1 desborde 1mSec.
    Call _setup_timer1(_tmr1_internal, _tmr1_div1)
    Call _set_timer1(0xf831)  'Interruption every 1mSec.
    Call _timer1(_on)
    Call _enable_interrupts(_int_timer1)
    'Call _enable_interrupts(_global)
    'Assign names to the Leds
    Symbol LedGreen = RB0
    Symbol LedYellow = RA7
    '********************************************************************
    Call _SetUp_MILLIS()  'Setup _MILLIS functions, before activate interrupts
    Call _enable_interrupts(_global)
    Dim PreMillis As Long
    Dim PreMillis1 As Long

    'Loop
    While True

        Call _MILLIS()  'Repeat As few times As possible, so As Not To interfere with interruptions.

        If (_MILLIS - PreMillis) >= 200 Then  'Wait time in mSec.
            PreMillis = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedYellow  'Invers the state of the led.
        Endif


        If (_MILLIS - PreMillis1) >= 400 Then  'Wait time in mSec.
            PreMillis1 = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedGreen  'Invers the state of the led.
        Endif

    Wend
End                                             
'********************************************************************
'Function _MILLIS
'Requires the use of a timer and interrupts.
'**************************************************
'Call _SetUp_MILLIS()  'Before triggering interrupts
'Call _MILLIS()  'Update _MILLIS counter
'Call _CounterMillis()  'Incrementa contador Millis
'**************************************************
'Inicialize functions
Proc _SetUp_MILLIS()
    _MILLIS = 0
    _CounterMillis = 0
End Proc                                        
'Return _MILLIS as Long and global variable
Function _MILLIS() As Long
    Disable  'Stop interruption
    _MILLIS = _CounterMillis
    Enable  'Enable interruption
End Function                                    
'Increment the counter Millis
'Return _CounterMillis as Long and global variable
Function _CounterMillis() As Long
    _CounterMillis++  'Increment counter millis
End Function                                    
'********************************************************************
'Interrupt vector
On Interrupt  'Disable interruptions
Save System
    If _tmr1if Then
        Call _set_timer1(0xf831)  'Reload TMR1 registers to count 1mSec and clear _tmr1if.
        Call _CounterMillis()  'Increments _CounterMILLIS every mSec.
    Endif
Resume  'Enable interruptions
 
Last edited:
This has the disadvantage that it always enables interrupt which can be eliminated.

For example, here's the Swordfish version of millis() from that link I posted earlier that does just that:
Code:
public function millis() as longword
    dim t_intcon as byte
    const GIE = 7

    // get current intr enable state and disable intrs
    // while we access the global msec variable
    t_intcon = INTCON
    INTCON.bits(GIE) = 0

    // read global variable to get return value
    result = tmr_ms

    // restore intr state
    if (t_intcon.bits(GIE) = 1) then
        INTCON.bits(GIE) = 1
    endif
end function

And just so we're clear, this has nothing to do with the language you're using. C, Basic, Pascal, or even asm all have the same problem. The logistics of how you implement it may change (ie no 'repeat... until'), but that's just a language issue.

We're discussing more of a fundamental programming problem, which you have to deal with no matter what language you use.
 
Ok, I'm sorry I misunderstood you, that's really a reply to a thread.

In any case, we have to take into account:

"On interrupt" => Stop global interrupts.

"Resume" => On global interrupts.

But I will continue with the topic, until you give the approval, thanks for the help.
 
Okay... DogFlu66 I like what you are doing, so keep doing what you are doing.

Everyone else... I understand the dilemma's BUT! Just for the functionality, the code he is providing is pretty damn good, so cut the guy a break..

DogFlu66 Just put a disclamer in the body of your code specifying the timer read issue and let them deal with it. I was under the same understanding that 16 bit timers are ALWAYS a pain to read as one of the bytes is unreadable directly anyway..

If you stop the timer while reading, your millis may be out by 1 anyway..
 
If you stop the timer while reading, your millis may be out by 1 anyway..
You don't stop the timer, just prevent interrupts for a (very) short time or introduce a flag as in Tumbleweeds code.

Whilst this may seem trivial, it's a problem that will almost never happen but if it does it's almost impossible to find. You know, that bug that shows up once every 6 months.

The OP doesn't seem to grasp the idea. It's a simple fix so why not just do it and then instead of "the code he is providing is pretty damn good" it'll be "the code he is providing is pretty damn excellent".

BTW, agree he should keep doing what he's doing.

Mike.
 
Of course he should keep doing examples. I certainly don't mean to discourage that.

BUT, a lot of new programmers read threads like this, so if you don't warn them about potential issues and show them ways to avoid it then they never learn. Isn't that the point of forums in the first place?

Who knows, maybe that code ends up in the next Mars rover or something. "Gee, it worked most of the time..."
 
I leave the functions using Disable/Enable to handle interrupts and read the _MILLIS counter stably.
As can be seen, the fewer times the call to Call _MiLLIS() is made, the less we interfere with the interruptions.

The bug that does not allow to perform this type of expression "If (_MILLIS - PreMILLIS1) > 1000 Then " when interrupts are active has been fixed v8.42.

Code:
'***********************************************************************
'MILLIS function III, long type geneal counter.
'For replacing absolute pauses generated with WaitMs.
'The _MILLIS() function increments every mSec. so it takes
'approximately 49.7 days To reinitialize.
'That is, it will pass through a zero value.
'************************************************************************
'Pic16F88, OshonSoft Pic Basic Compiler v8.42
'By COS, 03/2023, PCB PicEBasic.
'************************************************************************
#define CONFIG = 0x2f50  'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8  'Clock a 8Mhz
'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation.
Include "_FuncionesPic16F88.bas"
'************************************************************************
main:
    'Clock internal 8Mhz.
    Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc)
    Call _setup_oscillator(_osc_8mhz)
    'PCB configuration
    AllDigital
    TRISA = 0x00  'Puerto A como salidas
    TRISB = 0x00  'Puerto B como salidas
    TRISA.4 = 1  'Input (RA4, adc)
    TRISA.6 = 1  'Input (RA6, tecla S1)
    TRISA.5 = 1  'Input (RA5, tecla S2)
    TRISB.5 = 0  'Output (RB5,Tx RS232)
    TRISB.2 = 1  'Input (RB2, Rx RS232)
    TRISB.4 = 1  'Input (RHT03)
    TRISB.0 = 0  'Output (LedGreen)
    TRISA.7 = 0  'Output (LedYellow)
    TRISB.3 = 0  'Output (Backlight)
    'Configuration LCD 2x16 ports. ---------------------------------------
    Define LCD_BITS = 4  'Data bus length to 4bits
    Define LCD_DREG = PORTA  'Data bus: puerto A
    Define LCD_DBIT = 0  'Least significant bit of the data bus.
    Define LCD_RSREG = PORTB  'Rs control bit on port B
    Define LCD_RSBIT = 7  'RS bit on RB7 pin.
    Define LCD_EREG = PORTB  'E control bit on port B.
    Define LCD_EBIT = 6  'E pin on RB6 pin
    Define LCD_COMMANDUS = 2000  'Wait after each command in uSec.
    Define LCD_DATAUS = 100  'Wait after sending a data to the LCD in uSec.
    Define LCD_INITMS = 50  'Wait during display initialization in mSec.
    '---------------------------------------------------------------------
    Lcdinit  'Lcd withou cursor
    'Initialize Timer1 desborde 1mSec.
    Call _setup_timer1(_tmr1_internal, _tmr1_div1)
    Call _set_timer1(0xf831)  'Interruption every 1uSec.
    Call _timer1(_on)
    Call _enable_interrupts(_int_timer1)
    'Assign names to the Leds
    Symbol LedGreen = RB0
    Symbol LedYellow = RA7
    Symbol Backlight = RB3
    Backlight = 1
    '********************************************************************
    Dim PreMillis As Long
    Dim PreMillis1 As Long
 
    Lcdout "Ready"
    Call _SetUp_MILLIS()  'Initializes _MILLIS
    Call _enable_interrupts(_global)

    While True  'Infinite Loop
   
        Call _MILLIS()  'Update _MILLIS
   
        'Yellow led flashing
        If (_MILLIS - PreMillis) >= 500 Then  'If time passes (mSec.)
            PreMillis = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedYellow  'Invers the state of the led.
        Endif
   
        'Green led flashing
        If (_MILLIS - PreMILLIS1) >= 1000 Then  'If time passes (mSec.)
            PreMillis1 = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedGreen  'Invers the state of the led.
        Endif
   
    Wend
End                                          
'**************************************************
'**************************************************
'Function _MILLIS v. III
'Requires the use of a timer and interrupts.
'By COS, 02/2023, PIC Basic Compiler v8.38
'**************************************************
'Call _SetUp_MILLIS()  'Before triggering interrupts
'Call _MILLIS()  'Update _MILLIS And Return the value of the Millis counter
'Call _CounterMillis()  'Incrementa contador Millis
'**************************************************
'Group of new functions for _MILLIS
'Inicialize functions
Proc _SetUp_MILLIS()
    _MILLIS = 0
    _CounterMillis = 0
End Proc                                    
'Return _MILLIS as Long and global variable
Function _MILLIS() As Long
    Disable  'Stop interruption
    _MILLIS = _CounterMillis
    Enable  'Enable interruption
End Function                                
'Increment the counter Millis
'Return _Counter_Millis as Long and global variable
Function _CounterMillis() As Long
    _CounterMillis++
End Function                                
'**************************************************
'Interrupt vector
On Interrupt  'Disable interruption
    Save System
    If _tmr1if Then
        Call _set_timer1(0xf831)  'Reload TMR1 registers to count 1mSec and clear _Tmr1If.
        Call _CounterMillis()  'Increments counter Millis every mSec.
    Endif
Resume  'Enable interruption
 
Last edited:
Hello again; I have made a comparison between the previous _MILLIS function that stops the interruptions every time it is updated, with respect to the time bases that do not stop it.
Time bases are more complex because they use a different counter for each conditional count. But I have been surprised by its effectiveness in short programs like the one in the example.
Well, it seems that I didn't make it very clear that my purpose was to perform a _MILLIS function without having to stop the interrupts, and I really haven't been able to at the moment.

In the program I have put a counter (Counter++) that is incremented for 1Sec. both with the version for _MILLIS and the version with _BT.

_MILLIS: the counter is incremented by 7382.
_BT: increment 57259.

_MILLIS program:

'***********************************************************************
'MILLIS and BT functions, long type geneal counter.
'For replacing absolute pauses generated with WaitMs.
'The _MILLIS function increments every mSec. so it takes
'approximately 49.7 days To reinitialize.
'That is, it will pass through a zero value.
'************************************************************************
'Pic16F88, OshonSoft Pic Basic Compiler v.8.42
'By COS, 03/2023
'************************************************************************
#define CONFIG = 0x2f50 'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8 'Clock a 8Mhz
'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation.
Include "_FuncionesPic16F88.bas"
Include "_FuncionesTmrBase.bas"
Include "_FuncionMillis.bas"
'************************************************************************
main:
'Pin configuration
AllDigital
ConfigPin PORTA = Output
ConfigPin PORTB = Output
'Clock internal 8Mhz.
Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc)
Call _setup_oscillator(_osc_8mhz)
'Initialize Timer1 desborde 1mSec.
Call _setup_timer1(_tmr1_internal, _tmr1_div1)
Call _set_timer1(0xf831) 'Interruption every 1mSec.
Call _timer1(_on)
Call _enable_interrupts(_int_timer1)
'Call _enable_interrupts(_global)
'Assign names to the Leds
Symbol LedGreen = RB0
Symbol LedYellow = RA7
'********************************************************************
'Call _SetUp_MILLIS() 'Setup _MILLIS functions, before activate interrupts
'Call _enable_interrupts(_global)
Dim PreMillis As Long
Dim PreMillis1 As Long
Dim PreMillis2 As Long
Dim counter As Long
PreMillis = 0
PreMillis1 = 0
PreMillis2 = 0
counter = 0
Call _setup_millis() 'Setup _MILLIS functions, before activate interrupts
'Call _bt0call(_btsetup, 200) 'Wait time in mSec.
'Call _bt1call(_btsetup, 1) 'Wait time in mSec.
'Call _bt2call(_btsetup, 1000) 'Wait time in mSec.
Call _enable_interrupts(_global)

'Loop
While True

Call _millis() 'Repeat As few times As possible, so As Not To interfere with interruptions.

'If _bt0if = True Then
If (_millis - PreMillis) >= 200 Then 'Wait time in mSec.
PreMillis = _millis 'The last value of _MILLIS is stored.
'Call _bt0call(_btsetup, 200) 'Wait time in mSec.
Toggle LedYellow 'Invers the state of the led.
Endif

'If _bt1if = True Then
If (_millis - PreMillis1) >= 1 Then 'Wait time in mSec.
PreMillis1 = _millis 'The last value of _MILLIS is stored.
'Call _bt1call(_btsetup, 1) 'Wait time in mSec.
Toggle LedGreen 'Invers the state of the led.
Endif

counter++
If (_millis - PreMillis2) >= 1000 Then
'If _bt2if = True Then
While True
Wend
Endif

Wend
End
'********************************************************************
'********************************************************************
'Interrupt vector
On Interrupt 'Disable interruptions
Save System
If _tmr1if Then
Call _set_timer1(0xf831) 'Reload TMR1 registers to count 1mSec and clear _tmr1if.
Call _countermillis() 'Increments _CounterMILLIS every mSec.
'Call _bt0call(_btupdated, _null) 'Counter Long type
'Call _bt1call(_btupdated, _null) 'Counter Word type
'Call _bt2call(_btupdated, _null) 'Counter Word type
Endif
Resume 'Enable interruptions


_BT program:

'***********************************************************************
'MILLIS and BT functions, long type geneal counter.
'For replacing absolute pauses generated with WaitMs.
'The _MILLIS function increments every mSec. so it takes
'approximately 49.7 days To reinitialize.
'That is, it will pass through a zero value.
'************************************************************************
'Pic16F88, OshonSoft Pic Basic Compiler v.8.42
'By COS, 03/2023
'************************************************************************
#define CONFIG = 0x2f50 'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8 'Clock a 8Mhz
'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation.
Include "_FuncionesPic16F88.bas"
Include "_FuncionesTmrBase.bas"
Include "_FuncionMillis.bas"
'************************************************************************
main:
'Pin configuration
AllDigital
ConfigPin PORTA = Output
ConfigPin PORTB = Output
'Clock internal 8Mhz.
Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc)
Call _setup_oscillator(_osc_8mhz)
'Initialize Timer1 desborde 1mSec.
Call _setup_timer1(_tmr1_internal, _tmr1_div1)
Call _set_timer1(0xf831) 'Interruption every 1mSec.
Call _timer1(_on)
Call _enable_interrupts(_int_timer1)
'Call _enable_interrupts(_global)
'Assign names to the Leds
Symbol LedGreen = RB0
Symbol LedYellow = RA7
'********************************************************************
'Call _SetUp_MILLIS() 'Setup _MILLIS functions, before activate interrupts
'Call _enable_interrupts(_global)
Dim PreMillis As Long
Dim PreMillis1 As Long
Dim PreMillis2 As Long
Dim counter As Long
PreMillis = 0
PreMillis1 = 0
PreMillis2 = 0
counter = 0
'Call _setup_millis() 'Setup _MILLIS functions, before activate interrupts
Call _bt0call(_btsetup, 200) 'Wait time in mSec.
Call _bt1call(_btsetup, 1) 'Wait time in mSec.
Call _bt2call(_btsetup, 1000) 'Wait time in mSec.
Call _enable_interrupts(_global)

'Loop
While True

'Call _millis() 'Repeat As few times As possible, so As Not To interfere with interruptions.

If _bt0if = True Then
'If (_millis - PreMillis) >= 200 Then 'Wait time in mSec.
'PreMillis = _millis 'The last value of _MILLIS is stored.
Call _bt0call(_btsetup, 200) 'Wait time in mSec.
Toggle LedYellow 'Invers the state of the led.
Endif

If _bt1if = True Then
'If (_millis - PreMillis1) >= 1 Then 'Wait time in mSec.
'PreMillis1 = _millis 'The last value of _MILLIS is stored.
Call _bt1call(_btsetup, 1) 'Wait time in mSec.
Toggle LedGreen 'Invers the state of the led.
Endif

counter++
'If (_millis - PreMillis2) >= 1000 Then
If _bt2if = True Then
While True
Wend
Endif

Wend
End
'********************************************************************
'********************************************************************
'Interrupt vector
On Interrupt 'Disable interruptions
Save System
If _tmr1if Then
Call _set_timer1(0xf831) 'Reload TMR1 registers to count 1mSec and clear _tmr1if.
'Call _countermillis() 'Increments _CounterMILLIS every mSec.
Call _bt0call(_btupdated, _null) 'Counter Long type
Call _bt1call(_btupdated, _null) 'Counter Word type
Call _bt2call(_btupdated, _null) 'Counter Word type
Endif
Resume 'Enable interruptions
 

Attachments

  • _FuncionMillis.bas
    1.3 KB · Views: 156
  • _FuncionesTmrBase.bas
    8.5 KB · Views: 160
  • _FuncionesPic16F88.bas
    26.9 KB · Views: 151
Last edited:
Exactly. It's not enabling/disabling interrupts that causes the _Millis version to be slower, it's the difference in the main code... the _bt version loop is mostly a few bit tests.

Post 28 shows a method that doesn't require disabling interrupts.

The _bt version ISR would be much slower than the _Millis version ISR, especially as you add more timers, so if you have other interrupts that's something else to consider.
 
That looks very long and complicated and can still have errors.
Here's a (much) shorter version,
Code:
#define CONFIG = 0x2f50 'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8 'Clock a 8Mhz

Dim intFlag as bit
Dim ms as long

main:
    OSCCON=%01110000            '8MHz = 2,000,000 instructions per second
    'setup 1mS interrupt = 2,000,000/4 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    '                          4=prescaler    10=postscaler 
    T2CON = %01001101
    PR2 = 49
    PIR1.TMR2IE = 1              'timer 2 interrupts enable
    PEIE=1
    GIE=1
    while(1)
    wend
End

function getMillis() as long
    intFlag=false
    getMillis=ms
    if intFlag then             'if an interrupt has happened then reread the value
        getMillis=ms            'another interrupt can't happen until a full milli second has passed
    endif
End Function

On Interrupt
Save System
    intFlag=true
    if PIR2.TMR2IF then
        ms=ms+1
        PIR2.TMR2IF=0
    Endif
Resume
Note, this will never loose time (if the (8MHz) clock is accurate) and you can call getMillis as often as you wish.
The above uses Tumbleweed's idea to use an interrupt flag.

Mike.
 
Mike's use of TMR2 is nice since it automatically reloads for you, as long as the clock freq lets you use it.

I'd move the 'intflag=true' to after the TMR2IF test. You might even be able to get rid of the 'Save system' to speed things up, but I'd have to see the asm output to know if that was safe. Simple addition doesn't usually use a library, but who knows.
 
Mike's use of TMR2 is nice since it automatically reloads for you, as long as the clock freq lets you use it.
You can always work out what to put into timer2, the original I posted used a 32MHz clock and the above an 8MHz clock. If using a 64MHz clock then simply double the value in PR2 I.E. PR2=99; (zero based). If 1MHz then change post to 5 etc. So many possibilities.
I'd move the 'intflag=true' to after the TMR2IF test.
The test of TMR2IF is arbitary and could be dropped completely but still cleared (and maybe save system could be dropped too). If another interrupt gets triggered then it'll continually interrupt and stop the background code from executing = very bad.

If there was a way to just access the lowest byte of a 32 bit variable then the intFlag could be removed as well as the low byte changing will indicate an interrupt has happened.

Mike.
Edit, if Timer2 is being used for other things (PWM etc.) then timer1 can be used with the "Special Event Trigger" of the CCP to give an accurate timebase.
 
Each byte of the variables is accessible, the low byte would be variable_name.LB.
Same examples as above using TMR2:
_MILLIS: 15629
_BT: 133397

Code:
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8  'Clock a 8Mhz
'Define SIMULATION_WAITMS_VALUE = 1'Waitms is used activate for simulation.
Include "_FuncionesPic16F88.bas"
Include "_FuncionesTmrBase.bas"
Include "_FuncionMillis.bas"
'************************************************************************
main:
    'Pin configuration
    AllDigital
    ConfigPin PORTA = Output
    ConfigPin PORTB = Output
    'Configuration lcd ports. -------------------------------------
    Define LCD_BITS = 4  'Data bus length to 4bits
    Define LCD_DREG = PORTA  'Data bus: puerto A
    Define LCD_DBIT = 0  'Least significant bit of the data bus.
    Define LCD_RSREG = PORTB  'Rs control bit on port B
    Define LCD_RSBIT = 7  'RS bit on RB7 pin.
    Define LCD_EREG = PORTB  'E control bit on port B.
    Define LCD_EBIT = 6  'E pin on RB6 pin
    Define LCD_COMMANDUS = 2000  'Wait after each command in uSec.
    Define LCD_DATAUS = 100  'Wait after sending a data to the LCD in uSec.
    Define LCD_INITMS = 50  'Wait during display initialization in mSec.
    '---------------------------------------------------------------------
    'Clock internal 8Mhz.
    Call _setup_oscillator_mode_select_bit(_oscillator_mode_defined_by_fosc)
    Call _setup_oscillator(_osc_8mhz)

    Lcdinit  'Lcd withou cursor
    Lcdout "Ready"

    'Initialize timer2 desborde 1mSec.
    Call _setup_timer2(_tmr2_div16, 0x82, 1)
    Call _timer2(_on)
    Call _enable_interrupts(_int_timer2)

    'Assign names to the Leds
    Symbol LedGreen = RB0
    Symbol LedYellow = RA7
    '********************************************************************
    Dim PreMillis As Long
    Dim PreMillis1 As Long
    Dim PreMillis2 As Long
    Dim Counter As Long
    PreMillis = 0
    PreMillis1 = 0
    PreMillis2 = 0
    Counter = 0
    Call _setup_millis()  'Setup _MILLIS functions, before activate interrupts
    'Call _bt0call(_btsetup, 200)  'Wait time in mSec.
    'Call _bt1call(_btsetup, 1)  'Wait time in mSec.
    'Call _bt2call(_btsetup, 1000)  'Wait time in mSec.
    Call _enable_interrupts(_global)
    
    'Loop
    While True

        Call _millis()  'Repeat As few times As possible, so As Not To interfere with interruptions.

        'If _bt0if = True Then
        If (_millis - PreMillis) >= 200 Then  'Wait time in mSec.
            PreMillis = _millis  'The last value of _MILLIS is stored.
            'Call _bt0call(_btsetup, 100)  'Wait time in mSec.
            Toggle LedYellow  'Invers the state of the led.
        Endif

        'If _bt1if = True Then
        If (_millis - PreMillis1) >= 1 Then  'Wait time in mSec.
            PreMillis1 = _millis  'The last value of _MILLIS is stored.
            'Call _bt1call(_btsetup, 10)  'Wait time in mSec.
            Toggle LedGreen  'Invers the state of the led.
        Endif

        Counter++
        
        If (_millis - PreMillis2) >= 1000 Then
        'If _bt2if = True Then
            Lcdcmdout LcdLine2Home
            Lcdout "Counter:", #Counter
            While True
            Wend
        Endif

    Wend
End                                               
'********************************************************************
'********************************************************************
'Interrupt vector
On Interrupt  'Disable interruptions
Save System
    If _tmr2if Then
        _tmr2if = 0
        Call _countermillis()  'Increments _CounterMILLIS every mSec.
        'Call _bt0call(_btupdated, _null)  'Counter Long type
        'Call _bt1call(_btupdated, _null)  'Counter Word type
        'Call _bt2call(_btupdated, _null)  'Counter Word type
        
    Endif
Resume  'Enable interruptions
 
Using TMR2 (or TMR1+CCP) isn't going to make it any faster, it's just more accurate since every time you reload the timer you drift further and further off.

Very little is going to make the "millis" version faster since the main loop has all that 32-bit math and comparisons in it. The other version just tests bits to be set. The Millis ISR is fast, so it all depends on what you're looking for.
 
This can be further reduced by getting rid of the flag.
Code:
#define CONFIG = 0x2f50 'Fuse definition.
#define CONFIG2 = 0x3ffc
Define CLOCK_FREQUENCY = 8 'Clock a 8Mhz

Dim ms as long

main:
    OSCCON=%01110000            '8MHz = 2,000,000 instructions per second
    'setup 1mS interrupt = 2,000,000/4 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    '                          4=prescaler    10=postscaler
    T2CON = %01001101
    PR2 = 49
    PIE1.TMR2IE = 1              'timer 2 interrupts enable
    PEIE=1
    GIE=1
    while(1)
    wend
End

function getMillis() as long
    getMillis=ms
    if getMillis.LB<>ms.LB then 'an interrupt must have happened so fetch it again
        getMillis=ms            'another interrupt can't happen until a full milli second has passed
    endif
End Function

On Interrupt
Save System
      ms=ms+1
      PIR1.TMR2IF=0
Resume


Mike.
 
Last edited:
Using TMR2 (or TMR1+CCP) isn't going to make it any faster, it's just more accurate since every time you reload the timer you drift further and further off.
Not really, as you simply compensate for the reload time, this is clearly explained in the datasheets and application notes. As I recall it's two instruction cycles you have to reduce the timer value by?.

However, tmr2 (or any even timer) is often more convenient.

As for the millis() function, I generally just pause the timer interrupt flag - as far as I'm aware you don't lose any accuracy by this, as it simply triggers as soon as you re-enable it, if a timer interrupt happened while it was paused.
 
As for the millis() function, I generally just pause the timer interrupt flag - as far as I'm aware you don't lose any accuracy by this, as it simply triggers as soon as you re-enable it, if a timer interrupt happened while it was paused
Think I explained this in #64.

Mike.
Edit, and the IRQ lag? (1 or 2 instructions) cannot be fixed - it needs to be hardware.
 
Counter = 15278

Times accessed (If GetMillis.LB <> MS.LB Then): 116
Access times may vary.


'********************************************************************
Function GetMillis() As Long
GetMillis = MS
If GetMillis.LB <> MS.LB Then 'an interrupt must have happened so fetch it again
GetMillis = MS 'another interrupt can't happen until a full milli second has passed
Endif
End Function
'********************************************************************
'Interrupt vector
On Interrupt 'Disable interruptions
Save System
If _tmr2if Then
MS++ 'Increments _CounterMILLIS every mSec.
_tmr2if = 0
Endif
Resume 'Enable interruptions
 
Last edited:

New Articles From Microcontroller Tips

Back
Top