本帖最后由 voidx 于 2009-11-7 11:47 编辑
尝试写个多任务内核voidtask,
与一般RTOS不同的是,voidtask任务空闲时,回到主函数运行while(1)循环,换句话说,主函数就是voidtask的空闲任务。这么做不用单独给空闲任务分配堆栈,对avr这种小RAM MCU来说,还是能节省点RAM。
移植平台avr+gcc,avr+iar,msp430+iar,stm32+iar
AVR+IAR下简单例子:
#include "config.h"
TTask TaskA; //任务A控制块
TTask TaskB; //任务B控制块
TTask TaskC; //任务C控制块
#define TaskAStackSize 100 //任务A堆栈大小
#define TaskBStackSize 100 //任务B堆栈大小
#define TaskCStackSize 100 //任务C堆栈大小
uint8 TaskAStack[TaskAStackSize]; //任务A堆栈空间
uint8 TaskBStack[TaskBStackSize]; //任务B堆栈空间
uint8 TaskCStack[TaskCStackSize]; //任务C堆栈空间
#define LED_A IO_BIT_ALIAS(&PORTB,0) //LED_A,IO口位域别名
#define LED_B IO_BIT_ALIAS(&PORTB,1) //LED_B,IO口位域别名
#define LED_C IO_BIT_ALIAS(&PORTB,2) //LED_C,IO口位域别名
ATTR_CTASK void TaskAProc(void) //任务A处理
{
volatile float f1=1.0; //测试浮点运算
sei(); //任务开始开中断,每个任务都有自己单独的总中断标志位,任务开始执行时,总中断标志位是关闭的
while(1)
{
f1+=0.1; //测试浮点运算
LED_A=1; //LED_A写1
TSK_Delay(VT_TICKS_PER_SEC/2); //延时1/2S
LED_A=0; //LED_A写0
TSK_Delay(VT_TICKS_PER_SEC-VT_TICKS_PER_SEC/2); //延时1/2S
}
}
ATTR_CTASK void TaskBProc(void)
{
volatile float f2=1.0; //测试浮点运算
sei(); //任务开始开中断,每个任务都有自己单独的总中断标志位
while(1)
{
f2+=0.1; //测试浮点运算
LED_B=1; //LED_B写1
TSK_Delay(VT_TICKS_PER_SEC/3); //延时1/3S
LED_B=0; //LED_B写0
TSK_Delay(VT_TICKS_PER_SEC-VT_TICKS_PER_SEC/3); //延时2/3S
}
}
ATTR_CTASK void TaskCProc(void)
{
volatile float f3=1.0; //测试浮点运算
sei(); //任务开始开中断,每个任务都有自己单独的总中断标志位
while(1)
{
f3+=0.1; //测试浮点运算
LED_C=1; //LED_C写1
TSK_Delay(VT_TICKS_PER_SEC/4); //延时1/4S
LED_C=0; //LED_C写0
TSK_Delay(VT_TICKS_PER_SEC-VT_TICKS_PER_SEC/4); //延时3/4S
}
}
int main()
{
cli(); //任务开始调度前,要关中断,每个任务都有自己单独的总中断标志位
DDRB |=_BV(0)|_BV(1)|_BV(2); //LED_A,LED_B,LED_C输出
PORTB |=_BV(0)|_BV(1)|_BV(2); //LED_A,LED_B,LED_C写1
_delay_ms(1000);
PORTB &=~(_BV(0)|_BV(1)|_BV(2)); //LED_A,LED_B,LED_C写0
VT_TicksInit(); //系统节拍初始化
#ifdef __AVR_IAR__
//AVR IAR使用双堆栈
TSK_Init(&TaskA,(TTaskProc *)TaskAProc,0,&TaskAStack[TaskAStackSize-33],&TaskAStack[TaskAStackSize-1]); //任务A初始化,优先级0
TSK_Init(&TaskB,(TTaskProc *)TaskBProc,1,&TaskBStack[TaskBStackSize-33],&TaskBStack[TaskBStackSize-1]); //任务B初始化,优先级1
TSK_Init(&TaskC,(TTaskProc *)TaskCProc,2,&TaskCStack[TaskCStackSize-33],&TaskCStack[TaskCStackSize-1]); //任务C初始化,优先级2
#else
//AVR GCC使用单堆栈
TSK_Init(&TaskA,(TTaskProc *)TaskAProc,0,&TaskAStack[TaskAStackSize-1]); //任务A初始化,优先级0
TSK_Init(&TaskB,(TTaskProc *)TaskBProc,1,&TaskBStack[TaskBStackSize-1]); //任务B初始化,优先级1
TSK_Init(&TaskC,(TTaskProc *)TaskCProc,2,&TaskCStack[TaskCStackSize-1]); //任务C初始化,优先级2
#endif
TSK_Start(); //任务开始调度(开始调度由空闲任务主函数切换到用户任务)
sei(); //空闲任务主函数开中断,空闲任务主函数也有自己单独的总中断标志位
while(1) //任务空闲时,运行这里
{
SleepIdle(); //空闲休眠
}
}
void VT_TicksInit(void)
{
TCNT2 = 0;
TCCR2=_BV(WGM21) | T2_CLK_DIV_128;
OCR2 = F_CPU/128/VT_TICKS_PER_SEC-1;
TIFR|=_BV(OCF2);
TIMSK=_BV(OCIE2);
}
ISR_ATTR_NAKED(TIMER2_COMP_vect) //系统节拍中断,裸中断
{
VT_IntEnter(); //VoidTask入中断
VT_TicksHandler(); //节拍处理
VT_IntExit(); //VoidTask出中断
} |