本文提供这样一种方法: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);
欢迎关注公众号,干货满满。