最近刚学ucos-II,想利用ucos-ii中的任务调度来实现数据包处理功能,数据包采用stm32串口收发。具体思路如下:
1、用串口1发送数据包,串口2接收。
2、滴答定时器判接收超时。
3、接收超时则进入数据处理任务。
先写串口部分。
发送数据包函数:
void USART1_Send_Message(u8 *SendData,u8 len)
{
while(len--)
{
USART_SendData(USART1,*SendData++);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
}
}
串口2接收中断:
u8 *RES;
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2,USART_IT_RXNE))
{
*RES= USART_ReceiveData(USART2);
}
}
开始调试,断点打在中断函数第一个括号,发现进不了,查了半天才发现问题出在
错在时钟使能上,导致USART2无法接收数据。 改正后,断点打在中断能进去,但是运行完报硬件错误中断,把U8* res放进中断函数后,好了。原因不值,估计涉及野指针,明天补充。。。
接昨天内容,在能接受到字节数据后,断点打在接收中断函数,发现会漏数据,一开始以为是时钟或者中断优先级问题,后来将断点打在串口发送函数中,漏字节现象消失。
由于在具体项目中,串口接收中断基本不回去直接处理字节数据,而是等缓冲区满了之后再将数据存入内存。因此中断要修改成接收不定长数据包形式。
串口部分修改后如下:
void USART1_Send_Message(u8 *SendData,u8 len)
{
while(len--)
{
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_SendData(USART1, *SendData++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
return;
}
void USART2_IRQHandler(void)
{
u8 res;
static u8 first_byte=0;
static u8 which_buff=0;
if(USART_GetITStatus(USART2,USART_IT_RXNE))
{
switch(first_byte) //接收到首字符
{
case 0:
res= (u8)USART_ReceiveData(USART2);
if(res==0x7A) //首字符为0x7A
{
if_start_systick=1; //进入滴答定时器中断
first_buff[usart_RecIndex++]=res;
first_byte=1; //非首字符标志
data_comed=1; //新数据标志,滴答定时器中断计数值清零
return;
}
break;
case 1: //接收到非首字符
data_comed=1; //新数据标志,滴答定时器中断计数值清
if(USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
{
(void)USART_ReceiveData(USART2);//溢出
return;
}
else
{
switch(which_buff) //选择接收数据存放数组
{
case first_buff_flag:
if(usart_RecIndex >= BUF_SIZE)//第一个数组满
{
which_buff=second_buff_flag;
OSSemPost(sem_dpacket);//申请信号量,进入任务处理
usart_RecIndex=0; //字符位置清零
second_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
}
else
{
first_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
}
break;
case second_buff_flag: //第二个数组
if(usart_RecIndex >= BUF_SIZE)//第二个数组满
{
which_buff=first_buff_flag;
OSSemPost(sem_dpacket);
usart_RecIndex=0;
first_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
}
else
{
second_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
}
break;
default :break;
}
}
break;
default : break;
}
}
}
滴答定时器判超时:
void SysTick_Handler(void)
{
static u8 tim_cnt=0; //中断计数器
if(delay_osrunning==1)
{
OSIntEnter(); //½øÈëÖжÏ
OSTimeTick(); //µ÷ÓÃucosµÄʱÖÓ·þÎñ³ÌÐò
if(if_start_systick) //若接收到有效数据
{
if(tim_cnt>=30) //无数据时长达到30x5=150ms,认为此次接收完成
{
tim_cnt=0;
if_start_systick=0;
OSSemPost(sem_dpacket); //进入任务处理
}
else
{
if(data_comed==1) //5ms内有新数据
{
tim_cnt=0; //计数器清零
data_comed=0; //标志清零
}
else
{
tim_cnt++; //5ms内无新数据
}
}
}
OSIntExit();
}
return;
}
任务处理函数处理数据包:
//此任务未做数据处理,简单将接受数组中的数据取出并在LCD显示
void dpacket_task(void *pdata)
{
u8 err;
u8 i;
u8 x_loc;
while(1)
{
OSSemPend(sem_dpacket,0,&err);
if(usart_RecIndex==sizeof(buf))
{
memcpy(packetdata,first_buff,usart_RecIndex);
for(i=0;i<=usart_RecIndex-1;i++)
{
x_loc=20*i+10;
LCD_ShowxNum(x_loc,140,(u16)first_buff[i],3,16,1);
}
}
}
}
注:此任务没有长数据包进行验证。