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

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

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS 中断优先级和任务优先级是两个独立的概念。 中断优先级用于确定不同中断之间的优先级关系。通常,芯片的中断控制器会提供多个中断通道,每个中断通道都有一个可配置的优先级。当多个中断同时发生时,具有更高优先级的中断会被优先处理。 任务优先级用于确定不同任务之间的调度顺序。FreeRTOS 使用优先级抢占调度算法,具有更高优先级的任务将抢占正在运行的低优先级任务,以确保高优先级任务能够及时执行。 在 FreeRTOS 任务优先级的范围通常是从 0 到 configMAX_PRIORITIES-1,其 configMAX_PRIORITIES 是 FreeRTOS 配置文件定义的最大任务优先级数。而中断优先级的范围则取决于芯片和中断控制器的具体实现。 当一个任务和一个中断同时发生时,如果中断的优先级高于或等于任务的优先级,则中断会打断任务的执行,并立即执行中断服务程序。当中断服务程序完成后,系统会根据任务的优先级重新进行调度。 需要注意的是,中断服务程序(ISR)应该尽量保持简短,并尽可能避免在 ISR 进行阻塞操作或长时间的计算。这是因为在 ISR 任务调度器是被禁止的,而且其他中断也无法打断当前的中断服务程序。因此,长时间的 ISR 可能会导致系统响应性能下降。 总结来说,中断优先级用于确定中断之间的优先级关系,而任务优先级用于确定任务之间的调度顺序。在设计和使用 FreeRTOS 系统时,合理配置中断任务的优先级是至关重要的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值