buy hot The Fixer cool video Year One download Kasabian album nice Terminator Salvation hit cool track Jordin Sparks USA Whatever Works video download Check My Brain melodies nice video Finding Nemo nice Pop - Various Artists hit cheap DIVX Year One

digital-diy.com

Swordfish Code Snippet - Multi Tasking Print E-mail
( 4 Votes )
  
Saturday, 04 April 2009 10:18

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, the truth of the matter is that it is. Consider the following code and the video below;

 

 

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;

multi-tasking1


Comments (3)
  • Sergio Pinheiro  - Includding TMR0 and CCP1 Reading

    Hi Friend,

    my name is Sérgio, the guy who is trying to adapat your code to my new on-board computer !

    Well, my doubt is :

    My original source code was written in PicBasicPro using a 16F877, and I was using 3 different interrupts provided by the Darrel taylor´s interrupt lib.

    a) Timer2 for the Time-base (500ms)
    b) Timer0 to read the Speed sensor
    c) Timer1 (CCP1) to read the Injector´s on-time to calculet the fuel consumption.

    Analyzing your code, I did start trying to read the TMR0, configuring it as follows :

    Sub TMR0_Initialize()
    T0CON.7 = 0 'stop timer0 if its running
    T0CON.4 = 0 'increment on rising edge
    T0CON.5 = 1 'Put Timer0 in counter mode
    T0CON.6 = 0 '16 bit mode
    T0CON.3 = 1 'no prescaler
    TMR0H = 0 'clear the high byte of the count register
    TMR0L = 0 'clear the low byte of the count register
    T0CON.7 = 1 'start timer
    End Sub

    After that, I have another sub to read the TMR0 value :

    Sub TMR0_Read()
    PulseCount.Byte1 = TMR0H 'get high byte first
    PulseCount.Byte0 = TMR0L 'get low byte next
    TMR0H = 0 'clear high byte
    TMR0L = 0 'clear low byte
    GLCD.WriteAt(1,25,DecToStr(PulseCount,3))
    End Sub

    Modifying your code, the button has been modified to call TMR0_Read :

    If Task_1 = True Then // Waits for each service request bit to go high
    Task_1 = False // then services the task as required
    TMR0_Read()
    EndIf

    after some tests, I could note get any success.

    My doubt is : Do I have to create another interrupt functions to read each timer and/or CCP or My TMR0 routine is enough ?

    Regards !

    Sérgio

  • Sergio  - Got it !

    Hi Graham,

    finally I got the TMR0 running as a counter with your multi-task program !
    very nice !
    Now, I´m starting to configure the CCP1.
    To do that I will have to re-wire my circuit as I´m using a KS0108 display and I need the CCP1 and CCP2 pisn available to capture injector´s time and RPM pulses.

    I will keep you posted !

    my best regards.

    Sérgio

  • digital-diy

    Great to hear Sérgio!

    Think of multitasking as "Time Slicing", your not actually doing more than one task at a time, your spending X time on each task.

    Micrcontrollers work so quickly that this approach appears to be more than one task being serviced at the same time, handy!

Write comment
Your Contact Details:
Comment:
[b] [i] [u] [url] [quote] [code] [img]   
Security
Please input the anti-spam code that you can read in the image.
Last Updated ( Monday, 27 April 2009 10:40 )