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
'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?
'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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
'
'_______________________________________________________________________
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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. :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
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.
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
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
If you are interested in multitasking, have a look to this: http://sourceforge.net/forum/forum.php?thread_id=3135262&forum_id=629990
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. :)