有时候串口接收数据时,没有帧头与帧尾,单纯使用单字节中断接收数据,不太好断帧。如果单纯使用空闲中断接收数据,当帧内数据不连续或者黏包,使用空闲中断接收就会出现接收的数据小于或者大于帧长度,比较难断帧。解决办法
发送命令,等待返回数据,利用单字节中断将接收的数据压入缓存堆栈,当发生空闲中断后,判断缓存里的数据是否达到帧长度,如果是,解析数据,清空缓存;否则继续接收数据,知道达到帧长度,然后解析数据,清空缓存。
发送命令,等待返回数据,如果产生空闲中断,数据压入缓存堆栈,判断是数据长度是否完成,如果是,解析数据,清空缓存;否则继续接收数据,直到达到帧长度,然后解析数据,清空缓存。
#define RS485_TMLC_BAUD 9600//波特率
#define MEMPOOL_OBJECTS 15 // number of Memory Pool Objects
typedef struct
{
uint8_t buf[126]; // 数据
uint16_t Length; // 长度
}Message_t;
UART_HandleTypeDef *TMLCComm;
Message_t tmlcComRcvMsg;
uint8_t tmlcRdChar;
uint8_t tmlcComRdCounter = 0;
osMemoryPoolId_t tmlcRecMemPool;//内存池
osMessageQueueId_t tmlcRecMsgQueue;
/******************************************************************
函数名称: bsp_InitUart
函数: 串口参数设置
*****************************************************************/
void bsp_InitUart(void)
{
tmlcRecMemPool = osMemoryPoolNew(MEMPOOL_OBJECTS, sizeof(Message_t), NULL);
if(tmlcRecMemPool==NULL)
{
return ;//MemPool object not created, handle failure
}
tmlcRecMsgQueue = osMessageQueueNew(MEMPOOL_OBJECTS,sizeof(uint32_t), NULL);
if (tmlcRecMsgQueue == NULL) {
return -1;
}
TMLCComm = &huart4;
Usart_SetBuadRate(TMLCComm,RS485_TMLC_BAUD);
HAL_UART_Receive_IT(TMLCComm, (uint8_t *)&tmlcRdChar, 1);
__HAL_UART_ENABLE_IT(TMLCComm ,UART_IT_IDLE);
}
/******************************************************************
函数名称: HAL_UART_RxCpltCallback
函数功能: 串口中断回调函数
*****************************************************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* uartHandle)
{
if (uartHandle->Instance == TMLCComm->Instance)
{
//if (__HAL_UART_GET_FLAG(TMLCComm,UART_FLAG_RXNE) != RESET)
{
tmlcComRcvMsg.buf[tmlcComRdCounter] = tmlcRdChar;
tmlcComRdCounter++;
if (tmlcComRdCounter>sizeof(tmlcComRcvMsg.buf)-1)
{
tmlcComRdCounter = 0;
}
}
}
}
/******************************************************************
函数名称: void tmlc_com_rev_idle_callback(UART_HandleTypeDef *huart)
函数功能: TMLC串口空闲中断回调函数
*****************************************************************/
void tmlc_com_rev_idle_callback(UART_HandleTypeDef *huart)
{
Message_t *pMemMsg;
if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
if (tmlcComRdCounter>0)
{
pMemMsg = (Message_t *)osMemoryPoolAlloc(tmlcRecMemPool, 0U);
memset(pMemMsg,0,sizeof(Message_t));
tmlcComRcvMsg.Length = tmlcComRdCounter;
memcpy(pMemMsg,&tmlcComRcvMsg,sizeof(Message_t));
osMessageQueuePut(tmlcRecMsgQueue,&pMemMsg,0u,0u);
tmlcComRdCounter = 0;
}
}
}
/******************************************************************
函数名称: HAL_UART_ErrorCallback
函数功能: 串口错误回调函数
*****************************************************************/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle)
{
if (uartHandle->Instance == TMLCComm->Instance)
{
uint32_t isrflags = READ_REG(uartHandle->Instance->SR);//清错误都要先读SR
if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_PE))!=RESET)
{
READ_REG(uartHandle->Instance->DR);//PE清标志
__HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_PE);//清标志
}
if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_FE))!=RESET)
{
READ_REG(uartHandle->Instance->DR);
__HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_FE);
}
if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_NE))!=RESET)
{
READ_REG(uartHandle->Instance->DR);//NE清标志,第二步读DR
__HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_NE);
}
if((__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_ORE))!=RESET)
{
READ_REG(uartHandle->Instance->CR1);//ORE清标志,第二步读CR
__HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_ORE);
}
uartHandle->RxState = HAL_UART_STATE_READY;
}
else
{
;
}
}
//中断函数
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
/* USER CODE END UART4_IRQn 0 */
HAL_UART_IRQHandler(&huart4);
/* USER CODE BEGIN UART4_IRQn 1 */
tmlc_com_rev_idle_callback(&huart4);
HAL_UART_Receive_IT(TMLCComm, (uint8_t *)&tmlcRdChar, 1);
/* USER CODE END UART4_IRQn 1 */
}
uint16_t RcvLength=0;
Message_t tmlcRcvBuf;
void tmcl_task (void * arg)
{
uint32_t ptr;
osStatus_t status;
/*
tmlcResponseRd = 0;
tmlcResponseWr = 0;
createInitSeq(ADDR_1);
clearRcvFifo();
*/
while (1)
{
status = osMessageQueueGet(tmlcRecMsgQueue,&ptr,0U,0U);
if (osOK == status)
{
tmlcRcv_p = (Message_t *)ptr;
memcpy(&tmlcRcvBuf.buf+RcvLength,tmlcRcv_p,tmlcRcv_p->Length);
RcvLength +=tmlcRcv_p->Length;
tmlcRcvBuf.Length=RcvLength;
if(RcvLength>=9)//收到完整数据包
{
//do something... .
//比如数据解析,处理完后记得将缓存相关数据全部清空
/*
if(analysisTmlcRcvCmd(&tmlcRcvBuf,&fb_data)==0)
{
tmlcResponseWr++;
RcvLength=0;
}
else
{
osDelay(1);
}
*/
}
osMemoryPoolFree(tmlcRecMemPool,tmlcRcv_p);
}
/*
if (tmcl_HasSeq) // 有命令序列
{
if (tmlcSeqCommandBuf.seqStatus == WRITESEQ)
{
tmcl_HasSeq = WriteTMLC_ActionSeg();
}
else
tmcl_HasSeq = ReadTMLC_ActionSeg();
if (tmlcTimeOut > ACKCHECK_TIME)
{
tmcl_HasSeq = 0;
clearRcvFifo();
osEventFlagsSet(tmlcCommuationTimeOutEvt_id,0x1u);//通讯失败
}
}
else //序列执行完成
{
status = osMessageQueueGet(tmlcContrlcMsgQueue,&tmlcControlCommand,0,0);
if (osOK ==status)
{
add_CtrlCmd=1;
}
else
{
createReadSeq(ADDR_1);
}
}
checkCtlCmd();
*/
osDelay(1);
}
}
#include "tmcl_thread.h"
extern int32_t tmlcTimeOut;
tmlcControlMsg_t tmlcControlCommand;
Message_t *tmlcRcv_p;
uint8_t seq_NO=0;
uint8_t add_CtrlCmd=0;
uint32_t refreshTick;
uint32_t SendStatusPeriod=10;
uint16_t DebugCounter=0;
uint16_t RcvLength=0;
void tmcl_task (void * arg)
{
uint32_t ptr;
int32_t fb_data;
osStatus_t status;
tmlcResponseRd = 0;
tmlcResponseWr = 0;
createInitSeq(ADDR_1);
clearRcvFifo();
// clearError();
while (1)
{
// SeqTest(seq_NO);
status = osMessageQueueGet(tmlcRecMsgQueue,&ptr,0U,0U);
if (osOK == status)
{
tmlcRcv_p = (Message_t *)ptr;
memcpy(&tmlcRcvBuf.buf+RcvLength,tmlcRcv_p,tmlcRcv_p->Length);
RcvLength +=tmlcRcv_p->Length;
tmlcRcvBuf.Length=RcvLength;
if(RcvLength>=9)//收到完整数据包
{
if(analysisTmlcRcvCmd(&tmlcRcvBuf,&fb_data)==0)
{
tmlcResponseWr++;
RcvLength=0;
}
else
{
osDelay(1);
}
}
osMemoryPoolFree(tmlcRecMemPool,tmlcRcv_p);
}
if (tmcl_HasSeq) // 有命令序列
{
if (tmlcSeqCommandBuf.seqStatus == WRITESEQ)
{
tmcl_HasSeq = WriteTMLC_ActionSeg();
}
else
tmcl_HasSeq = ReadTMLC_ActionSeg();
if (tmlcTimeOut > ACKCHECK_TIME)
{
tmcl_HasSeq = 0;
clearRcvFifo();
osEventFlagsSet(tmlcCommuationTimeOutEvt_id,0x1u);//通讯失败
}
}
else //序列执行完成
{
status = osMessageQueueGet(tmlcContrlcMsgQueue,&tmlcControlCommand,0,0);
if (osOK ==status)
{
add_CtrlCmd=1;
}
else
{
createReadSeq(ADDR_1);
}
}
checkCtlCmd();
osDelay(1);
}
}
/**
入参:checkCtlCmd(void)
功能:检测是否有控制命令
返回:NULL
**/
void checkCtlCmd(void)
{
if((osKernelGetTickCount()-refreshTick)>SendStatusPeriod)
{
refreshTick = osKernelGetTickCount();
if(add_CtrlCmd==1 && tmcl_HasSeq==1)
{
if(p_tmlcSeqCommandBuf->sumstep-1==p_tmlcSeqCommandBuf->currentstep)//等待前面序列执行完
{
osDelay(20);
unpackTmlcControlCommand();
add_CtrlCmd=0;
}
}
}
}
//命令控制
void unpackTmlcControlCommand(void)
{
tmlc_contrlseq_t command;
command = (tmlc_contrlseq_t)tmlcControlCommand.action;
switch (command)
{
case STOP_MODE: //停止
createRELPositionSeq(ADDR_1,4096);
//createStopSeq(ADDR_1);
break;
case LIMIT_MODE://运动到限位
createLimitgSeq(ADDR_1,DIR_NEGATIVE,