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

 Skip Navigation Links.

Collapse Site Tutorial IndexSite Tutorial Index
Expand 16F PIC Examples16F PIC Examples
Collapse 18F PIC Examples18F PIC Examples
LED's
Switches
Expand 7 Segment Displays7 Segment Displays
LCD's
Expand 7 Segment Displays7 Segment Displays
ADC
ADC (Another Example)
EEPROM's
DS1307
Expand RS232 and UARTRS232 and UART
DS18B20
External ADC
Hall Effect Sensor
Pulse Width Modulation (PWM)
Infrared UART
Swordfish Modules
Collapse Code SnippetsCode Snippets
SF Libraries
18F Transition Guide
Internal Oscillator
PLL
Structures
Multi Tasking
Expand Internal TimersInternal Timers
Expand InterruptsInterrupts
Expand Handy TipsHandy Tips