18F Code Snippet - Multi Tasking
Who ever said
PIC's can't do more than one thing at the same time was right, that's because
they have a single instruction pointer that executes one command at a time. But
what if one function took 1mS, and another took 3mS (and so on). Instead of
waiting forever servicing the one function/waiting for a condition, why not
allocate a time interval for each task, eg
Perform Task 1
every 10mS
Perform Task 2 every 5mS
Perform Task 3 every 25mS
One thing to
keep in mind is that each task takes time, and you should allocate enough time
for the task to complete, and every other task (as sooner or later, all the
tasks will be synchronized and will need to be serviced one after the other).
This is only really important if you want perfect timing, but its definitely not
needed for most (almost all) applications, as each task will be serviced no
matter what with this method.
OK, lets move
on. My first task is to scan for a button press. The button will control a
counter on an
LCD, but at the same time, I want to update the current time on
the
LCD. I cant check the button every mS, or else the counter will almost
instantly go to max, and there's
no point updating the
LCD display
more than once a second to show
current time... So lets
multi-task!
To spice it up
a little, I'm going to add two more tasks, frequency generators. (4 Tasks in
total)
|
Task |
Frequency Interval |
| Check Button & Update Counter |
500mS |
| Update Current Time |
1000mS |
| Frequency Generator 1 |
100mS
(10Hz) |
| Frequency Generator 2 |
5mS
(200Hz) |
Sounds a little tricky, but consider the
following code;
Device = 18F452
Clock = 20
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTE.0
#option LCD_EN = PORTE.1
Include "LCD.bas"
Include "utils.bas"
Include "convert.bas"
Dim
TMR2_Int_Enable As PIE1.1, // TMR2 interrupt enable
TMR2_Overflow As PIR1.1, // TMR2 overflow flag
TMR2_On As T2CON.2, // Enables TMR2 to begin incrementing
mS As Word, // Time Registers
S As Byte, //
M As Byte, //
H As Byte, //
Task_1_Timer As Word, // Task 1 = Check if button pressed
Task_2_Timer As Word, // Update Time on LCD
Task_3_Timer As Word, // Frequency output 1
Task_4_Timer As Word, // Frequency output 2
Task_1 As Boolean, // Task service request bits
Task_2 As Boolean, //
Task_3 As Boolean, //
Task_4 As Boolean, //
Example_Counter As Byte, // Counter register for the button
Button As PORTA.0 // Assing the button Pin
Const
Task_1_Interval = 500, // mS interval for button check
Task_2_Interval = 1000, // mS interval between LCD time display updates
Task_3_Interval = 100, // mS interval for frequency generator output 1
Task_4_Interval = 5 // mS interval for frequency generator output 2
Interrupt TMR2_Interrupt()
Save(0)
If TMR2_Overflow = 1 And TMR2_Int_Enable = 1 Then
TMR2_Overflow = 0 // Reset TMR2 Overflow flag
mS = mS + 1
If mS = 1000 Then // Code for current time
mS = 0
S = S + 1
If S = 60 Then
S = 0
M = M + 1
If M = 60 Then
M = 0
H = H + 1
If H = 24 Then
H = 0
EndIf
EndIf
EndIf
EndIf
Task_1_Timer = Task_1_Timer + 1 // Increment all Task handlers
Task_2_Timer = Task_2_Timer + 1
Task_3_Timer = Task_3_Timer + 1
Task_4_Timer = Task_4_Timer + 1
If Task_1_Timer = Task_1_Interval Then // Check if a task interval is
Task_1_Timer = 0 // ready to be flagged
Task_1 = True
EndIf
If Task_2_Timer = Task_2_Interval Then
Task_2_Timer = 0
Task_2 = True
EndIf
If Task_3_Timer = Task_3_Interval Then
Task_3_Timer = 0
Task_3 = True
EndIf
If Task_4_Timer = Task_4_Interval Then
Task_4_Timer = 0
Task_4 = True
EndIf
EndIf
Restore
End Interrupt
Sub TMR2_Initialize()
TMR2_On = 0 // Disbale TMR2
TMR2_Int_Enable = 0 // Turn off TMR2 interrupts
INTCON.6 = 1 // Peripheral Interrupts Enabled
T2CON.0 = 1 // 00 = Prescaler is 1
T2CON.1 = 0 // 01 = Prescaler is 4
// 1x = Prescaler is 16
PR2 = 249 // TMR2 Period register PR2
T2CON.3 = 0 // 0000 = 1:1 postscale
T2CON.4 = 0 // 0001 = 1:2 postscale
T2CON.5 = 1 // 0010 = 1:3 postscale
T2CON.6 = 0 // 1111 = 1:16 postscale
TMR2 = 0 // Reset TMR2 Value
TMR2_Int_Enable = 1 // Enable TMR2 interrupts
TMR2_On = 1 // Enable TMR2 to increment
Enable(TMR2_Interrupt)
End Sub
Sub Check_Button()
If Button = 1 Then
Example_Counter = Example_Counter + 1
WriteAt(1,11,DecToStr(Example_Counter,3))
EndIf
End Sub
Sub Update_Time()
WriteAt(2,7,DecToStr(H,2), ":", DecToStr(M,2), ":", DecToStr(S,2))
End Sub
Sub Freqency_Output_1()
PORTB.0 = 1
PORTB.0 = 0
End Sub
Sub Freqency_Output_2()
PORTB.1 = 1
PORTB.1 = 0
End Sub
DelayMS(200) // Allow LCD to warm up
SetAllDigital // Make all pins digital I/O's
Cls // Clear the LCD screen
WriteAt(1,1,"Counter = 000") // Send text that only needs to be sent once
WriteAt(2,1,"Time:") // to the LCD
mS = 0 // Reset all registers
S = 0 //
M = 30 //
H = 12 //
Example_Counter = 0 //
Task_1_Timer = 0 //
Task_2_Timer = 0 //
Task_3_Timer = 0 //
Task_4_Timer = 0 //
Task_1 = False //
Task_2 = False //
Task_3 = False //
Task_4 = False //
Input(Button) // Make the button an input
Low(PORTB.0) // Make frequency 1 signal an output and low
Low(PORTB.1) // Make frequency 2 signal an output and low
TMR2_Initialize // Turn on TMR2 (with settings for 1mS interrupt)
While 1 = 1 // Main program loop that is multi-tasked
If Task_1 = True Then // Waits for each service request bit to go high
Task_1 = False // then services the task as required
Check_Button
EndIf
If Task_2 = True Then
Task_2 = False
Update_Time
EndIf
If Task_3 = True Then
Task_3 = False
Freqency_Output_1
EndIf
If Task_4 = True Then
Task_4 = False
Freqency_Output_2
EndIf
Wend
Notice that the interrupt
contains only simple flag setting and variable increments. The actual tasks are
performed outside the interrupt, so one task could be doing its thing, an
interrupt occurs mid way through, "flagging" a task if its intervals elapses.
This ensures that the task is serviced when the previous task is complete, easy!
The result, 4 tasks being
performed at the same time at precise intervals;

Note the PIC's power supply/oscillator are not shown
Click here to watch this circuit in action

 | Site Tutorial Index |
|  | 16F PIC Examples |
|  | 18F PIC Examples |
| |  | 7 Segment Displays |
| |  | 7 Segment Displays |
| |  | RS232 and UART |
| |  | Code Snippets |
| | |  | Internal Timers |
| | |  | Interrupts |
|  | Handy Tips |