梳理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中断的一些注意事项:
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
//---------------------------------------------------------------------------------------------//
//////////////////////////////////////////////////////////
//① 重定向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等函数
/* 声明引用外部二值信号量 */
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 );
}
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);
// 使能DMA
DMA_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 //数据流 2
void 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
/* 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(); /* 启动任务,开启调度 */
else
return -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****************************/