Menu

Multitasking in GCBASIC

2008-05-28
2013-05-30
  • Internet Lam

    Internet Lam - 2008-05-28

    Folks, I've created a sample multitasking, Time-slice based OS and it is working in GCBASIC. Feel free to use this template and make your program multitasking. If you have updated it, kindly post it here for sharing. Thanks.

    This example connects a LED to PORTA.4 to indicate the LIFE activity. LCD is configured as 4-bit mode to display the counter value. Enjoy multitasking.

    ' Time slice multitasking for GCBASIC
    '
    ' (c) Shane Tolmie, http://www.microchipc.com/,
    ' Distribute freely for non commercial use on the condition that you
    ' include this web link somewhere in your document.
    ' Multitasking system - handle multiple tasks with one microprocessor.
    '
    ' Port over from the weblink below to GCBASIC by Internet Lam (C) 2008.
    ' The port is inspired from http://www.microchipc.com/Hi-Tech_C_multitask/
    ' Refer to the weblink for details. Take note regarding interrupt
    ' jitter and attempt to avoid it with good design of task.
    '
    '---------------------------------------------------------------------
    ' Name         Date     Description of change
    '------------- -------- ----------------------------------------------
    ' New revision
    ' Internet Lam 05/28/08 Port over from C language to QCBASIC.
    ' Old revision
    '---------------------------------------------------------------------
    '--------------------- Configuration begins here ---------------------
    'General hardware configuration
    #chip 16F876, 20
    #config HS_OSC, WDT_OFF, LVP_OFF

    'LCD connection settings
    #define LCD_IO          4
    #define LCD_RS          PORTB.4
    #define LCD_NO_RW
    #define LCD_Enable      PORTB.5
    #define LCD_DB4         PORTB.0
    #define LCD_DB5         PORTB.1
    #define LCD_DB6         PORTB.2
    #define LCD_DB7         PORTB.3

    'Define ports
    #define LIFE_LED        PORTA.4

    'Set port directions
    DIR LIFE_LED            OUT

    'Set on/off for output port
    #define LIFE_LED_ON     SET LIFE_LED On
    #define LIFE_LED_OFF    SET LIFE_LED Off

    'Custom states
    #define LIFE_LED_STATE_OFF          0
    #define LIFE_LED_STATE_ON           1

    '--------------------------- Task configuration -----------------------
    'Task counters used to tell when a task is ready to be executed.
    'All these counters are incremented every time an interrupt happens.
    'Every task has its own counter that is updated every time an interrupt happens.
    'For instant, if the PIC Clock is 20MHz and instruction is taking 4 clock cycles,
    'then the effective frequency for each interrupt is 20MHz/4 = 5MHz. This value
    'however will vary with your prescaler value of the timer.
    task0_counter = 0
    task1_counter = 0
    task2_counter = 0

    'Task execution period and priority.
    'If we configure the prescaler of timer as 1:1, then the effective time would be
    '1 * prescaler/5MHz = 200us. In the example below, task0 will be executed each ~200us,
    'task1 will be executed each 20 * 200us ~ 4ms, task2 will be executed each 50 * 200us
    '~ 10ms.
    #define TASK0_COUNTER_MAX           1           'Highest frequency, highest priority task, such as PWM?
    #define TASK1_COUNTER_MAX           20
    #define TASK2_COUNTER_MAX           50          'Lowest frequency, lowest priority task, such as update LED?

    'Enable/Disable task
    task0_enabled = True
    task1_enabled = True
    task2_enabled = True

    'Task to run in background in main loop
    task0_go = False
    task1_go = False
    task2_go = False

    'Place your task init routines here

    'Initialize the timer with prescaler of 1:1. Avoid using Timer 0 as it might
    'interfere GCBASIC.
    InitTimer1 Osc, PS1_1/1
    StartTimer 1

    'Act when interrupt occurs
    On Interrupt Timer1Overflow Call Timer1ISR

    '----------------------------- Code begins here -----------------------
    'Global variables
    Life_LED_state = LIFE_LED_STATE_OFF

    '*************************** Main Loop **************************
    GoSub Toggle_life_LED
    Do
        If task1_go = True Then
            task1_go = False
            'Take time to do task at the leisure in the background

        End If

        If task1_go = True Then
            task1_go = False
            'Take time to do task at the leisure in the background

        End If

        If task2_go = True Then
            task2_go = False
            'Take time to do task at the leisure in the background

            'Toggle the LED
            'GoSub Toggle_life_LED
        End If
    Loop

    '************************* Subroutines *************************
    '*********************************
    '*  Interrupt service routines   *
    '*********************************
    'This subroutine serves the interrupt source from timer 1 upon timer expiration
    Sub Timer1ISR
        '***** Task 0 region *****
        If task0_counter >= TASK0_COUNTER_MAX Then
            'Reset the task counter
            task0_counter = 0

            If task0_enabled = True Then
                'Do high frequency important task 0

            End If
        End If
        task0_counter ++

        '***** Task 1 region *****
        If task1_counter >= TASK1_COUNTER_MAX Then
            'Reset the task counter
            task1_counter = 0

            If task1_enabled = True Then
                'Do medium frequency yet important task 1

                'Display the current task2_counter value in LCD
                GoSub Display_LCD
            End If
        End If
        task1_counter ++

        '***** Task 2 region *****
        If task2_counter >= TASK2_COUNTER_MAX Then
            'Reset the task counter
            task2_counter = 0

            If task2_enabled = True Then
                'Do low frequency least important task 2
                'Toggle the LED
                GoSub Toggle_life_LED
                task2_go = True
            End If
        End If
        task2_counter ++
    End Sub

    '*********************************
    '*        Utility routines       *
    '*********************************
    'This subroutine will output the LED based on LED state
    Sub Toggle_life_LED
        If Life_LED_state = LIFE_LED_STATE_ON Then
            LIFE_LED_ON
            Life_LED_state = LIFE_LED_STATE_OFF
        Else
            LIFE_LED_OFF
            Life_LED_state = LIFE_LED_STATE_ON
        End If
    End Sub

    'This subroutine will output counter value to LCD
    Sub Display_LCD
        CLS
        LCDInt(task2_counter)
    End Sub

     
    • Internet Lam

      Internet Lam - 2008-05-28

      Folks, I would like to make correction for the timing calculation around Line 61 - Line 64:
      'Task execution period and priority.
      'If we configure the prescaler of timer as 1:2, then the effective time would be
      'prescaler/5/10 = 0.04s. In the example below, task0 will be executed each ~0.04s,
      'task1 will be executed each 20 * 0.04s ~ 0.8s, task2 will be executed each 50 * 0.04s
      '~ 2s.

      Change to prescaler value 1:2 will make the calculation easier to understand.

      TIPS: You can create a spreadsheet to calculate the task counter value.

       
    • Santiago

      Santiago - 2009-02-13

      Very interesting and useful!!

      doing multitasking with a "base time" running on timer0 and interrupts is a very powerful tool... for example is possible reading ADC every 1 ms, blinking leds at different speeds, controling two motors and sending ADC data via UART (long string) at the "same time"... tought just sending data takes about 20 ms.

      i didn't use your code directly  but the idea of multitasking is the same.
      Here the very basic example: to leds blinking at diferent speeds:

      '_______________________________________________________________________
      '
      '
      '      Multitarea: Dos leds parpadeando a distinta velocidad
      '
      '_______________________________________________________________________

      '------------------------- CONFIGURAR MICRO -----------------------------
      '------------------------------------------------------------------------

      #chip 16F876, 4      'modelo de pic y velocidad de reloj

      #config HS_OSC, WDT_OFF, LVP_OFF, BODEN_OFF, PWRTE_ON

      '--------------------------- DEFINICIONES -------------------------------
      '------------------------------------------------------------------------

      #define LED1 PORTB.0
      #define LED2 PORTB.2

      '----------------------- CONFIGURAR VARIABLES ---------------------------
      '------------------------------------------------------------------------

      dim t_led1 as word          'tiempo de parpadeo led1
      dim c_led1 as word          'contador led1
      f_led1 = 0                  'flag led1

      dim t_led2 as word          'tiempo de parpadeo led2
      dim c_led2 as word          'contador led2
      f_led2 = 0                  'flag led2

      '------------------------- CONFIGURAR PUERTOS ---------------------------
      '------------------------------------------------------------------------

          TRISA = b'000001'
          TRISB = b'00000000'
          TRISC = b'10000000'

          PORTA = b'000000'
          PORTB = b'00000000'
          PORTC = b'00000000'

      '----------------------------- PRINCIPAL --------------------------------
      '------------------------------------------------------------------------

      OPTION_REG = b'10000001'      'Timer0 configurado para 1 ms con Fosc=4MHz (prescaler 1/4)

      bsf INTCON,T0IE                'Interrupciones Timer0 habilitadas

      t_led1 = 1000                  'Tiempo de tarea led1
      t_led2 = 300                  'Tiempo de tarea led2

      c_led1 = 0
      c_led2 = 0

      do

          if f_led1 = 1 then call tarea_led1

          if f_led2 = 1 then call tarea_led2

      loop

      '--------------------------- INTERRUPCIONES -----------------------------
      '------------------------------------------------------------------------

      Sub interrupt

          if INTCON.T0IF = 1 then        'si la interrupcion es de timer0

              TMR0 = 5                    'necesitamos una cuenta de 250: 5 a 255

              c_led1 += 1                'incrementar contador de tarea

              if c_led1 > t_led1 then    'si ha pasado el tiempo establecido
                  c_led1 = 0              'borrar contador
                  f_led1 = 1              'subir flag de tarea
              End if

              c_led2 += 1

              if c_led2 > t_led2 then
                  c_led2 = 0
                  f_led2 = 1
              End if

          End if

          INTCON.T0IF = 0
      End Sub

      '------------------------ SUBRUTINAS DE TAREAS --------------------------
      '------------------------------------------------------------------------
      Sub tarea_led1

          f_led1 = 0

          if LED1 = 1 then
              LED1 = 0
              exit Sub
          End if

          LED1 = 1

      End Sub

      Sub tarea_led2

          f_led2 = 0

          if LED2 = 1 then
              LED2 = 0
              exit Sub
          End if

          LED2 = 1

      End Sub

       
    • Nobody/Anonymous

      this is interesting. I will study code and give my additions to this condept.

      it is good idea to read freertos implemination capter 1 at http://www.freertos.org/implementation/index.html

       
    • Nobody/Anonymous

      If you are interested in multitasking, have a look to this: http://sourceforge.net/forum/forum.php?thread_id=3135262&forum_id=629990

       
    • Nobody/Anonymous

      I already saw this.
      I didnt have time to analise all detils, but for now I can say tahn it is bad to put all tasks in interrupt. My idea is following: IRQs must be short as possible. tasks should be handled in main loop. do not panic if You can't do all tasks at the same time. most important thing is to respond on cruitical events (port inputs timert ADC etc depending on your project). key sucees to construct multitasking in processor is to make good design and theory. all ather is just technical question. also sometimes it is OK to make all without rtos. Look on this interesting idea: http://www.embedded.com/2000/0009/0009feat4.htm

      sorry for my bad english, because i can't tell all things in english. :)

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.