串口1连接蓝牙模块在串口中断中接收数据
通过消息队列将数据发送给任务
任务请求消息阻塞等待
调试过程中,APP每隔200ms向串口发送一次数据
分别在串口和任务中的消息发送函数里标记flag计数,发现消息队列全部接收到数据并转发成功,
但根据指令解析处理函数未处理,出现蓝牙数据丢包现象。
串口中断中发送消息函数如下:
/****************************************************
函数名:USART1_IRQHandler
形参:
返回值:无
函数功能:串口中断处理函数
****************************************************/
void USART1_IRQHandler(void) //串口1中断服务程序
{
static u8 Rxcount = 0;
u8 recv_u1 =0;
OSIntEnter();
#if 1
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
recv_u1 = USART_ReceiveData(USART1); //(USART1->DR); //读取接收到的数据
ServerData.server_data_rx[Rxcount++] = recv_u1;
}
else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//接收到一帧数据
{
recv_u1 = USART_ReceiveData(USART1);
Rxcount = 0;
//蓝牙模块 修改名称
if(strstr((char*)ServerData.server_data_rx,"AT+OK\r\n") != NULL)
{
if((strlen((char*)ServerData.server_data_rx)) < 8)
return;
substring(BLT_Rx_Buf,(char*)ServerData.server_data_rx,20,7);
}
else
{
OSQPost ((OS_Q *)&Server_DATA_Q, //消息变量指针
(void *) &ServerData.server_data_rx,//要发送的数据的指针,将内存块首地址通过队列“发送出去”
(OS_MSG_SIZE )8, //数据字节大小
(OS_OPT )OS_OPT_POST_LIFO, //先进先出和发布给全部任务的形式
(OS_ERR *)&err);
}
}
#endif
OSIntExit();
}
任务中请求接收消息如下:
/****************************************************
函数名:Server_task
形参:
返回值:
函数功能:设备与服务器通信 任务处理
****************************************************/
void Server_task(void *p_arg)
{
OS_MSG_SIZE size;
u8 * p;
u8 i;
while(1)
{
//请求消息KEY_Msg
p = OSQPend((OS_Q* )&Server_DATA_Q,
(OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(OS_MSG_SIZE* )&size,
(CPU_TS* )0,
(OS_ERR* )&err);
//处理串口接收到的数据
if(err == OS_ERR_NONE)
{
ServerData.Sw_Command = *(p+1); //保存变量地址
ServerData.Sw_Value1 = ((*(p+2) << 8) & 0xFF00 ) | (*(p+3) & 0x00FF); //保存变量数据
ServerData.Sw_Value2 = ((*(p+4) << 8) & 0xFF00 ) | (*(p+5) & 0x00FF); //保存变量数据
for(i = 0; i < 8; i++)
*(p+i) = 0;
Server_Data_Receive(); //数据接收
ServerCommand_Updata();//设置数据接收处理
}
else//帧头和校验值不正确 清除校验值和接收缓存
{
ServerData.CRC_Value = 0x0000;
for(i = 0; i < 8; i++)
*(p+i) = 0;
}
}
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err); //延时10ms
}
因为判断err无错误才处理中断,怀疑是err出现问题所以未进入蓝牙数据处理函数
将err添加到watch窗口,查看变量
发现app蓝牙数据传送多了之后 err 会由OS_ERR_NONE 变成 OS_ERR_INT_Q_FULL
搜索一下这个变量在哪出现
出现在os_int.c中,看一下这个函数是啥
void OS_IntQPost (OS_OBJ_TYPE type, //内核对象类型
void *p_obj, //被发布的内核对象
void *p_void, //消息队列或任务消息
OS_MSG_SIZE msg_size, //消息的数目
OS_FLAGS flags, //事件标志组
OS_OPT opt, //发布内核对象时的选项
CPU_TS ts, //发布内核对象时的时间戳
OS_ERR *p_err) //返回错误类型
{
CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变
//量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR)
//,开中断时将该值还原。
#ifdef OS_SAFETY_CRITICAL //如果使能(默认禁用)了安全检测
if (p_err == (OS_ERR *)0) { //如果错误类型实参为空
OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数
return; //返回,不继续执行
}
#endif
CPU_CRITICAL_ENTER(); //关中断
if (OSIntQNbrEntries < OSCfg_IntQSize) { //如果中断队列未占满
OSIntQNbrEntries++;
if (OSIntQNbrEntriesMax < OSIntQNbrEntries) { //更新中断队列的最大使用数目的历史记录
OSIntQNbrEntriesMax = OSIntQNbrEntries;
}
/* 将要重新提交的内核对象的信息放入到中断队列入口的信息记录块 */
OSIntQInPtr->Type = type; //保存内核对象类型
OSIntQInPtr->ObjPtr = p_obj; //保存被发布的内核对象
OSIntQInPtr->MsgPtr = p_void; //保存消息内容指针
OSIntQInPtr->MsgSize = msg_size; //保存消息大小
OSIntQInPtr->Flags = flags; //保存事件标志组
OSIntQInPtr->Opt = opt; //保存选项
OSIntQInPtr->TS = ts; //保存对象被发布的时间错
OSIntQInPtr = OSIntQInPtr->NextPtr; //指向下一个带处理成员
/* 让中断队列管理任务 OSIntQTask 就绪 */
OSRdyList[0].NbrEntries = (OS_OBJ_QTY)1; //更新就绪列表上的优先级0的任务数为1个
OSRdyList[0].HeadPtr = &OSIntQTaskTCB; //该就绪列表的头指针指向 OSIntQTask 任务
OSRdyList[0].TailPtr = &OSIntQTaskTCB; //该就绪列表的尾指针指向 OSIntQTask 任务
OS_PrioInsert(0u); //在优先级列表中增加优先级0
if (OSPrioCur != 0) { //如果当前运行的不是 OSIntQTask 任务
OSPrioSaved = OSPrioCur; //保存当前任务的优先级
}
*p_err = OS_ERR_NONE; //返回错误类型为“无错误”
} else { //如果中断队列已占满
OSIntQOvfCtr++; //中断队列溢出数目加1
*p_err = OS_ERR_INT_Q_FULL; //返回错误类型为“中断队列溢出”
}
CPU_CRITICAL_EXIT(); //开中断
}
在使用OSQPost函数发送消息队列的时候,会调用OS_IntQPost,这时候中断队列满了所以err出现OS_ERR_INT_Q_FULL错误。看看我都用了啥中断,好几个定时器、串口还有任务里也用了好多临界段
在os_cfg_app.h中可以设置中断队列和中断服务任务的大小
原UCOSIII系统 中断队列大小OS_CFG_INT_Q_SIZE 设置的是10u 改为 50u
原UCOSIII系统中断服务任务的栈大小OS_CFG_INT_Q_TASK_STK_SIZE 设置的是128u 改为 200u
修改后重新测试app每隔200ms给蓝牙发数据,没出现中断队列溢出的错误了,蓝牙数据也全部解析指令处理完成。