对于RTOS来说,当外部事件发生的时候,触发中断,而从中断中通过POST信号量或消息等事件来让任务处理,是保证系统实时性的关键所在!我测试了这个时间是3-4微秒,一般的实时性足够了!有些话哪一本书都没有说,但是我想LABROSS老先生是很清楚的。
实验的平台是亮点STM32开发板
关键:中断服务程序运行在系统模式,特权级别;任务是用户程序,线程模式,可以是特权级别也可以是用户级别
/*实验
需求说明:从串口1采集数据 数据格式 0XFA 10个数据值 0XFF
例如 FA 01 02 03 04 05 06 07 08 09 0A FF
将采集到的10组数据送回串口,并显示在屏幕上
要求:因为数据采集速度要求很快,不能等待
分析:方法2:可采用双缓冲完成该需求,采集数据采用DMA方式,DMA中断服务程序中提交信号量给任务
创建一个任务用于处理和显示数据
优点:CPU占用率更低,基本在跑空闲任务
亮点嵌入式 UCOS实验
请将 FA 01 02 03 04 05 06 07 08 09 0A FF 发送到串口,将显示在屏幕上!
附加功能:从系统模式下的中断中提交到线程模式下的用户任务处理,到底要多久呢?
在这个例程中做了一个测试,测试的结果是3微妙
方法:中断ISR中POST后设置定时器计数频率1微秒
PEND信号量的任务在复活后马上关闭定时器,取计数值
*/
主程序代码:
int main(void)
{
INT8U os_err;
os_err=os_err;
bpboard_init();//初始化硬件
//bp_selfcheck(1);
OSInit(); //初始化UCOS
os_err = OSTaskCreate((void (*)(void *)) App_TaskStart, // 创建启动任务
(void * ) 0,
(OS_STK * )&App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //堆栈地址
(INT8U ) APP_TASK_START_PRIO); //优先级3,最高
os_err = OSTaskCreate((void (*)(void *)) App_TaskProc, /* 处理任务 */
(void * ) 0,
(OS_STK * )&App_TaskProcStk[APP_TASK_PROC_STK_SIZE - 1],
(INT8U ) APP_TASK_PROC_PRIO);
FontSize(32);
LcdPrintStr("亮点嵌入式学习平台STM32/UCOS/UCGUI",10,50,RED,WHITE,1);
LcdPrintStr("请将 FA 01 02 03 04 05 06 07 08 09 0A FF 发送到串口,将显示在屏幕上!",10,80,RED,WHITE,1);
LcdPrintStr("会自动计算中断到来到处理的时间间隔!",10,80,RED,WHITE,1);
FontSize(16);
OSStart();
return(0);
}
处理任务代码:
static void App_TaskProc(void *p_arg)
{
INT8U err;
uint16_t Counter;
u8 i;
u16 line=10;
MyEventSem=OSSemCreate(0);
if (MyEventSem==(OS_EVENT *)0)
{
printf("task rece failed to create sem!\r\n");
OSTaskDel(OS_PRIO_SELF);
return;
}
dma5_configuration();
while(1)
{
OSSemPend(MyEventSem,0,&err);
//这里获得计数器值,然后关闭计数器
TIM_Cmd(TIM1, DISABLE);
Counter=TIM1->CNT;
LcdClear(WHITE);
LcdPrintf(10,10,RED,WHITE,"从中断发生到离开中断到此处处理时间是:%d微秒",Counter);
led_on2;
if (USART1_BUF[PROCBUF][0]!=0xFA)
{
printf("the start byte is not 0xFA!\r\n");
}
line=20;
for(i=1;i<11;i++)
{
printf("%d ",USART1_BUF[PROCBUF][i]);
if (TFT_SUPPORT)
{ LcdPrintf(10,30+line,RED,WHITE,"NO %i is:%d",i,USART1_BUF[PROCBUF][i]);
line+=20;}
}
printf("\r\n");
led_off2;
}
}
中断ISR代码:
void DMA1_Channel5_IRQHandler(void)
{
u8 t;
if(DMA_GetITStatus(DMA1_IT_TC5)) //通道5传输完成中断
{
DMA_ClearITPendingBit(DMA1_IT_GL5); //清除中断等待标志
OSIntEnter();
t=RECEBUF; //交换缓冲区指针
RECEBUF=PROCBUF;
PROCBUF=t;
DMA_InitStructure5.DMA_MemoryBaseAddr = (u32)(&(USART1_BUF[RECEBUF][0]));
DMA_Init(DMA1_Channel5, &DMA_InitStructure5); //重新配置缓冲区
OSSemPost(MyEventSem);//修改为提交信号量 DMARECE=1;通知主程序,该发送数据了!
TIM1_Int_Init(1000000);//启动定时器1,用来做计数器,以微秒为单位
//65535微秒才记满
OSIntExit(); //有信号量提交,因此该中断服务程序需包含 OSIntEnter(); OSIntExit();
}
}
这样,屏幕上打印出3微妙,实际是计数3次,未到第4次,就是4微妙以内!
|