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:
Another version of MILLIS():

Code:
'***********************************************************************
'MILLIS function II, 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.38
'By COS, 02/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 1uSec.
    Call _timer1(_on)
    Call _enable_interrupts(_int_timer1)
    'Call _enable_interrupts(_global)
    'Assign names to the Leds
    Symbol LedGreen = RB0
    Symbol LedYellow = RA7
    '********************************************************************
    Dim prev As Long
    Dim prev1 As Long
    prev = 0  'Initialize to zero
    prev1 = 0
    Call _SetUp_MILLIS()  'Initializes _MILLIS
    Call _enable_interrupts(_global)
    'Loop
    While True
       
        Call _MILLIS()  'Update _MILLIS
       
        If (_MILLIS - prev) >= 200 Then  'Wait time in mSec.
            prev = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedYellow  'Invers the state of the led.
        Endif
       
        If (_MILLIS - prev1) >= 400 Then  'Wait time in mSec.
            prev1 = _MILLIS  'The last value of _MILLIS is stored.
            Toggle LedGreen  'Invers the state of the led.
        Endif
       
    Wend
End                                              
'********************************************************************
'Group of new functions for _MILLIS
Dim _Flag_Millis As Bit
'Inicialize _MILLIS
Proc _SetUp_MILLIS()
    _MILLIS = 0
    Millis = 0
    _Flag_Millis = 0
End Proc                                        
'It hopes that Millis is stable And updates it.
Function _MILLIS() As Long
    _Flag_Millis = 1
    While _Flag_Millis = 1
    Wend
    _MILLIS = Millis
End Function                                    
'Increment the counter Millis
Function Millis() As Long
    Millis++
    _Flag_Millis = 0
End Function
'***********************************************************************
'Interrupt vector
On Interrupt
    Save System
    If _tmr1if Then
        Call _set_timer1(0xf831)  'Reload TMR1 registers to count 1mSec.
        Call Millis()  'Increments _MILLIS every mSec.
    Endif
Resume
 
Last edited:
You seem to have misunderstood what Tumbleweed was saying and your code still has the same problem.
Does Oshonsoft have repeat until?

Mike.
 
Doesn't appear to Mike. The only loop construct I see is WHILE-WEND... seems to be a real basic BASIC!

Well it's simple enough to replicate using if/then/goto :D

WHILE-WEND isn't something you get (or got) on a basic BASIC, so it's strange REPEAT-UNTIL isn't included as well?, there's very little difference in the resultant code from the two, so no real reason not to include it?.
 
One thing worth mentioning is that if you use code like from back in post 28 with an optimizing compiler you should definitely declare the variables as 'volatile', especially the 'has_updated' flag.

A "smart" compiler might optimize out the whole function, putting you right back to square one.
 
To create a conditional wait loop in this language, use While(ex.) Wend => While(Ex.) {}.

This too:

label:
if flag = 1 then goto label

But this is like going back to prehistory.
 
One thing worth mentioning is that if you use code like from back in post 28 with an optimizing compiler you should definitely declare the variables as 'volatile', especially the 'has_updated' flag.

A "smart" compiler might optimize out the whole function, putting you right back to square one.
LOL.. volatile.. ALL Vlads variables are volatile. Oshonsoft is a very basic, basic, basic... Best to write an ASM routine to read those variables
 
I actually prefer to do this, the compiler is more advanced and already takes care of managing reentries. As long as you don't make it too difficult.

//Bit (flag) de control
//Const int1 _btsetup = 1;
//Const int1 _btupdated = 0;
//Const int1 _null = 0;
#Define _BTSETUP 1
#Define _BTUPDATED 0
#Define _NULL 0
Static Int16 _ifbt;
//Funciones base de tiempos 0
//Función control base de tiempos
#bit _ifbt0 = _ifbt.0 //Bit de control Bt0
Void _bt0call(Int1 _setup, Int32 _btwait) {
Static Int32 _contador; //_contadores bases de tiempos
If (_setup == True) { //Inicializa la base de tiempos
_ifbt0 = False; //Activa la base de tiempos
_contador = _btwait; //Tiempo a contar
Return;
}
If (_contador > 0) _contador--; //_contador BT
If (_contador == 0) _ifbt0 = True; //Para BT
}
 
To create a conditional wait loop in this language, use While(ex.) Wend => While(Ex.) {}.
Unfortunately that makes it more difficult to do things like 'do... while' or 'repeat... until', so you have to do it the "hard" way.

As you say, you're stuck with what you have to deal with.
 
Every global variable is external and doesn't matter where you declare it and static.

I have to work with what I have.
No, you don't you have choices. You can continue this masochistic self-flagellation if that is your desire, or you can switch to more congenial methods to get what you want. The choice is entirely up to you.
 
Well, I think that the thread is deviating from the main topic and it is to solve a problem with this tool.

This is just a hobby anyway, doing all this with another language is no fun.

I am already many years old and also many developed automatisms, can you really imagine what language I use?.
 
Well, I think that the thread is deviating from the main topic and it is to solve a problem with this tool.

This is just a hobby anyway, doing all this with another language is no fun.

I am already many years old and also many developed automatisms, can you really imagine what language I use?.
I disagree. The topic is finding a solution. There may not be a viable solution. What will you do if that turns out to be the case? You're certainly entitled to continue on this path, or you can move in a different direction. The choice is up to you how long you want to keep beating this horse.

While we are on the topic of age, I just might have a leg up on you, and I don't see any impediments to learning new things.
 
I think you did not understand me, it will be a language problem (translation).
I will give a real example to make me understand:
This is one of the automatisms that I finished and is manufactured for approximately 1 year:
There are 5 Pics working and communicating with each other, programmed in C language.

I think I did not know how to explain the reason for the thread.

Tarjeta_24A05.jpg
 
You seem to have misunderstood Tumbleweeds solution to your problem.
If you do Word=intWord then it'll be compiled into two byte moves.
If after the first byte move an interrupt comes along then the value copied will be wrong.
To correct this you need to ensure that either,
1, if an interrupt comes along during the read then it's flagged and the value recopied.
2, You ensure an interrupt can't come along during a read - I.E. disable interrupts around the read.
Tumbleweeds code,
Code:
function millis() as unsigned long
    dim retval as unsigned long
    
    // read msec counter used in the ISR until we
    // know we weren't interrupted while accessing it
    repeat
        has_updated = 0
        retval = milli
    until (has_updated = 0)
    return retval
end function
can be implemented with a goto by doing,
Code:
function millis() as unsigned long
    dim retval as unsigned long
 loop:   
    // read msec counter used in the ISR until we
    // know we weren't interrupted while accessing it
        has_updated = 0
        retval = milli
    if has_updated = 1 then
        goto loop
    Endif
    return retval
end function

Hope this makes it clearer.
I also assume the function can be reduced to,
Code:
function millis() as unsigned long
 loop: 
// read msec counter used in the ISR until we
// know we weren't interrupted while accessing it
    has_updated = 0
    millis = milli
    if has_updated = 1 then goto loop
end function
You could also do, (solution #2)
Code:
function millis() as unsigned long
    INTCON.GIE=0
    millis = milli
    INTCON.GIE=1
end function
This has the disadvantage that it always enables interrupt which can be eliminated.
BTW, I find it dangerous to have two variables (or functions) with very similar names and would rename milli as IRQmilli. Just my personal preference.


Mike.
 

Latest threads

New Articles From Microcontroller Tips

Back
Top