FreeRTOS中断和任务之间的队列,自定义串口通讯协议

本文提供这样一种方法:FreeRTOS中串口接收数据中断,然后通过队列将数据传递给任务A,在任务A中对数据进行处理,串口使用的通讯协议为自定义。
依次给出了串口的初始化,中断服务函数;任务A,队列创建的代码;由于实际在MDK中采用多文件编程,结合自己的需求对相应代码进行移植和修改.
由于本人能力水平有限,仅供参考,欢迎交流
串口初始化代码:

void usart5_init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO, ENABLE);	//使能GPIOA时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);	//使能USART5时钟
	
	//USART5_TX   GPIOC.12
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PC.12
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
   GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.12
   
  //USART5_RX	  GPIOD.2初始化
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PD2
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
   GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化GPIOD.2  
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

   USART_Init(UART5, &USART_InitStructure); //初始化串口5
  //Uart5 NVIC 配置
   NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=7 ;//抢占优先级7
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级一定需要为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
  USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);//开启串口接受中断
   USART_Cmd(UART5, ENABLE);                    //使能串口5 
	
}

中断服务函数

extern QueueHandle_t   S_Queue;//队列句柄,

//串口5中断服务函数,
void UART5_IRQHandler(void)   
{  
	 u16 ch=0;
	 int i=0;
	 BaseType_t xHigherPriorityTaskWoken;
     static  u8 count=0,t=0,data[4]={0x00,0x00,0x00,0x00}; 
  	 if(USART_GetITStatus(UART5, USART_IT_RXNE) != RESET)
	{
		 USART_ClearFlag(UART5, USART_FLAG_RXNE);
		 USART_ClearITPendingBit(UART5,USART_IT_RXNE);
		 ch=USART_ReceiveData(UART5);	//读取接收到的数据
      
		 switch(count){  //自定义的通讯协议为:0x01,0x02数据头,后面有4组数据,每组包含两位十六进制的数.
	       case 0:{if(ch==0x01) count++;else count=0;break;}									         						
		   case 1:{ if(ch==0x02) count++;else count=0;break;}       		 
		   case 2: data[t]=ch;t++;
                  if  (t==4) 
	            {			  
				          if(S_Queue!=NULL) //判断队列是否有效
		                 { 
				         xQueueSendFromISR(S_Queue,data,&xHigherPriorityTaskWoken);//向队列S_Queue中发送数据data,阻塞时间为最大
				         portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换	 
				         }
	                     count=0,t=0;//计数清零
	             } 		 
	    }
}


任务A:

#define  A_TASK_PRIO  4      //优先级
#define  A_STK_SIZE   256    //堆栈大小
TaskHandle_t ATask_Handler; //任务句柄
void A_task(void *pvParameters);

extern QueueHandle_t S_Queue;
//start_task中创建A_task
 xTaskCreate(
				(TaskFunction_t    )    A_task,
				(const char *      )    "A_task",	
				(uint16_t          )    A_STK_SIZE,
				(void *            )    NULL,
				(UBaseType_t       )    A_TASK_PRIO,
				(TaskHandle_t *    )    &A_Handler
             );

void A_task(void *pvParameters)    
{
  u8 data[4];
  int j=0;
  BaseType_t xTaskWokenByReceive=pdFALSE;
  BaseType_t err=pdFALSE; 
  
  for( ;; )    
    {    
     err=xQueueReceiveFromISR(S_Queue,data,&xTaskWokenByReceive);
     if(err==pdTRUE) //接收成功
        {
          	for( j=0;j<4;j++)	 //对数据进行处理,这里仅将他们打印出来	
           {
             printf("指令是:%X\n",data[j]);
            }
        }
       vTaskDelay(10);//延时,进入阻塞
    }
}

创建队列

#define S_MSG_Q_NUM      10  //消息队列的数量
#define USART_REC_LEN  	1  //定义最大接收字节数4  1B 字节=8bit 位,0x01:1B(字节)
S_Queue=xQueueCreate(S_MSG_Q_NUM,USART_REC_LEN);

欢迎关注公众号,干货满满。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43499780/article/details/106392129