I think multitasking is a very powerfull thing, but when you have 6 or 7 task running, the GCBasic code is a mess of variables, counters, flags, interrupts... etc.
Then, for keep a simple GCBasic code i wrote a library for using multitasking in the easy way.
This library can manage upto 8 tasks, but can grow to any number you want.
The base-time is established to 10 ms to have a big gap-time to run long routines that can take a lot of clock-cicles. Anyway the base-time can also be changed.
There is a "multitasking.h" file that contain the functions, and some notes about how it works and how to modify it.
And a "multitask_example.gcb" : an example of use with some explanations; this example blinks 3 leds at different speeds, one blinks every 1s, other every 600 ms, and the third blinks in a period determined by the readed ADC value.
I think it should not be problem using hardware pwm, i tried it with multitasking, but not with this library.
For short tasks it should not be problem, for long tasks sometimes is better using several short tasks than one long task, or using one long task with sub-tasks inside activated by flags: in the first cicle run first sub-task and activate second sub-task flag, in next cicle run second sub-task and activate third sub-task flag...
The cuestion with multitasking is that sometimes it just doesn't work, or it work for some seconds (or even minutes) and then just stops... like a PC. This happend to me with many long tasks running at a time at very short time periods, then the pic just stalls; that's why i used a 10 ms base-time instead of 1 ms or less.
The good thing is when the time needed to run all tasks is less than 10 ms.
Sometimes it can be helpfull add an "offset" to tasks that have the same period; for example if you have several long tasks with a 100 ms period, you can avoid all the tasks to be executed is the same loop-cicle by setting an initial value to the task-counter, something like this:
This three tasks will run with the same period (100 ms), but at different moments.
What i do for testing purposes or even for definitive circuits is using a task as "life-led", that's a blinking led at a 500 ms toggle period, this way i know that multitasking is working and i can see that the running speed is as i expected (led on, every 1s).
Multitasking can be very complex... then the goal is using an RTOS.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I forgot to say that you can use the library as a pwm generator, but perhaps for this you need to use a smaller base-time...
If this is what you are talking about you need edit multitasking.h to have por example an 1 ms base-time; in the file there are some brief explanations about where are the lines to edit; if have some cuestion about this let me know...
Greetings.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There is a new version of this multitasking library.
Now is possible up to 16 tasks and 8 long-task (for long period tasks).
LTasks, for long period: upto one hour with 4 Mhz clock and 65535 us base time; but depending on the base time and the used clock.
Is also possible (needed indeed) to set the base time in your program so you can change it easily.
Is possible to set the period of tasks in us, ms, s, instead of number of cicles.
'Notes:
'
'¡¡¡¡¡ this library will use Timer0, don't use it in your program !!!!!.
'
'Actually a maximum of 16 Tasks and 8 LTasks are supported.
'
'The base time must be defined:
'
'#define base_time value
'where value is the desired value in us, for example:
'
'#define base_time 100 'for 100 us
'Maximum base_time value with 20 MHz clock is 13107.
'Maximum base_time value with 4 MHz clock is 65535.
'Maximum base_time value with other clocks: 65535/ChipMhz/4.
'
'
'The subroutine containing each task must be defined:
'
'#define Task1 Sub_name1
'#define Task2 Sub_name2
'#define LTask1 Sub_name3
'
'
'The period of each Task must be defined:
'
'#define Task1_us 500 'Task1 period is 500 us
'#define Task2_ms 10 'Task2 period is 10 ms
'#define LTask1_s 1 'LTask1 period is 1 s
'
'In the previous example, Sub_name1 will be executed every 500 us,
' Sub_name2 every 10 ms and Sub_name3 every 1 S.
'
'Maximum value for Task period in us is: base_time*255
'
'For example, with a 100 us base_time,
' maximum value for Tasks is: 100*255 = 25500 us => 25 ms
'
'LTask is for long period tasks,
' a period is long or not depending on the base_time
' When the needed period > base_time*255 then you need a LTask
'
'Maximun value for LTask period in us is: base_time*65535
'
'For example, with a 100 us base_time,
' maximum value for LTasks is: 100*65535 = 6553500 us => 6553 ms => 6 s
'
'
'Task will be executed with the command: Do_Taskx,
' for example in a main loop:
'
'do
' Do_Task2
' Do_LTask1
'loop
'
'or any other way... for example:
'
'do
' Do_Task2
' if PORTB.0 on then Do_LTask1
'loop
'
'
'Is possible to execute a Task inside Interrupt subroutine:
'
'#define Run_Task1 'Run Task inside interrupt subroutine
'
'_______________________________________________________________________
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
#define Task1 read_input
#define Task1_us 500 'Task period in ms
#define LTask1 led1 'Task subroutine
#define LTask1_s 1 'task will run every 1 s
#define Run_LTask1 'Run Task inside interrupt subroutine
#define Task2 led2
#define Task2_ms 100 'task will run every 100 ms
#define Task3 led3 'we will have the time from ReadAD
'--------------------- MAIN -----------------------
'------------------------------------------------
Dir PORTA.0 in
Dir PORTB out
do
Do_Task1
Do_Task3
Do_Task2
loop
'------------------- TASK's SUBs ---------------------
'------------------------------------------------
Sub read_input
time_Task3 = ReadAD(AN0) 'set led3 period to the AD value
End Sub
Sub led1
PORTB = PORTB xor 1 'toggle led on bit 0
End Sub
Sub led2
PORTB = PORTB xor 2 'toggle led on bit 1
End Sub
Sub led3
PORTB = PORTB xor 4 'toggle led on bit 2
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The previous example blinks 3 leds at diferent speeds: led1 at 1 Seg, led2 at 100 ms and led3 at a variable speed depending on ADC readed value.
The good thing is that you can now add new tasks and the blinking leds will not be afected. They looks to work "simultaneously".
This is another example that use multitasking to generate pwm signals.
It blinks one led (lifeled) at 500 ms rate at RA0, and drive 8 leds using software pwm signals.
This is a simple example, but i did a larger version controlling 64 leds directly (not a matrix) using shift registers.
'----------------- CONFIGURE MICRO -------------------
'------------------------------------------------
#chip 16F627, 4 'modelo de pic y velocidad de reloj
#config HS_OSC, WDT_OFF, LVP_OFF, PWRTE_ON
#define Task7 pwm_period 'pwm period for all leds
#define Run_Task7 'Run Task inside interrupt subroutine
#define Task7_us niveles*base_time 'pwm period = resolution * base time
#define LTask1 life_led 'LTask is for long period tasks
#define LTask1_ms 500 'use LTask when period > base_time*255
'--------------------- MAIN -----------------------
'------------------------------------------------
TRISA = 0
TRISB = 0
for contador = 0 to total_regs
FSR = registro + contador 'Store initial values
INDF = (contador*contador)/3
puerto = puerto xor 255 'Blink leds
wait 200 ms
Next
wait 500 ms
do 'Main Loop
Do_Task1
Do_Task2
Do_LTask1
loop
'------------------- TASK's SUBs ---------------------
'------------------------------------------------
Sub rota_leds
for contador = 0 to total_regs
FSR = registro + contador
prev = INDF
INDF = regprev
regprev = prev
Next
End Sub
Sub calc_output
lectura = 0
FSR = registro
if INDF > cont_Task7 then lectura.0 = 1
FSR += 1
if INDF > cont_Task7 then lectura.1 = 1
FSR += 1
if INDF > cont_Task7 then lectura.2 = 1
FSR += 1
if INDF > cont_Task7 then lectura.3 = 1
FSR += 1
if INDF > cont_Task7 then lectura.4 = 1
FSR += 1
if INDF > cont_Task7 then lectura.5 = 1
FSR += 1
if INDF > cont_Task7 then lectura.6 = 1
FSR += 1
if INDF > cont_Task7 then lectura.7 = 1
PORTB = lectura
End Sub
Sub pwm_period 'this task is just needed to have the cont_Task7 counter
nop
End Sub
Sub life_led
PORTA = PORTA xor 1 'Blink led at RA0
End Sub
I compiled an example PWMLEDS. Used assembly file with MPLAB and got:
Error C:\PROGRAM FILES\GCBASIC\EXAMPLES\PWMLEDS\PWMLEDS.ASM 417 : Symbol not previously defined (SYSCOMPLESSOREQUAL16)
Commented out "call SYSCOMPLESSOREQUAL16", programmed PIC, works fine. Where this statement is coming from?
Otherwise great job, very useful multitasking library, thanks.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I started to work with multasking afther reading viper7882 thread:
https://sourceforge.net/forum/forum.php?thread_id=2055691&forum_id=629990
I think multitasking is a very powerfull thing, but when you have 6 or 7 task running, the GCBasic code is a mess of variables, counters, flags, interrupts... etc.
Then, for keep a simple GCBasic code i wrote a library for using multitasking in the easy way.
This library can manage upto 8 tasks, but can grow to any number you want.
The base-time is established to 10 ms to have a big gap-time to run long routines that can take a lot of clock-cicles. Anyway the base-time can also be changed.
There is a "multitasking.h" file that contain the functions, and some notes about how it works and how to modify it.
And a "multitask_example.gcb" : an example of use with some explanations; this example blinks 3 leds at different speeds, one blinks every 1s, other every 600 ms, and the third blinks in a period determined by the readed ADC value.
You can download files here:
https://sourceforge.net/project/showfiles.php?group_id=247157
Any feedback will be apreeciated.
Greetings.
Hello,
I have downloaded multitasking library and it works perfectly.
I am developing RGB LED controller using PWM with this library.
Is it possible to use PWM with this library ?
Pls. reply.
Thank you very much for contribution with GCbasic.
Regards,
Deepak Chatwani
Hi Deepak. Thanks for the feedback.
I think it should not be problem using hardware pwm, i tried it with multitasking, but not with this library.
For short tasks it should not be problem, for long tasks sometimes is better using several short tasks than one long task, or using one long task with sub-tasks inside activated by flags: in the first cicle run first sub-task and activate second sub-task flag, in next cicle run second sub-task and activate third sub-task flag...
The cuestion with multitasking is that sometimes it just doesn't work, or it work for some seconds (or even minutes) and then just stops... like a PC. This happend to me with many long tasks running at a time at very short time periods, then the pic just stalls; that's why i used a 10 ms base-time instead of 1 ms or less.
The good thing is when the time needed to run all tasks is less than 10 ms.
Sometimes it can be helpfull add an "offset" to tasks that have the same period; for example if you have several long tasks with a 100 ms period, you can avoid all the tasks to be executed is the same loop-cicle by setting an initial value to the task-counter, something like this:
'------------------------ TASK's DEFINITIONS ----------------------------
'------------------------------------------------------------------------
#include <multitasking.h>
#define Task1 led1 'Task subroutine
time_Task1 = 10 'x10 ms = task will run every 100 ms
cont_Task1 = 6 '60 ms offset
#define Task2 led2
time_Task2 = 10
cont_task2 = 3
#define Task3 led3
time_Task2 = 10
__________________________________________________________
This three tasks will run with the same period (100 ms), but at different moments.
What i do for testing purposes or even for definitive circuits is using a task as "life-led", that's a blinking led at a 500 ms toggle period, this way i know that multitasking is working and i can see that the running speed is as i expected (led on, every 1s).
Multitasking can be very complex... then the goal is using an RTOS.
I forgot to say that you can use the library as a pwm generator, but perhaps for this you need to use a smaller base-time...
If this is what you are talking about you need edit multitasking.h to have por example an 1 ms base-time; in the file there are some brief explanations about where are the lines to edit; if have some cuestion about this let me know...
Greetings.
There is a new version of this multitasking library.
Now is possible up to 16 tasks and 8 long-task (for long period tasks).
LTasks, for long period: upto one hour with 4 Mhz clock and 65535 us base time; but depending on the base time and the used clock.
Is also possible (needed indeed) to set the base time in your program so you can change it easily.
Is possible to set the period of tasks in us, ms, s, instead of number of cicles.
There is an example too.
Download here:
https://sourceforge.net/project/showfiles.php?group_id=247157
These are the explanations included in the file:
'_______________________________________________________________________
'
'
'Notes:
'
'¡¡¡¡¡ this library will use Timer0, don't use it in your program !!!!!.
'
'Actually a maximum of 16 Tasks and 8 LTasks are supported.
'
'The base time must be defined:
'
'#define base_time value
'where value is the desired value in us, for example:
'
'#define base_time 100 'for 100 us
'Maximum base_time value with 20 MHz clock is 13107.
'Maximum base_time value with 4 MHz clock is 65535.
'Maximum base_time value with other clocks: 65535/ChipMhz/4.
'
'
'The subroutine containing each task must be defined:
'
'#define Task1 Sub_name1
'#define Task2 Sub_name2
'#define LTask1 Sub_name3
'
'
'The period of each Task must be defined:
'
'#define Task1_us 500 'Task1 period is 500 us
'#define Task2_ms 10 'Task2 period is 10 ms
'#define LTask1_s 1 'LTask1 period is 1 s
'
'In the previous example, Sub_name1 will be executed every 500 us,
' Sub_name2 every 10 ms and Sub_name3 every 1 S.
'
'Maximum value for Task period in us is: base_time*255
'
'For example, with a 100 us base_time,
' maximum value for Tasks is: 100*255 = 25500 us => 25 ms
'
'LTask is for long period tasks,
' a period is long or not depending on the base_time
' When the needed period > base_time*255 then you need a LTask
'
'Maximun value for LTask period in us is: base_time*65535
'
'For example, with a 100 us base_time,
' maximum value for LTasks is: 100*65535 = 6553500 us => 6553 ms => 6 s
'
'
'Task will be executed with the command: Do_Taskx,
' for example in a main loop:
'
'do
' Do_Task2
' Do_LTask1
'loop
'
'or any other way... for example:
'
'do
' Do_Task2
' if PORTB.0 on then Do_LTask1
'loop
'
'
'Is possible to execute a Task inside Interrupt subroutine:
'
'#define Run_Task1 'Run Task inside interrupt subroutine
'
'_______________________________________________________________________
This is interesting and seems better than Internet Lam – viper7882 code, because it is possible to run tasks outside interrupt. Keep going!
I will try to contribute some ideas, asm and BASIC code for this project as soon as I have some time for this.
where is that library? can't find it. :-(
Sorry… i was updating all files. You can find it here:
https://sourceforge.net/projects/piclinux/files/GcBasic-PL/multitasking.h/download
Example program:
'----------------- CONFIGURE MICRO -------------------
'------------------------------------------------
#chip 16F876A, 4
#config HS_OSC, WDT_OFF, LVP_OFF, PWRTE_ON
'---------------- TASK's DEFINITIONS -------------------
'------------------------------------------------
#include <multitasking.h>
#define base_time 500 'base_time in us
#define Task1 read_input
#define Task1_us 500 'Task period in ms
#define LTask1 led1 'Task subroutine
#define LTask1_s 1 'task will run every 1 s
#define Run_LTask1 'Run Task inside interrupt subroutine
#define Task2 led2
#define Task2_ms 100 'task will run every 100 ms
#define Task3 led3 'we will have the time from ReadAD
'--------------------- MAIN -----------------------
'------------------------------------------------
Dir PORTA.0 in
Dir PORTB out
do
Do_Task1
Do_Task3
Do_Task2
loop
'------------------- TASK's SUBs ---------------------
'------------------------------------------------
Sub read_input
time_Task3 = ReadAD(AN0) 'set led3 period to the AD value
End Sub
Sub led1
PORTB = PORTB xor 1 'toggle led on bit 0
End Sub
Sub led2
PORTB = PORTB xor 2 'toggle led on bit 1
End Sub
Sub led3
PORTB = PORTB xor 4 'toggle led on bit 2
End Sub
The previous example blinks 3 leds at diferent speeds: led1 at 1 Seg, led2 at 100 ms and led3 at a variable speed depending on ADC readed value.
The good thing is that you can now add new tasks and the blinking leds will not be afected. They looks to work "simultaneously".
This is another example that use multitasking to generate pwm signals.
It blinks one led (lifeled) at 500 ms rate at RA0, and drive 8 leds using software pwm signals.
This is a simple example, but i did a larger version controlling 64 leds directly (not a matrix) using shift registers.
'----------------- CONFIGURE MICRO -------------------
'------------------------------------------------
#chip 16F627, 4 'modelo de pic y velocidad de reloj
#config HS_OSC, WDT_OFF, LVP_OFF, PWRTE_ON
'---------------- TASK's DEFINITIONS -------------------
'------------------------------------------------
#include <multitasking.h>
#define niveles 20 'light (pwm) levels
#define base_time 1000 'base_time in us
#define Task1 rota_leds
#define Task1_us 255*base_time 'Task period in us
#define Task2 calc_output
#define Task2_us base_time
#define Task7 pwm_period 'pwm period for all leds
#define Run_Task7 'Run Task inside interrupt subroutine
#define Task7_us niveles*base_time 'pwm period = resolution * base time
#define LTask1 life_led 'LTask is for long period tasks
#define LTask1_ms 500 'use LTask when period > base_time*255
'------------------- REGs DEFs ---------------------
'------------------------------------------------
#define total_regs 7
#define registro 77 - total_regs
'--------------------- MAIN -----------------------
'------------------------------------------------
TRISA = 0
TRISB = 0
for contador = 0 to total_regs
FSR = registro + contador 'Store initial values
INDF = (contador*contador)/3
puerto = puerto xor 255 'Blink leds
wait 200 ms
Next
wait 500 ms
do 'Main Loop
Do_Task1
Do_Task2
Do_LTask1
loop
'------------------- TASK's SUBs ---------------------
'------------------------------------------------
Sub rota_leds
for contador = 0 to total_regs
FSR = registro + contador
prev = INDF
INDF = regprev
regprev = prev
Next
End Sub
Sub calc_output
lectura = 0
FSR = registro
if INDF > cont_Task7 then lectura.0 = 1
FSR += 1
if INDF > cont_Task7 then lectura.1 = 1
FSR += 1
if INDF > cont_Task7 then lectura.2 = 1
FSR += 1
if INDF > cont_Task7 then lectura.3 = 1
FSR += 1
if INDF > cont_Task7 then lectura.4 = 1
FSR += 1
if INDF > cont_Task7 then lectura.5 = 1
FSR += 1
if INDF > cont_Task7 then lectura.6 = 1
FSR += 1
if INDF > cont_Task7 then lectura.7 = 1
PORTB = lectura
End Sub
Sub pwm_period 'this task is just needed to have the cont_Task7 counter
nop
End Sub
Sub life_led
PORTA = PORTA xor 1 'Blink led at RA0
End Sub
Here you can see the effect in a video:
: http://piclinux.sourceforge.net/files/videos/rot-led.ogg "Ktechlab-gcb simulation"
I compiled an example PWMLEDS. Used assembly file with MPLAB and got:
Error C:\PROGRAM FILES\GCBASIC\EXAMPLES\PWMLEDS\PWMLEDS.ASM 417 : Symbol not previously defined (SYSCOMPLESSOREQUAL16)
Commented out "call SYSCOMPLESSOREQUAL16", programmed PIC, works fine. Where this statement is coming from?
Otherwise great job, very useful multitasking library, thanks.