|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2007-1-4 15:22:35
|
显示全部楼层
2. AVRX系统的应用
2.1 任务(task) Avrx的编程是对任务(task)进行编程。任务的属性个人可分为:同步,互斥,独立,关联。一个完整的AvrX程序由
AVRX_SIGINT(SIG_OVERFLOW0)
{
IntProlog(); // Switch to kernel stack/context
TCNT0 = TCNT0_INIT;
// outp(TCNT0_INIT, TCNT0);
AvrXTimerHandler(); // Call Time queue manager
Epilog(); // Return to tasks
}
int main(void) // Main runs under the AvrX Stack
{
AvrXSetKernelStack(0);
MCUCR = 1<<SE;
TCNT0 = TCNT0_INIT;
TCCR0 = TMC8_CK256;
TIMSK = 1<<TOIE0;
LEDDDR = 0xFF;
LED = 0xFF;
PORTC=0xff;
DDRC=0xf0;
PINC=0xFF;
AvrXRunTask(TCB(task1));
AvrXRunTask(TCB(task2));
AvrXRunTask(TCB(Monitor));
InitSerialIO(UBRR_INIT); // Initialize USART baud rate generator
Epilog(); // Switch from AvrX Stack to first task
while(1);
}
和至少两个以上的任务(task)组成。
任务类似于子程序又不同于子程序,在一个任务中可完成一项工作或多项工作。任务是采用线性方式编程,既不要编写子程序再在任务中
调用,而是在任务中直接编写你需要的程序,做什么-等什么-做什么。
AvrX是实时多任务操作系统,可把每个任务看着是一个完整的“CPU”。因此用它可降低编程难度,提高编程效率。
另外,可在任务(task)中操作其他任务(task)。
2.2 变量 任务中的常驻变量在任务中的While(1)之前声明且初始化,临时变量在任务中的While(1)之后声明且初始化。任务与任务间,任务与
中断服务程序间的共用变量在int main()之前用volatile声明且初始化。与AvrX内核事务有关的变量和宏如:
AVRX_GCC_TASK(task1, 20, 2);//任务的声明(Declare)见jiaotong.c
/*宏:
AVRX_GCC_TASKDEF(start,c_stack,priority)
AVRX_GCC_TASK(start,c_stack,priority)
AVRX_SIGNT(vector)
*/
TimerControlBlock mytimer;
TimerMessageBlock Timer;
MUTEX mySemaphore;
MessageControlBlock myMessage;
MessageQueue MyQueue;
等在int main()之前声明。不要再另外声明所谓的位变量和判断用的变量,将与AvrX内核有关的一切事务交给AvrX内核去做(任务的操作,定
时器(Timer),信号(Semaphore)和消息(Message) )。这是要点。
2.3 信号(Semaphore)和消息(Message) 信号(Semaphore)类似FLAGE,用MUTEX修饰,用于两个互斥任务或单条件分支。它们有三种状态:
SEM_PEND(0) //清零等待信号
SEM_DONE(1) //信号触发
SEM_WAIT(2) //除以上以外的状态
API函数如下:
AvrXSetSemaphore \
置 互为反逻辑
AvrXIntsetSemapore/
AvrXWaitSemaplaore //类似while(...)死等,阻塞函数
AvrXTestSemapIlorc //测试(SEM_WAIT,SEM_PEND,SEM_DONE三态之一)
AvrXIntTestSemaphore //(=AvrXTestSemapIlorc+AvrXIntsetSemapore)
AvrxResetSemaphore //迫使=SEM_PEND
消息(Message)是信号(Semaphore)的扩展,消息可以认为是灵活性更大的信号量。API函数如下:
AvrXSendMessage \
发送 互为反逻辑
AvrXIntSendMessage/
AvrXRecvMessage//接收
AvrXWaitMessage//类似while(...)死等,阻塞函数。
AvrXAckMessage//发送握手
AvrXTestMessage//测试(SEM_WAIT,SEM_PEND,SEM_DONE三态之一)
AvrXWaitMessageAck//等握手 类似while(...)死等,阻塞函数。
有如下用法:
发送端AvrXSendMessage//发送消息
AvrXWaitMessageAck//等握手
接收端AvrXWaitMessage//等消息
AvrXAckMessage//发送握手
另外可见列程Timer3.c
2.4 中断 在实时系统中,实时系统的实时性表现在系统对外部事件的响应能力上。系统通过中断来响应外部事件的发生,并且在用户中断程序
中做的事要尽量少,把大部分工作留给任务去做,只是通过信号量或者消息机制来通知任务运行。
jiaotong.c
/*这是个交通灯的程序,有两个互斥的任务*/
#include <C:\avrx\avrx-io.h>
#include <C:\avrx\avrx-signal.h>
#include "C:\avrx\serialio.h"
#include "C:\avrx\avrx.h"
#include "hardware.h"
TimerControlBlock timer1; // Declare the control blocks needed for timers
AVRX_GCC_TASK(task1, 20, 2); // Declare the Task
AVRX_GCC_TASK(task2, 20, 2);
AVRX_MUTEX(TimerSemaphore1);
int main(void)
{
AvrXSetKernelStack(0);
MCUCR = _BV(SE); // Initialize Timer Hardware
TCNT0 = TCNT0_INIT;
TCCR0 = TMC8_CK256;
TIMSK = _BV(TOIE0); // Enable Timer overflow interrupt
// outp((1<<SE) , MCUCR);
// outp(TCNT0_INIT, TCNT0);
// outp(TMC8_CK256 , TCCR0);
// outp((1<<TOIE0), TIMSK);
DDRB = 0xFF;
PORTB = 0xFF;
AvrXRunTask(&task1Tcb);
AvrXRunTask(&task2Tcb);
AvrXSetSemaphore(&TimerSemaphore1);
PORTB &=~ (_BV(PORTB0)|_BV(PORTB3));
InitSerialIO(UBRR_INIT); // Initialize USART baud rate generator
Epilog(); // Switch from AvrX Stack to first task
while(1);
}
AVRX_SIGINT(SIG_OVERFLOW0)
{
IntProlog();
TCNT0 = TCNT0_INIT;
// outp(TCNT0_INIT, TCNT0);
AvrXTimerHandler();
Epilog();
}
NAKEDFUNC(task1)
{
uint8_t i;
while(1)
{
AvrXWaitSemaphore(&TimerSemaphore1);//类似While(...)
PORTB &=~ _BV(PORTB0); //
PORTB |= _BV(PORTB1);
AvrXStartTimer(&timer1, 800); // 800 ms delay非阻塞函数
AvrXWaitTimer(&timer1); //阻塞函数
PORTB &=~ (_BV(PORTB0)|_BV(PORTB1));//
for(i=0;i<3;i++)
{ AvrXStartTimer(&timer1, 200);//非阻塞函数
AvrXWaitTimer(&timer1);//阻塞函数
PORTB |= _BV(PORTB0)|_BV(PORTB1);
AvrXStartTimer(&timer1, 200); // 200 ms delay非阻塞函数
AvrXWaitTimer(&timer1);//阻塞函数
PORTB &=~ (_BV(PORTB0)|_BV(PORTB1));
}
PORTB &=~ _BV(PORTB1);//
PORTB |= _BV(PORTB0);
// outp(inp(PORTB) ^ 1, PORTB); // Toggle bits
AvrXSetSemaphore(&TimerSemaphore1);
}
}
NAKEDFUNC(task2)
{uint8_t i;
while(1)
{
AvrXWaitSemaphore(&TimerSemaphore1);
PORTB &=~ _BV(PORTB2);
PORTB |= _BV(PORTB3);
AvrXDelay(&timer1, 800); // 800 ms delay 阻塞函数
/*AvrXDelay(&timer1, 800)=AvrXStartTimer(&timer1, 800)+ AvrXWaitTimer(&timer1);*/
PORTB &=~ (_BV(PORTB2)|_BV(PORTB3));
for(i=0;i<3;i++)
{AvrXDelay(&timer1, 200); // 200 ms delay阻塞函数
PORTB |= _BV(PORTB2)|_BV(PORTB3);
// outp(inp(PORTB) ^ 2, PORTB); // Toggle bits
AvrXDelay(&timer1, 200);//阻塞函数
PORTB &=~ (_BV(PORTB2)|_BV(PORTB3));
}
PORTB &=~ _BV(PORTB3);
PORTB |= _BV(PORTB2);
AvrXSetSemaphore(&TimerSemaphore1);
}
}
Timers1.c
/*这是运动记时器,俗称“跑表”,记时范围0~99.99秒,用LED数码管显示。用M16的定时器1的CTC方式定时,256分频,10ms单位。PC0为启
动/停止钮,PC1为复位钮。Timers1.c和Timer3.c完成相同功能,Timer3.c更符合AvrX的风格*/
#include <c:\avrx\avrx-io.h>
#include <c:\avrx\avrx-signal.h>
#include "c:\avrx\avrx.h"
#include "c:\avrx\serialio.h" // From AvrX...
#include <avr/pgmspace.h>
#include <stdint.h>
#include "hardware.h"
prog_uint8_t LEDD[27]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F,
0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x7c,0x73,0x67,0x50,0x78,
0x3e,0x00,0x40,0x54};//共阳
/*unsigned char LEDD[27] =
{ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0xc7,0x83,0x8c,
0x98,0xaf,0x87,0xc1,0xff,0xbf,0xab};
//{0123456789
// AbcdEFHLoP
// QrtU -n} LED段码表*/ //共阴
//AVRX_IAR_TASK(Monitor, 0, 20, 0); // External Task: Debug Monitor
///AVRX_GCC_TASK(Monitor, 20, 0); // External Task: Debug Monitor
volatile uint16_t Myclock;
volatile uint8_t disp[4]={0x3f,0x3f,0x3f,0x3f};
TimerControlBlock timer1;//, // Declare the control blocks needed for timers
AVRX_MUTEX(TimerSemaphore);
AVRX_SIGINT(SIG_OVERFLOW0)
{
IntProlog(); // Switch to kernel stack/context
TCNT0 = TCNT0_INIT;
// outp(TCNT0_INIT, TCNT0);
AvrXTimerHandler(); // Call Time queue manager
Epilog(); // Return to tasks
}
SIGNAL(SIG_OUTPUT_COMPARE1A)
{ sei();
if((Myclock+=1)>=10000)Myclock=0;
AvrXSetSemaphore(&TimerSemaphore);
}
//AVRX_IAR_TASKDEF(task1, 0, 6, 3)
AVRX_GCC_TASKDEF(task1, 12, 3)
{ uint8_t Key[3];
//TCCR1B|=(_BV(WGM12)|_BV(CS12));//控制寄存器B,CTC模式256分频
while (1)
{uint8_t i;
Key[0]=PINC&03;
if(Key[0]!=Key[1])
{ i=Key[0];
if((~i&03)==3||(~i&03)==2)
{TCCR1B&=~(_BV(WGM12)|_BV(CS12));
Myclock=0;
disp[0]=disp[1]=disp[2]=disp[3]=0x3f;
TIMSK&=~_BV(OCIE1A);
TCNT1=0;
Myclock=0;
}
else if((~i&03)==1)
{ if((Key[2]^=~i&Key[1])==1)
{TCCR1B|=(_BV(WGM12)|_BV(CS12));
TIMSK|=_BV(OCIE1A);
}
else {TCCR1B&=~(_BV(WGM12)|_BV(CS12));
TIMSK&=~_BV(OCIE1A);
}
}
Key[1]=Key[0];
}
}
}
//AVRX_IAR_TASKDEF(task2, 0, 6, 2)
AVRX_GCC_TASKDEF(task2, 12, 1)
{uint8_t Tcount=0;
while (1)
{
uint8_t i;
AvrXDelay(&timer1, 4);
PORTC=0xff;
PINC|=0xF0;
if((Tcount+=1)==4)
Tcount=0;
switch(Tcount&0x3)
{case 0x0:PORTC&=0xef;break;
case 0x1:PORTC&=0xdf;break;
case 0x2:PORTC&=0xbf;break;
case 0x3:PORTC&=0x7f;break;
}
if(((Tcount&0x3)==0)&&(disp[Tcount]==0x3f))
LED=0xff;
// else LED = disp[Tcount];
else if((Tcount&0x3)==1)
LED = disp[Tcount]|0x80;//LED ^ 0x02;
else LED = disp[Tcount];
// outp((inp(LED) ^ 0x02), LED);
if(AvrXIntTestSemaphore(&TimerSemaphore)==SEM_DONE)//测试相等清除
{ uint16_t div=1000,t;
uint8_t dd=0;
t=Myclock;
for(i=0;i<4;i++)
{
while(t>=div){dd+=1;t-=div;};
disp=pgm_read_byte(&LEDD[dd]);div/=10;dd=0;}
}
}
}
int main(void) // Main runs under the AvrX Stack
{
AvrXSetKernelStack(0);
MCUCR = 1<<SE;
TCNT0 = TCNT0_INIT;
TCCR0 = TMC8_CK256;
TIMSK = 1<<TOIE0;
LEDDDR = 0xFF;
LED = 0xFF;
PORTC=0xff;
DDRC=0xf0;
PINC=0xFF;
OCR1A=F_CPU*10/256/1000;//10ms
TCNT1=0;
AvrXRunTask(TCB(task1));
AvrXRunTask(TCB(task2));
/// AvrXRunTask(TCB(Monitor));
InitSerialIO(UBRR_INIT); // Initialize USART baud rate generator
Epilog(); // Switch from AvrX Stack to first task
while(1);
}
Timer3.c
#include <c:\avrx\avrx-io.h>
#include <c:\avrx\avrx-signal.h>
#include "c:\avrx\avrx.h"
#include "c:\avrx\serialio.h" // From AvrX...
#include <avr/pgmspace.h>
#include "hardware.h"
prog_uint8_t LEDD[27]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F,
0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x7c,0x73,0x67,0x50,0x78,
0x3e,0x00,0x40,0x54};//共阳
/*unsigned char LEDD[27] =
{ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0xc7,0x83,0x8c,
0x98,0xaf,0x87,0xc1,0xff,0xbf,0xab};
//{0123456789
// AbcdEFHLoP
// QrtU -n} LED段码表*/ //共阴
//AVRX_IAR_TASK(Monitor, 0, 20, 0); // External Task: Debug Monitor
///AVRX_GCC_TASK(Monitor, 20, 0); // External Task: Debug Monitor
volatile uint16_t Myclock;
volatile uint8_t disp[4]={0x3f,0x3f,0x3f,0x3f};
TimerControlBlock timer1; // 声明定时器控制块
typedef struct//声明一个带内部变量的消息结构体MyMessage。
{
MessageControlBlock mcb;
uint8_t SwitchUp,switches; //变量在对应的任务中赋值
}
MyMessage;
MessageQueue MyQueue; // 消息队列
AVRX_SIGINT(SIG_OVERFLOW0)//用定时器0以1ms的中断速率来实现循环打鸣调度。
{
IntProlog(); //为实现任务间的无缝切换并与GCC编译器兼容,每个任务必须有35个字节以上的SRAM。
TCNT0 = TCNT0_INIT;
AvrXTimerHandler();
Epilog();
}
SIGNAL(SIG_OUTPUT_COMPARE1A)
{ static MyMessage SW;//声明新变量
sei();
if((Myclock+=1)>=10000)Myclock=0;
SW.SwitchUp=1;
AvrXSendMessage(&MyQueue, &SW.mcb);//
}
AVRX_GCC_TASKDEF(task1, 40, 3)
{ uint8_t Key=0;
//TCCR1B|=(_BV(WGM12)|_BV(CS12));//控制寄存器B,CTC模式256分频
MessageControlBlock *p;
while (1)
{
uint8_t i;
p = AvrXRecvMessage(&MyQueue);//AvrXWaitMessage
if((((MyMessage*)p)->switches==3)||(((MyMessage*)p)->switches==2))
{TCCR1B&=~(_BV(WGM12)|_BV(CS12));
Myclock=0;
disp[0]=disp[1]=disp[2]=disp[3]=0x3f;
TIMSK&=~_BV(OCIE1A);
TCNT1=0;
Key=0;//Myclock=0;
}
else if(Key^=((MyMessage*)p)->switches)
{TCCR1B|=(_BV(WGM12)|_BV(CS12));
TIMSK|=_BV(OCIE1A);
}
else {TCCR1B&=~(_BV(WGM12)|_BV(CS12));
TIMSK&=~_BV(OCIE1A);
}
if(((MyMessage*)p)->SwitchUp)
{uint8_t dd=0;uint16_t div=1000;uint16_t t;
t=Myclock;
for(i=0;i<4;i++)
{
while(t>=div){dd+=1;t-=div;};
disp=pgm_read_byte(&LEDD[dd]);div/=10;dd=0;}
}
}
}
AVRX_GCC_TASKDEF(task2, 15, 1)
{uint8_t Tcount=0;
static MyMessage SwitchMessage;//声明新变量
while (1)
{ uint8_t current;
AvrXDelay(&timer1, 4);
PORTC=0xff;
PINC|=0xF0;
if((Tcount+=1)==4)
Tcount=0;
switch(Tcount&0x3)
{case 0x0:PORTC&=0x7f;break;
case 0x1:PORTC&=0xbf;;break;
case 0x2:PORTC&=0xdf;break;
case 0x3:PORTC&=0xef;break;
}
if(((Tcount&0x3)==0)&&(disp[Tcount]==0x3f))
LED=0xff;
else if((Tcount&0x3)==1)
LED = disp[Tcount]|0x80;
else LED = disp[Tcount];
// LED = disp[Tcount];
current=(~PINC)&03;
if(SwitchMessage.switches!=current)
{SwitchMessage.switches=current;
AvrXSendMessage(&MyQueue, &SwitchMessage.mcb);
}
}
}
int main(void) // Main runs under the AvrX Stack
{
AvrXSetKernelStack(0);
MCUCR = 1<<SE;
TCNT0 = TCNT0_INIT;
TCCR0 = TMC8_CK256;
TIMSK = 1<<TOIE0;
LEDDDR = 0xFF;
LED = 0xFF;
PORTC=0xff;
DDRC=0xf0;
PINC=0xFF;
OCR1A=F_CPU*10/256/1000;//10ms
TCNT1=0;
AvrXRunTask(TCB(task1));
AvrXRunTask(TCB(task2));
/// AvrXRunTask(TCB(Monitor));
InitSerialIO(UBRR_INIT); // Initialize USART baud rate generator
Epilog(); // Switch from AvrX Stack to first task
while(1);
}
结论
AVRX是一个不错的RTOS,最显著的特点就是内核小,速度快,编译后大概只需700~1000字(words),且基本的调度功能一个也不少。由于其
代码公开,结合不同型号AVR单片机的特性,可以在此基础上进行系统的裁减和扩展,使之能达到更好的效果。本文为AVR嵌入式系统的应用提
供了借鉴。
-----此内容被ml07077于2007-01-04,16:04:11编辑过 |
|