基于GD32+FreeRTOS队列串口接收的一种思路

前言

平台:GD32F303+FreeRTOS

实现思路:

 使用队列作为数据容器,将串口接收中断里的数据传递到任务中,替代使用全局变量的方式,保证数据的完整性。

实现过程

  1. 串口的初始化,标准流程,应该没什么好说的了吧。
    /* USART0 init function */
    
    void MX_USART0_UART_Init(void)
    {
    	/* USART interrupt configuration */
    	nvic_irq_enable(USART0_IRQn, 0, 0);
    
    	/* enable GPIO clock */
    	rcu_periph_clock_enable(RCU_GPIOA);
    
    	/* enable USART clock */
    	rcu_periph_clock_enable(RCU_USART0);
    
    	/* connect port to USARTx_Tx */
    	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    
    	/* connect port to USARTx_Rx */
    	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    
    	/* USART configure */
    	usart_deinit(USART0);
    	usart_baudrate_set(USART0, 115200U);
    	usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    	usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    	usart_enable(USART0);
    
    	/* enable USART0 receive interrupt */
        usart_interrupt_enable(USART0, USART_INT_RBNE);
    
    
    }
  2. 主函数,初始化队列和接收任务。这里任务堆栈使用最小堆栈,任务优先级可自定义。
    //uart0 task
    #define UART0_STK_SIZE    configMINIMAL_STACK_SIZE//任务堆栈
    #define UART0_TASK_PRIO    ( tskIDLE_PRIORITY + 3 )//任务优先级
    TaskHandle_t uart0_task_t;//任务句柄
    void uart0_task(void * pvParameters);//任务函数
    
    #define UART0_RX_QUEUE_SIZE	(0XFF)//接收队列长度
    QueueHandle_t uart0_rx_queue = NULL;//接收队列句柄
    
    int main(void)
    {
    
    	MX_USART0_UART_Init();
    
    	taskENTER_CRITICAL();
    	
    	//创建任务
    	xTaskCreate(uart0_task, "uart0_task", UART0_STK_SIZE, NULL, UART0_TASK_PRIO, &uart0_task_t);
    
        //初始化接收队列,队列长度根据需求定义
    	uart0_rx_queue = xQueueCreate(UART0_RX_QUEUE_SIZE, sizeof(char));//单个长度为char
    	
    	taskEXIT_CRITICAL();
    	/* start scheduler */
    	vTaskStartScheduler();
    
    	while(1)
        {
    
        }
    }
  3. 接收任务函数,这里判断0xOD、0x0A是以回车换行结束的数据为接收依据,portMAX_DELAY表示任务将阻塞等待直到收到数据。

    
    /* 接收任务 */
    void uart0_task(void * pvParameters)
    {
    	static uint8_t rx_byte;//接收字节
    	static uint16_t rx_flag;//接收标志
    	static uint8_t rx_data[UART0_RX_QUEUE_SIZE];//接收缓存
    
    	while(1)
    	{
    		if (xQueueReceive(uart0_rx_queue, &rx_byte, portMAX_DELAY) == pdPASS)//等待接收队列
    		{
    			/*接收到了0x0d*/
    			if((rx_byte==0x0d)&&((rx_flag&0X3FFF)>0))
    			{
    				rx_flag|=0x4000;
    				rx_data[rx_flag&0X3FFF] = rx_byte;
    				rx_flag++;
    			}
    			/*接收到了0x0a*/
    			else if((rx_flag&0x4000)&&((rx_flag&0X3FFF)>0)) 				
    			{
    				if(rx_byte==0x0a)
    				{
    				  rx_flag|=0x8000;				
    				}
    				rx_data[rx_flag&0X3FFF] = rx_byte;
    				rx_flag++;
    				usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
    				printf("rx: %d,%s", rx_flag&0x3fff, rx_data);
    				memset(rx_data, 0, sizeof(rx_data));
    				rx_flag = 0;
    			}
    			else
    			{
    				rx_data[rx_flag&0X3FFF] = rx_byte;
    				rx_flag++;
    				if(rx_flag > UART0_RX_QUEUE_SIZE-1)
    					rx_flag = 0;
    			}
    			
    		}
    
    	}
    		
    }
  4. 串口中断函数,将接收到的数据发送到队列,注意中断里要使用xQueueSendFromISR(),如果出现队列满,可以适当增加队列长度。
    /*!
        \brief      this function handles USART RBNE interrupt request and TBE interrupt request
        \param[in]  none
        \param[out] none
        \retval     none
    */
    void USART0_IRQHandler(void)
    {
    	uint8_t res;
    
    	BaseType_t xHigherPriorityTaskWoken = pdTRUE;
    	BaseType_t err;
    	if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))//接收缓存非空标志
    	{
    		/* receive data */
    		res = usart_data_receive(USART0);
    		if(xQueueIsQueueFullFromISR(uart0_rx_queue) == pdFALSE)
    		{
    			err = xQueueSendFromISR(uart0_rx_queue, &res, &xHigherPriorityTaskWoken);;//发送到接收数据
    			if(err != pdPASS)
    				debug_log("uart0 queue send error", NULL, -1, -1);
    		}
    		else {
    			debug_log("uart0 queue full", NULL, -1, -1);
    			xQueueReset(uart0_rx_queue);
    		}
    		
    		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
    
    	}
    
    
    }

小结

当然实现串口接收的方式还有很多种,这里仅提供一种较直接简单的思路,后续整理好继续分享给大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值