|
I leave extensive testing to you. Have a look at the example
with the three tasks on the second page (table). Time to see it happening.
We will use our common debugging technic, we will send bytes to the serial
port. Have the full code!
/// Includes //////////
#include <avr/io.h>
#include <avr/interrupt.h>
/// Data Types /////////
typedef unsigned char u8;
typedef unsigned int u16;
typedef struct task
{
// pointer to a function
void (*pfunc) (void);
// delay before the first call
u16 delay;
// interval between subsequent runs
u16 period;
// flag indicating time to run
u8 run;
}task;
/// Defines ///////////
// 25msec period 256-180
// 7.3728MHz and /1024 prescaler
#define StartFrom 76
// maximum number of tasks
#define MAXnTASKS 20
/// Globals ///////////
volatile task TaskArray[MAXnTASKS];
/// Prototypes ////////
void InitUART (u16 baud);
void TransmitByte (u8 data);
void InitScheduler (void);
void UpdateScheduler(void);
void DeleteTask (u8 index);
void AddTask (void (*taskfunc)(void), u16 taskdelay, u16 taskperiod);
void DispatchTask (void);
void TestA (void);
void TestB (void);
void TestC (void);
/// Main //////////////
int main(void)
{
InitUART (23);
InitScheduler();
// populate task array
AddTask (TestA, 0, 3);
AddTask (TestB, 1, 4);
AddTask (TestC, 4, 0);
// enable interrupts
sei();
while (1)
{
DispatchTask();
}
}
void InitUART (u16 baud)
{
UBRRH = (u8)(baud>>8);
UBRRL = (u8)baud;
UCSRB = (1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}
void TransmitByte (u8 data)
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}
void InitScheduler (void)
{
u8 i;
// timer prescaler clock/1024
TCCR0 |= (1<<CS02)|(1<<CS00);
// clear pending interrupts
TIFR = 1<<TOV0;
// enable timer0 overflow interrupt
TIMSK |= 1<<TOIE0;
// load timer0
TCNT0 = StartFrom;
// clear task array
for (i=0; i<MAXnTASKS; i++) DeleteTask(i);
}
void DeleteTask (u8 j)
{
TaskArray[j].pfunc = 0x0000;
TaskArray[j].delay = 0;
TaskArray[j].period = 0;
TaskArray[j].run = 0;
}
void AddTask (void (*taskfunc)(void), u16 taskdelay, u16 taskperiod)
{
u8 n=0;
// find next available position
while ((TaskArray[n].pfunc != 0) && (n < MAXnTASKS)) n++;
// place task
if (n < MAXnTASKS)
{
TaskArray[n].pfunc = taskfunc;
TaskArray[n].delay = taskdelay;
TaskArray[n].period = taskperiod;
TaskArray[n].run = 0;
}
}
SIGNAL(SIG_OVERFLOW0)
{
u8 m;
// testing
TransmitByte(45); // (-)
// load timer
TCNT0 = StartFrom;
for (m=0; m<MAXnTASKS; m++)
{
if (TaskArray[m].pfunc)
{
if (TaskArray[m].delay == 0)
{
TaskArray[m].run = 1;
TaskArray[m].delay = TaskArray[m].period;
}
else TaskArray[m].delay--;
}
}
}
void DispatchTask (void)
{
u8 k;
for (k=0; k<MAXnTASKS; k++)
{
if (TaskArray[k].run == 1)
{
// run task
(*TaskArray[k].pfunc)();
// clear run flag
TaskArray[k].run = 0;
}
}
}
void TestA (void)
{
TransmitByte(49); //(1)
}
void TestB (void)
{
TransmitByte(50); //(2)
}
void TestC (void)
{
TransmitByte(51); //(3)
}
Connect your favorite terminal program and get the following
sequence ... -1 -2 - - -13 -3 -23 -3 -13 -3 -3 -23 -13 -3 -3 -3 -123 -3 -3 -3 -13 -23 -3 -3 -13 -3 -23 -3 -13 -3 -3 -23 -13 -3 -3 -3 -123 ... it works!
Final word, you cannot use interrupts with this scheme.
The only interrupt that should exist is the timer overflow interrupt.
If you do activate other interrupts, your code will be doomed!
Thanks to [davef] for his interest and corrections!
|