当前位置: 代码迷 >> 综合 >> 梳理STM32F429之通信传输部分---NO.3 串口空闲IDEL中断+DMA+FreeRTOS
  详细解决方案

梳理STM32F429之通信传输部分---NO.3 串口空闲IDEL中断+DMA+FreeRTOS

热度:77   发布时间:2023-12-16 13:59:51.0

梳理STM32F429之通信传输部分---NO.3 串口空闲IDEL中断+DMA+FreeRTOS

目录

一、串口空闲IDEL中断:

二、串口及串口中断的配置:

三、stm32f4xx_it.h 的配置:

四、DMA 的配置:

五、主函数


如果大家有什么问题,欢迎在下面评论交流!

串口部分的详解梳理STM32F429之通信传输部分---NO.1 串口通讯

DMA直接存储器访问梳理STM32F429之通信传输部分---NO.2 DMA—直接存储区访问

FreeRTOS-二值信号量从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十一)信号量 NO.1 基本概念

                                        从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十二)信号量 NO.2 常用信号量函数接口讲解

                                        从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十三)信号量 NO.3 信号量实验

这里补充一下:串口空闲IDEL中断的一些注意事项:

一、串口空闲IDEL中断:

1、串口空闲IDEL中断的作用:

       现在有很多数据处理都要用到不定长数据,而单片机串口的RXNE中断一次只能接收一个字节的数据,没有缓冲区,无法接收一帧多个数据,利用串口IDLE空闲中断的方式接收一帧数据,方法如下:

       实现思路:采用STM32F429的串口1,并配置成空闲中断IDLE模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是200个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理

2、注意事项:避免一直进入空闲中断

       空闲中断是在检测到在数据收受后,总线上在一个字节的时间内没有再接收到数据时发生。即串口的RXNE位被置位之后才开始检测,检测到空闲之后,串口的CR1寄存器的IDLE位被硬件置1,必须采用软件将IDLE位清零才能避免反复进入空闲中断。具体的做法是先读取USART_SR,再读取USART_DR。需要注意的是,不能采用库函数USART_ClearFlag()或者USART_ClearItPending()来清除IDEL标志位。

USART_ReceiveData(USART1);    清除标志位 

二、串口及串口中断的配置:

bsp_usart.c

/********************************************************************************* @file    bsp_usart.c* @author  Sumjess* @version V1.0* @date    2019-09-xx* @brief   MDK5.27******************************************************************************* @attention** 实验平台   :STM32 F429 * CSDN Blog  :https://blog.csdn.net/qq_38351824* 微信公众号 :Tech云********************************************************************************/#include "bsp_usart.h"/*** @brief  配置嵌套向量中断控制器NVIC* @param  无* @retval 无*/// 中断服务函数  在#include "stm32f4xx_it.h"中  为了防止写错中断服务函数,请去startup_stm32f429_439xx.s中粘贴
static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 嵌套向量中断控制器组选择 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);/* 配置USART为中断源 */NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;     //USART1_IRQn  串口1/* 抢断优先级为1 */NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;/* 子优先级为1 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;/* 使能中断 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/* 初始化配置NVIC */NVIC_Init(&NVIC_InitStructure);
}void Debug_USART_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;
/
//--------------------------------------串口1--------------------------------------------------///* -----------------------------串口相关的GPIO初始化-------------------------------------- */	RCC_AHB1PeriphClockCmd(DEBUG_USART1_RX_GPIO_CLK|DEBUG_USART1_TX_GPIO_CLK,ENABLE);/* 使能 USART 时钟 */RCC_APB2PeriphClockCmd(DEBUG_USART1_CLK, ENABLE);  //注意!只有串口1和6是APB2为90M,其他均为APB1为45M/* GPIO初始化 */GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     //输出推挽GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;       //上拉GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //速度50MHZ/* 配置Tx引脚为复用功能  */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;       //复用功能模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_TX_PIN  ;//GPIO_Pin_9  GPIO_Init(DEBUG_USART1_TX_GPIO_PORT, &GPIO_InitStructure); //GPIOA/* 配置Rx引脚为复用功能 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;       //复用功能模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART1_RX_PIN;  //GPIO_Pin_10 GPIO_Init(DEBUG_USART1_RX_GPIO_PORT, &GPIO_InitStructure);/* 连接 PXx 到 USARTx_Tx*/GPIO_PinAFConfig(DEBUG_USART1_RX_GPIO_PORT,DEBUG_USART1_RX_SOURCE,DEBUG_USART1_RX_AF);//GPIOA---9---GPIO_AF_USART1/*  连接 PXx 到 USARTx__Rx*/GPIO_PinAFConfig(DEBUG_USART1_TX_GPIO_PORT,DEBUG_USART1_TX_SOURCE,DEBUG_USART1_TX_AF);//GPIOA--10---GPIO_AF_USART1/* -----------------------------串口配置-------------------------------------- */	/* 配置串DEBUG_USART 模式 *//* 波特率设置:DEBUG_USART_BAUDRATE */USART_InitStructure.USART_BaudRate = DEBUG_USART1_BAUDRATE;     //115200 串口波特率/* 字长(数据位+校验位):8 */USART_InitStructure.USART_WordLength = USART_WordLength_8b;    /* 停止位:1个停止位 */USART_InitStructure.USART_StopBits = USART_StopBits_1;         /* 校验位选择:不使用校验 */USART_InitStructure.USART_Parity = USART_Parity_No;            /* 硬件流控制:不使用硬件流 */                                USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;/* USART模式控制:同时使能接收和发送 */USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;/* 完成USART初始化配置 */USART_Init(DEBUG_USART1, &USART_InitStructure);/* 配置串口的接收中断 */NVIC_Configuration();/	
//USART_IT_IDLE和USART_IT_RXNE区别 //当接收到1个字节,会产生USART_IT_RXNE中断 //当接收到一帧数据,就会产生USART_IT_IDLE中断// 开启 串口空闲IDEL 中断USART_ITConfig(DEBUG_USART1, USART_IT_IDLE, ENABLE);	
//	/* 使能串口接收中断 */
//	USART_ITConfig(DEBUG_USART1, USART_IT_RXNE, ENABLE);
//* 使能串口 */USART_Cmd(DEBUG_USART1, ENABLE);
}/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{/* 发送一个字节数据到USART */USART_SendData(pUSARTx,ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{uint8_t temp_h, temp_l;/* 取出高八位 */temp_h = (ch&0XFF00)>>8;/* 取出低八位 */temp_l = ch&0XFF;/* 发送高八位 */USART_SendData(pUSARTx,temp_h);	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);/* 发送低八位 */USART_SendData(pUSARTx,temp_l);	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{unsigned int k=0;do {Usart_SendByte( pUSARTx, *(str + k) );k++;} while(*(str + k)!='\0');/* 等待发送完成 */while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET){}
}//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USART_printf_choose, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USART_printf_choose, USART_FLAG_TXE) == RESET);		return (ch);
}//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{/* 等待串口输入数据 */while (USART_GetFlagStatus(DEBUG_USART_printf_choose, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USART_printf_choose);
}

bsp_usart.h

#ifndef __BSP_USART_H
#define	__BSP_USART_H
/********************************************************************************* @file    bsp.usart.c* @author  Sumjess* @version V1.0* @date    2019-09-10* @brief   MDK5.27******************************************************************************* @attention** 实验平台   :STM32 F429 * CSDN Blog  :https://blog.csdn.net/qq_38351824* 微信公众号 :Tech云********************************************************************************/
#include "stm32f4xx.h"
#include <stdio.h>
//---------------------------------------------------------------------------------------------//
//
//① 重定向c库函数printf到串口,重定向后可使用printf等函数
//② 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
//选择使用串口被允许使用 ① ② 
#define DEBUG_USART_printf_choose   DEBUG_USART1
////------------------------------------------------------//
//引脚定义
/*******************************************************/#define DEBUG_USART1                             USART1
#define DEBUG_USART1_CLK                         RCC_APB2Periph_USART1  //注意!只有串口1和6是APB2为90M,其他均为APB1为45M
#define DEBUG_USART1_BAUDRATE                    115200  //串口波特率#define DEBUG_USART1_RX_GPIO_PORT                GPIOA
#define DEBUG_USART1_RX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART1_RX_PIN                      GPIO_Pin_10
#define DEBUG_USART1_RX_AF                       GPIO_AF_USART1  //映射
#define DEBUG_USART1_RX_SOURCE                   GPIO_PinSource10
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_USART1_TX_GPIO_PORT                GPIOA
#define DEBUG_USART1_TX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART1_TX_PIN                      GPIO_Pin_9
#define DEBUG_USART1_TX_AF                       GPIO_AF_USART1  //映射
#define DEBUG_USART1_TX_SOURCE                   GPIO_PinSource9//中断部分配置//
#define DEBUG_USART_IRQHandler                  USART1_IRQHandler
#define DEBUG_USART_IRQ                 				USART1_IRQn     //串口1中断void Debug_USART_Config(void);                                 //串口初始化
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);     //发送一个字符
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);//发送一个16位数
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);    //发送字符串
int fputc(int ch, FILE *f);                                    //重定向c库函数printf到串口,重定向后可使用printf函数
int fgetc(FILE *f);                                            //重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数

三、stm32f4xx_it.h 的配置:

/* 声明引用外部二值信号量 */
extern SemaphoreHandle_t BinarySem_Handle;void USART1_IRQHandler(void)
{uint32_t ulReturn;/* 进入临界段,临界段可以嵌套 */ulReturn = taskENTER_CRITICAL_FROM_ISR();if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET){	Uart_DMA_Rx_Data();       /* 释放一个信号量,表示数据已接收 */USART_ReceiveData(USART1); /* 清除标志位 */}	 /* 退出临界段 */taskEXIT_CRITICAL_FROM_ISR( ulReturn );
}

四、DMA 的配置:

bsp_DMA.c

char RevBuff[REVBUFF_SIZE];void USART1_RX_DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;// 开启DMA时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);// DMA复位DMA_DeInit(USART1_RX_DMA_STREAM);  // 设置DMA通道DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  /*设置DMA源:串口数据寄存器地址*/DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)USART1_DR_BASE;// 内存地址(要传输的变量的指针)DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RevBuff;// 方向:从内存到外设	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;// 传输大小	DMA_InitStructure.DMA_BufferSize = (uint32_t)REVBUFF_SIZE;// 外设地址不增	    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 内存地址自增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 外设数据单位	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// 内存数据单位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	 // DMA模式,一次或者循环模式//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	// 优先级:中	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // 禁止内存到内存的传输/*禁用FIFO*/DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;    /*存储器突发传输 1个节拍*/DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;    /*外设突发传输 1个节拍*/DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;    /*配置DMA2的数据流7*/		   DMA_Init(USART1_RX_DMA_STREAM, &DMA_InitStructure);// 清除DMA所有标志DMA_ClearFlag(USART1_RX_DMA_STREAM,DMA_FLAG_TCIF2);DMA_ITConfig(USART1_RX_DMA_STREAM, DMA_IT_TE, ENABLE);// 开启串口DMA接收USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); // 使能DMADMA_Cmd (USART1_RX_DMA_STREAM,ENABLE);
}信号量
extern SemaphoreHandle_t BinarySem_Handle;void Uart_DMA_Rx_Data(void)
{BaseType_t pxHigherPriorityTaskWoken;// 关闭DMA ,防止干扰DMA_Cmd(USART1_RX_DMA_STREAM, DISABLE);      // 清DMA标志位DMA_ClearFlag(USART1_RX_DMA_STREAM,DMA_FLAG_TCIF2);         //  重新赋值计数值,必须大于等于最大可能接收到的数据帧数目DMA_SetCurrDataCounter(USART1_RX_DMA_STREAM,REVBUFF_SIZE);     DMA_Cmd(USART1_RX_DMA_STREAM, ENABLE);       /* xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);*///给出二值信号量 ,发送接收到新数据标志,供前台程序查询xSemaphoreGiveFromISR(BinarySem_Handle,&pxHigherPriorityTaskWoken);	//释放二值信号量//如果需要的话进行一次任务切换,系统会判断是否需要进行切换portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);}

bsp_DMA.h

/*存储器到外设串口1TX*/
#define USART1_DR_BASE               (uint32_t)(&USART1->DR)		//数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define SENDBUFF_SIZE                5000				//发送的数据量  小于65535#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2	
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_TX_DMA_STREAM            DMA2_Stream7        //数据流 7
/*存储器到外设串口1RX*/
#define USART1_DR_BASE              (uint32_t)(&USART1->DR)		//数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define REVBUFF_SIZE                 5000				//接收的数据量  小于65535#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2	
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_RX_DMA_STREAM         DMA2_Stream2        //数据流 2void USART1_TX_DMA_Config(void);
void USART1_RX_DMA_Config(void);
void Uart_DMA_Rx_Data(void);

五、主函数

/********************************************************************************* @file    main.c* @author  Sumjess* @version V1.0* @date    2019-09-xx* @brief   MDK5.27******************************************************************************* @attention** 实验平台   :STM32 F429 * CSDN Blog  :https://blog.csdn.net/qq_38351824* 微信公众号 :Tech云********************************************************************************//*
*************************************************************************
*                             包含的头文件
*************************************************************************
*/
/* 标准库头文件 */
#include <string.h>/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"        //消息队列
#include "semphr.h"       //信号量、互斥信号量
#include "event_groups.h" //事件
#include "timers.h"       //软件定时器/* 开发板硬件bsp头文件 */
#include "sum_common.h"                  
#include "limits.h"       //任务通知使用的
/**************************** 任务句柄 ********************************/
/* * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么* 这个句柄可以为NULL。*/
static TaskHandle_t AppTaskCreate_Handle = NULL;/* 创建任务句柄 */static TaskHandle_t LED_Task_Handle = NULL;/* LED_Task任务句柄 */
static TaskHandle_t Uart_Task_Handle = NULL;/* KEY任务句柄 *//********************************** 内核对象句柄 *********************************/
/** 信号量,消息队列,事件标志组,软件定时器这些都属于内核的对象,要想使用这些内核* 对象,必须先创建,创建成功之后会返回一个相应的句柄。实际上就是一个指针,后续我* 们就可以通过这个句柄操作这些内核对象。** 内核对象说白了就是一种全局的数据结构,通过这些数据结构我们可以实现任务间的通信,* 任务间的事件同步等各种功能。至于这些功能的实现我们是通过调用这些内核对象的函数* 来完成的* */SemaphoreHandle_t BinarySem_Handle =NULL;   //二值信号量/******************************* 全局变量声明 ************************************/
/** 当我们在写应用程序的时候,可能需要用到一些全局变量。*/
extern char RevBuff[REVBUFF_SIZE];/********************************** 宏定义 **************************************/
/** 当我们在写应用程序的时候,可能需要用到一些宏定义。*//*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */static void LED_Task(void* pvParameters);/* LED_Task任务实现 */
static void Uart_Task(void* pvParameters);/* KEY_Task任务实现 */static void BSP_Init(void);/* 用于初始化板载相关资源 *//****************************************************************** @brief  主函数* @param  无* @retval 无* @note   第一步:开发板硬件初始化 第二步:创建APP应用任务第三步:启动FreeRTOS,开始多任务调度****************************************************************/
int main(void)
{	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS *//* 开发板硬件初始化 */BSP_Init();printf("开发板硬件初始化完毕!\r\n");/* 创建AppTaskCreate任务 */xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数---即任务函数的名称,需要我们自己定义并且实现。*/(const char*    )"AppTaskCreate",/* 任务名字---字符串形式, 最大长度由 FreeRTOSConfig.h 中定义的configMAX_TASK_NAME_LEN 宏指定,多余部分会被自动截掉,这里任务名字最好要与任务函数入口名字一致,方便进行调试。*/(uint16_t       )512,  /* 任务栈大小---字符串形式, 最大长度由 FreeRTOSConfig.h 中定义的configMAX_TASK_NAME_LEN 宏指定,多余部分会被自动截掉,这里任务名字最好要与任务函数入口名字一致,方便进行调试。*/(void*          )NULL,/* 任务入口函数参数---字符串形式, 最大长度由 FreeRTOSConfig.h 中定义的configMAX_TASK_NAME_LEN 宏指定,多余部分会被自动截掉,这里任务名字最好要与任务函数入口名字一致,方便进行调试。*/(UBaseType_t    )1, /* 任务的优先级---优先级范围根据 FreeRTOSConfig.h 中的宏configMAX_PRIORITIES 决定, 如果使能 configUSE_PORT_OPTIMISED_TASK_SELECTION,这个宏定义,则最多支持 32 个优先级;如果不用特殊方法查找下一个运行的任务,那么则不强制要求限制最大可用优先级数目。在 FreeRTOS 中, 数值越大优先级越高, 0 代表最低优先级。*/(TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针---在使用内存的时候,需要给任务初始化函数xTaskCreateStatic()传递预先定义好的任务控制块的指针。在使用动态内存的时候,任务创建函数 xTaskCreate()会返回一个指针指向任务控制块,该任务控制块是 xTaskCreate()函数里面动态分配的一块内存。*/ /* 启动任务调度 */           if(pdPASS == xReturn)vTaskStartScheduler();   /* 启动任务,开启调度 */elsereturn -1;  while(1);   /* 正常不会执行到这里 */    
}/************************************************************************ @ 函数名  : AppTaskCreate* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面* @ 参数    : 无  * @ 返回值  : 无**********************************************************************/
static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */taskENTER_CRITICAL();           //进入临界区///  /* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */(const char*    )"LED_Task",/* 任务名字 */(uint16_t       )512,   /* 任务栈大小 */(void*          )NULL,	/* 任务入口函数参数 */(UBaseType_t    )2,	    /* 任务的优先级 */(TaskHandle_t*  )&LED_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn)printf("创建LED_Task任务成功\r\n");  
////* 创建 BinarySem */BinarySem_Handle = xSemaphoreCreateBinary();	 if(NULL != BinarySem_Handle)printf("BinarySem_Handle二值信号量创建成功!\r\n");/* 创建Uart_Task任务 */xReturn = xTaskCreate((TaskFunction_t )Uart_Task,  /* 任务入口函数 */(const char*    )"Uart_Task",/* 任务名字 */(uint16_t       )512,  /* 任务栈大小 */(void*          )NULL,/* 任务入口函数参数 */(UBaseType_t    )3, /* 任务的优先级 */(TaskHandle_t*  )&Uart_Task_Handle);/* 任务控制块指针 */ if(pdPASS == xReturn)printf("创建Uart_Task任务成功!\r\n");
///vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务taskEXIT_CRITICAL();            //退出临界区
}/*********************************************************************** @ 函数名  : LED_Task* @ 功能说明: LED_Task任务主体* @ 参数    :   * @ 返回值  : 无********************************************************************/
static void LED_Task(void* parameter)
{	while (1){LED1_ON;vTaskDelay(500);   /* 延时500个tick */printf("LED_Task Running,LED1_ON\r\n");LED1_OFF;     vTaskDelay(500);   /* 延时500个tick */		 		printf("LED_Task Running,LED1_OFF\r\n");}
}
/*********************************************************************** @ 函数名  : LED_Task* @ 功能说明: LED_Task任务主体* @ 参数    :   * @ 返回值  : 无********************************************************************/
static void Uart_Task(void* parameter)
{	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */while (1){//获取二值信号量 xSemaphore,没获取到则一直等待xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */portMAX_DELAY); /* 等待时间 */if(pdPASS == xReturn){LED2_TOGGLE;printf("收到数据:%s\r\n",RevBuff);memset(RevBuff,0,REVBUFF_SIZE);/* 清零 */}}                     
}/************************************************************************ @ 函数名  : BSP_Init* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面* @ 参数    :   * @ 返回值  : 无*********************************************************************/
static void BSP_Init(void)
{/** STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,* 都统一用这个优先级分组,千万不要再分组,切忌。*/NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );/* LED 初始化 */LED_GPIO_Config();/* 串口初始化	*/Debug_USART_Config();/* 按键初始化	*/Key_GPIO_Config();/* DMA初始化	*/USART1_RX_DMA_Config();}/********************************END OF FILE****************************/

 

 

  相关解决方案