1.32 Cubemx_STM32F429串口中断+空闲中断

1、简介

有时候串口接收数据时,没有帧头与帧尾,单纯使用单字节中断接收数据,不太好断帧。如果单纯使用空闲中断接收数据,当帧内数据不连续或者黏包,使用空闲中断接收就会出现接收的数据小于或者大于帧长度,比较难断帧。解决办法

方法1、单字节中断接收+空闲中断

发送命令,等待返回数据,利用单字节中断将接收的数据压入缓存堆栈,当发生空闲中断后,判断缓存里的数据是否达到帧长度,如果是,解析数据,清空缓存;否则继续接收数据,知道达到帧长度,然后解析数据,清空缓存。

方法2、单纯使用空闲中断。

发送命令,等待返回数据,如果产生空闲中断,数据压入缓存堆栈,判断是数据长度是否完成,如果是,解析数据,清空缓存;否则继续接收数据,直到达到帧长度,然后解析数据,清空缓存。

2、配置

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3、 方法1

3.1 工程代码

中断以及接收


#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);
    }
}

3.2 个人笔记与工程无关代码

tmcl_thread.c

#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,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值