[转]STM32 串口传输处理方式 FreeRTOS+队列+DMA+IDLE (二)

紧接着上一篇文章,如何合理处理多个串口接收大量数据。此种方法,很厉害,很NB,首先,利用DMA 可节省大量CUP资源。其次,利用IDLE空闲中断来接收位置个数的数据。最后利用串口DMA环形数据的偏移量、长度,入队,出队处理数据。保证了任务的流畅处理。
串口接收数据:
中心思想
1、开启DMA 环形接收数据模式。
2、触发接收数据中断。
3、假如数据有进来,将上面环形数据的偏移量与长度 入队。
4、出队函数,处理数据。

直接上代码
两个任务完成

#define MAX_FRAME_DISP_LEN       125       #define MAX_FRAME_DISP_ITEM      5         #define MaxSize_FRAME_DISP    (MAX_FRAME_DISP_LEN*MAX_FRAME_DISP_ITEM)  static void RecUart1Temp_Task(void* parameter){		uint16_t len;	uint16_t ndtr_last;//上次剩余个数	BufferLoopData_Typedef buffer_loop;	BaseType_t xReturn = pdPASS;	 	buffer_loop.start_addr = 0;	buffer_loop.len = 0;	ndtr_last = MaxSize_FRAME_DISP;        while (1)        {           //等待有数据消息	   xReturn = xSemaphoreTake(BinarySem_Handle,  portMAX_DELAY); 	   len = Reg_Usart1_CHANNEL_CNDTR;//DMA剩余个数	   //环形数组	   if (ndtr_last != len)//上次与这次不同,表示有新数据	   {		buffer_loop.start_addr = buffer_loop.start_addr + buffer_loop.len;                //环形数据地址偏移量		if (buffer_loop.start_addr >= MaxSize_FRAME_DISP)		{		     buffer_loop.start_addr = buffer_loop.start_addr - MaxSize_FRAME_DISP;		}			if (ndtr_last > len)		{		    buffer_loop.len = ndtr_last - len;                    //接收数据长度=上次长度-这次长度		}		else		{		    buffer_loop.len = MaxSize_FRAME_DISP  - len+ ndtr_last;                    //环形数据到头后,总数-这次剩余+上次剩余		} 		ndtr_last = len;							if ((buffer_loop.len > 0)||(buffer_loop.len < MAX_FRAME_DISP_LEN))		{			xQueueSendToBack(xQueue_Smrj_rx,(void *)&buffer_loop,0);		}            	}	taskYIELD();        	    }} 

任务出队,处理函数

extern  uint8_t rxbuf_Uart1_DMA[MaxSize_FRAME_DISP]; static void RecUart1DealTask(void* pvParameters){    uint16_t i;    BufferLoopData_Typedef buffer_loop;       for (;;)    {        xQueueReceive(xQueue_Smrj_rx,&buffer_loop,portMAX_DELAY);          if ((buffer_loop.len > 0)&&(buffer_loop.len < MAX_FRAME_DISP_LEN))        {            for (i=0;i= MaxSize_FRAME_DISP)                {                    buffer_loop.start_addr = buffer_loop.start_addr - MaxSize_FRAME_DISP;                }                rxbuf_Uart1_tmp[i] = rxbuf_Uart1_DMA[buffer_loop.start_addr];                                buffer_loop.start_addr += 1;                 }                  __nop();            /*此处处理接收的数据*/            //Smrj_RecUserHandle(&rxbuf_Uart1_tmp[0],buffer_loop.len);	    //SMRJ_Data_Dec(&rxbuf_Smrj_tmp[0],buffer_loop.len);        }        taskYIELD();     }  }

中断处理函数:

void USART1_IRQHandler(void){     uint32_t ulReturn;     ulReturn = taskENTER_CRITICAL_FROM_ISR();     if(USART_GetITStatus(DEBUG_USARTx,USART_IT_IDLE)!=RESET)        {				Uart_DMA_Rx_Data();   		USART_ReceiveData(DEBUG_USARTx); 		taskEXIT_CRITICAL_FROM_ISR( ulReturn );         }} void Uart_DMA_Rx_Data(void){	BaseType_t pxHigherPriorityTaskWoken;	DMA_Cmd(USART_RX_DMA_CHANNEL, DISABLE);      	DMA_ClearFlag( DMA1_FLAG_TC5 );                  Reg_Usart1_CHANNEL_CNDTR=  USART_RX_DMA_CHANNEL->CNDTR;//循环数组里剩余个数	DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE);       	xSemaphoreGiveFromISR(BinarySem_Handle,&pxHigherPriorityTaskWoken);		portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);} 

串口初始化见上面一篇文章
总结,从上面代码我们可以看到,我们是巧妙的利用的串口DMA环形模式,利用队列来处理数据。
下一篇,我们直接利用环形缓存buf来实现数据的处理,是的更加的通用性。

————————————————
版权声明:本文为CSDN博主「断雁孤鸿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/oDuanYanGuHong/article/details/100576160

---------------------
作者:ba_wang_mao
来源:CSDN
原文:https://blog.csdn.net/ba_wang_mao/article/details/103817626?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-0.pc_relevant_default&spm=1001.2101.3001.4242.1&utm_relevant_index=2
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值