I want to use 2 timer interrupts. One of them will be always firing at 50 ms (Timer1) and the other at 1ms (Timer0). The 50ms one should always run and never stop. The 1ms one will be used for other things and will be stopped and started occasionally. How can I use the IntOn and IntOff on just the 1ms timer without effecting the 50ms timer? In other words is there a method or someting like Timer0IntOff and Timer0IntOn to control an individual timer?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
IntOn and IntOff will start and stop all interrupts, they are the Global Interrupt Enable / Disable commands.
You can enable and disable the interrupts on individual peripherals by setting and clearing their unique interrupt Control Bit.
You need to refer to the Datasheet for the Register/Bit names but as you chose Timer0 which I happen to know off hand you need the following 2 commands:
You can tell I know PIC architecture better than I do Great Cow Basic at the moment :)
But that is one of the things that make Great Cow Basic stand out from all other compilers and languages, you can freely mix assembler, direct register access and the Basic language on the fly.
But don't do it if you want your code to be portable, in that case stick with GCBasic commands alone.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Or use a state machine? Set up a single timer for both (or multiple) operations by incrementing a counter in the 1ms interrupt handler. Use Select Case in main to decide what to do at 1ms and the 50 x 1ms interval where the counter is reset and start over again.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Excellent, so I probably will never have to stop the timers, I just need to disable the interrupt. Thanks for all you help Chris. Your examples are really helpful!!!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Now seeing Evans post, maybe I should stop the timer instead? Just saw your statemachine post. That sounds like the best idea yet. I will start looking into that. I could probably use that method for many different events also, using just one timer instead of multiple timers. Can you give me a quick example of that using the case?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
So a 100ms timer1 interrupt example I believe? Well in this case I used if statements...dealers choice :) In one instance a binary pushwheel switch is checked on. And in the other, a DS18S20 temp conversion is started, and then a second later the scratchpad is read (No tying up the controller with a wait!).
'*******Timer 1 Interrupt**************
On Interrupt Timer1Overflow Call Event_Schedule
InitTimer1 Osc, PS1_1/8
TMR1H = 133 '10MHz clock, PS1_1/8, TMR1H= 133, TMR1L = 237
TMR1L = 237
StartTimer 1
...
...
...
If TenthSec = 5 Then
'remember to install 10k pull down R's to input pins & zero ohm R's to the binary switch!!!
Group = PortD AND b'01110000'
If Group = 0 Then
FourColor = True
AnalogColor = False
EncoderColor = False
DisplayPots = False
Latch = 0
pfetsH = 255
pfetsL = 255
OutSeg pfetsH
OutSeg pfetsL
Latch = 1
end if
If Group = 64 Then
Group = 1
FourColor = False
AnalogColor = True
EncoderColor = False
TempRead = False
VoltRead = False
AmpRead = False
DisplayPots = True
Set led1 Off
end if
If Group = 32 Then
Group = 2
FourColor = False
AnalogColor = False
EncoderColor = True
DisplayPots = False
Latch = 0
pfetsH = 255
pfetsL = 255
OutSeg pfetsH
OutSeg pfetsL
Latch = 1
'Set led1 On
end if
end if
If TenthSec = 10 Then 'tenthsec multiplier or 1 sec intervals
Call DisplayNum LedTemp
LED_ON = NOT LED_ON 'toggle led flag
'Set TMR1ON OFF
IF LED_ON = True Then
Set LED1 ON
'start DS18S20 temp conversion
MasterRST
OWout SkipRom
OWout ConvertT
Else
Set LED1 OFF
'read DS18S20 temp conversion
MasterRST
OWout SkipRom
OWout ReadScratch
Owin
LedTemp = HighLow/2
End If
TenthSec = 0
fanspeed += 1
TMR1H = 60
TMR1L = 175
Set TMR1ON ON
End if
...
...
'*****Timer 1 Overflow Event Scheduler*******
sub Event_Schedule
TMR1IF = 0
TMR1H = 133 '10MHz clock, PS1_1/8, TMR1H= 133, TMR1L = 237
TMR1L = 237
TenthSec += 1
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Whilst we are on the subject of State Machines and Timers you may notice that the above structure could also form the basis of a Multitasking or Time Slicing system. If your timer tick is 1 mS and your Microcontroller is running at 32Mhz it can execute about 8 thousand instructions in that millisecond.
Consider this structure:
''' 16f18855 - Task Scheduler.gcb '''' --- Configuration '#chip 16f18855,32#Config FEXTOSC_OFF, RSTOSC_HFINT32#Config WRT_OFF, CPD_ON, MCLRE_OFF' TMR0_Initialize() 'InitTimer0(Osc,(TMR0_FOSC4+PRE0_32),POST0_1)SetTimer(0,0xF900)' Preload Count for 1ms 'StartTimer0' Add a handler for the interrupt 'OnInterruptTimer0OverflowCallTMR0_ISR#Define TASKS 3DoSelectCaseTaskCase0:Task0Case1:Task1Case2:Task2Case3:Task3CaseElseTaskErrorEndSelectLoopSubTask0' ... 'EndSubSubTask1' ... 'EndSubSubTask2' ... 'EndSubSubTask3' ... 'EndSubSubTaskErrorENDEndSubSubTMR0_ISR()SetTimer(0,0xFA00)' reset count for 1ms adj for isr time't0_millis+=1' Keep for the Millis() function. 'ifTask++>TASKSthenTask=0EndSubfunctionmillis()aslong' disable interrupts while we read t0_millis or we might get an '' inconsistent value (e.g. in the middle of a write to t0_millis)'IntOffmillis=t0_millisIntOnendFunctionEnd
Every millisecond a new task will run, to a human it will appear as if they all execute simultaneously because a 1 mS period is far to small for us to notice. Even the best reaction time from the best athlete will be in the region of 100mS. But to the Microcontroller that 1 mS is a lot of time and it can perform a lot of instructions in that time.
The entire outline above is only 204 instructions, so even if every instruction were to run on every pass through the structure we would still have time to execute 7,750 instructions at least before the task switches again.. Just remember that the task must complete within the mS, this code is not reentrant and it is not preemptive, if the task does not yield the next task will not be able to run.
To handle delays we can use the Millis() function, described elsewhere, and abort if it is not time to change, so you will be surprised how much can be done in a 1 mS time slice.
If anything is time critical like the USART it can be interrupt driven, as can input buttons etc. just have the Interrupt Routine set a flag to say the event happened and have the appropriate task handle it when called.
Cheers
Chris
Last edit: Chris Roper 2016-07-14
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I want to use 2 timer interrupts. One of them will be always firing at 50 ms (Timer1) and the other at 1ms (Timer0). The 50ms one should always run and never stop. The 1ms one will be used for other things and will be stopped and started occasionally. How can I use the IntOn and IntOff on just the 1ms timer without effecting the 50ms timer? In other words is there a method or someting like Timer0IntOff and Timer0IntOn to control an individual timer?
IntOn and IntOff will start and stop all interrupts, they are the Global Interrupt Enable / Disable commands.
You can enable and disable the interrupts on individual peripherals by setting and clearing their unique interrupt Control Bit.
You need to refer to the Datasheet for the Register/Bit names but as you chose Timer0 which I happen to know off hand you need the following 2 commands:
As you mentioned Starting and Stopping Timer0 as well as disabling the interrupt you may also need:
Cheers
Chris
Last edit: Chris Roper 2016-07-14
Great Cow BASIC commands are
StartTimer x
StopTimer x
so, you would use StartTImer 0 and StopTimer 0
:-)
You can tell I know PIC architecture better than I do Great Cow Basic at the moment :)
But that is one of the things that make Great Cow Basic stand out from all other compilers and languages, you can freely mix assembler, direct register access and the Basic language on the fly.
But don't do it if you want your code to be portable, in that case stick with GCBasic commands alone.
Or use a state machine? Set up a single timer for both (or multiple) operations by incrementing a counter in the 1ms interrupt handler. Use Select Case in main to decide what to do at 1ms and the 50 x 1ms interval where the counter is reset and start over again.
Excellent, so I probably will never have to stop the timers, I just need to disable the interrupt. Thanks for all you help Chris. Your examples are really helpful!!!
Now seeing Evans post, maybe I should stop the timer instead? Just saw your statemachine post. That sounds like the best idea yet. I will start looking into that. I could probably use that method for many different events also, using just one timer instead of multiple timers. Can you give me a quick example of that using the case?
I have a question. What are we, as a collective, building?
This may help us understand the goal.
Are you building a timemachine? That would be so cool.
viscomjim:
So a 100ms timer1 interrupt example I believe? Well in this case I used if statements...dealers choice :) In one instance a binary pushwheel switch is checked on. And in the other, a DS18S20 temp conversion is started, and then a second later the scratchpad is read (No tying up the controller with a wait!).
This is the way I normally handle a state machine, it is very close to the way you are doing it above but makes it easier to read and debug:
Actual subroutine names are up to you, they don't have to be DoState1 etc, they could be FlashLED, updateDisplay, etc..
In the interrupts or whatever triggers you have for changing state you set the State variable to the appropriate State.
Cheers
Chris
p.s. was sure to only use GCBasic commands this time :-)
Last edit: Chris Roper 2016-07-14
Task Scheduler
Whilst we are on the subject of State Machines and Timers you may notice that the above structure could also form the basis of a Multitasking or Time Slicing system. If your timer tick is 1 mS and your Microcontroller is running at 32Mhz it can execute about 8 thousand instructions in that millisecond.
Consider this structure:
Every millisecond a new task will run, to a human it will appear as if they all execute simultaneously because a 1 mS period is far to small for us to notice. Even the best reaction time from the best athlete will be in the region of 100mS. But to the Microcontroller that 1 mS is a lot of time and it can perform a lot of instructions in that time.
The entire outline above is only 204 instructions, so even if every instruction were to run on every pass through the structure we would still have time to execute 7,750 instructions at least before the task switches again.. Just remember that the task must complete within the mS, this code is not reentrant and it is not preemptive, if the task does not yield the next task will not be able to run.
To handle delays we can use the Millis() function, described elsewhere, and abort if it is not time to change, so you will be surprised how much can be done in a 1 mS time slice.
If anything is time critical like the USART it can be interrupt driven, as can input buttons etc. just have the Interrupt Routine set a flag to say the event happened and have the appropriate task handle it when called.
Cheers
Chris
Last edit: Chris Roper 2016-07-14