[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
* 模块名称 : 主程序模块。
* 文件名称 : main.c
* 版 本 : V1.0
* 说 明 : 本实验主要学习FreeRTOS的定时器组
* 实验目的:
* 1. 学习FreeRTOS的定时器组
* 实验内容:
* 1. 按下按键K1可以通过串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)
* =================================================
* 任务名 任务状态 优先级 剩余栈 任务序号
* vTaskUserIF R 1 320 1
* IDLE R 0 117 5
* Tmr Svc B 2 224 6
* vTaskMsgPro B 3 483 3
* vTaskLED B 2 483 2
* vTaskStart B 4 489 4
*
* 任务名 运行计数 使用率
* vTaskUserIF 641 <1%
* IDLE 171716 99%
* vTaskMsgPro 0 <1%
* vTaskLED 0 <1%
* vTaskStart 1 <1%
* Tmr Svc 43 <1%
* 串口软件建议使用SecureCRT(V6光盘里面有此软件)查看打印信息。
* 各个任务实现的功能如下:
* vTaskTaskUserIF 任务: 接口消息处理
* vTaskLED 任务: LED闪烁
* vTaskMsgPro 任务: 消息处理,这里用作LED闪烁
* vTaskStart 任务: 启动任务,也就是最高优先级任务,这里实现按键扫描
* 2. 任务运行状态的定义如下,跟上面串口打印字母B, R, D, S对应:
* #define tskBLOCKED_CHAR ( 'B' ) 阻塞
* #define tskREADY_CHAR ( 'R' ) 就绪
* #define tskDELETED_CHAR ( 'D' ) 删除
* #define tskSUSPENDED_CHAR ( 'S' ) 挂起
* 3. 创建两个软件定时器。
* 注意事项:
* 1. 本实验推荐使用串口软件SecureCRT,要不串口打印效果不整齐。此软件在
* V6开发板光盘里面有。
* 2. 务必将编辑器的缩进参数和TAB设置为4来阅读本文件,要不代码显示不整齐。
*
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2016-03-15 Eric2013 1. ST固件库到V1.6.1版本
* 2. BSP驱动包V1.2
* 3. FreeRTOS版本V8.2.3
*
* Copyright (C), 2016-2020, 安富莱电子 [url]www.armfly.com[/url]
*
*********************************************************************************************************
*/
#include "includes.h"
/*
**********************************************************************************************************
函数声明
**********************************************************************************************************
*/
static void vTaskTaskUserIF(void *pvParameters);
static void vTaskLED(void *pvParameters);
static void vTaskMsgPro(void *pvParameters);
static void vTaskStart(void *pvParameters);
static void AppTaskCreate (void);
static void AppObjCreate (void);
static void vTimerCallback(xTimerHandle pxTimer);
/*
**********************************************************************************************************
变量声明
**********************************************************************************************************
*/
static TaskHandle_t xHandleTaskUserIF = NULL;
static TaskHandle_t xHandleTaskLED = NULL;
static TaskHandle_t xHandleTaskMsgPro = NULL;
static TaskHandle_t xHandleTaskStart = NULL;
static TimerHandle_t xTimers[2] = {NULL};
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: 标准c程序入口。
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
int main(void)
{
/*
在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
这样做的好处是:
1. 防止执行的中断服务程序中有FreeRTOS的API函数。
2. 保证系统正常启动,不受别的中断影响。
3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
和cpsie i是等效的。
*/
__set_PRIMASK(1);
/* 硬件初始化 */
bsp_Init();
/* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
目中不要使用,因为这个功能比较影响系统实时性。
2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
*/
vSetupSysInfoTest();
/* 创建任务 */
AppTaskCreate();
/* 创建任务通信机制 */
AppObjCreate();
/* 启动调度,开始执行任务 */
vTaskStartScheduler();
/*
如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
*/
while(1);
}
/*
*********************************************************************************************************
* 函 数 名: vTaskTaskUserIF
* 功能说明: 接口消息处理。
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
*********************************************************************************************************
*/
static void vTaskTaskUserIF(void *pvParameters)
{
uint8_t ucKeyCode;
uint8_t pcWriteBuffer[500];
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
/* K1键按下 打印任务执行情况 */
case KEY_DOWN_K1:
printf("=================================================\r\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
printf("\r\n任务名 运行计数 使用率\r\n");
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
break;
/* 其他的键值不处理 */
default:
break;
}
}
vTaskDelay(20);
}
}
/*
*********************************************************************************************************
* 函 数 名: vTaskLED
* 功能说明: LED闪烁
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 2
*********************************************************************************************************
*/
static void vTaskLED(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 200;
/* 获取当前的系统时间 */
xLastWakeTime = xTaskGetTickCount();
while(1)
{
bsp_LedToggle(3);
/* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
/*
*********************************************************************************************************
* 函 数 名: vTaskMsgPro
* 功能说明: 消息处理,这里用作LED闪烁
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 3
*********************************************************************************************************
*/
static void vTaskMsgPro(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 200;
/* 获取当前的系统时间 */
xLastWakeTime = xTaskGetTickCount();
while(1)
{
bsp_LedToggle(4);
/* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
/*
*********************************************************************************************************
* 函 数 名: vTaskStart
* 功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 4
*********************************************************************************************************
*/
static void vTaskStart(void *pvParameters)
{
while(1)
{
/* 按键扫描 */
bsp_KeyScan();
vTaskDelay(10);
}
}
/*
*********************************************************************************************************
* 函 数 名: AppTaskCreate
* 功能说明: 创建应用任务
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
xTaskCreate( vTaskTaskUserIF, /* 任务函数 */
"vTaskUserIF", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
1, /* 任务优先级*/
&xHandleTaskUserIF ); /* 任务句柄 */
xTaskCreate( vTaskLED, /* 任务函数 */
"vTaskLED", /* 任务名 */
512, /* stack大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
2, /* 任务优先级*/
&xHandleTaskLED ); /* 任务句柄 */
xTaskCreate( vTaskMsgPro, /* 任务函数 */
"vTaskMsgPro", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
3, /* 任务优先级*/
&xHandleTaskMsgPro ); /* 任务句柄 */
xTaskCreate( vTaskStart, /* 任务函数 */
"vTaskStart", /* 任务名 */
512, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
4, /* 任务优先级*/
&xHandleTaskStart ); /* 任务句柄 */
}
/*
*********************************************************************************************************
* 函 数 名: AppObjCreate
* 功能说明: 创建任务通信机制
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
uint8_t i;
const TickType_t xTimerPer[2] = {100, 100};
static void AppObjCreate (void)
{
/*
1. 创建定时器,如果在RTOS调度开始前初始化定时器,那么系统启动后才会执行。
2. 统一初始化两个定时器,他们使用共同的回调函数,在回调函数中通过定时器ID来区分
是那个定时器的时间到。当然,使用不同的回调函数也是没问题的。
*/
for(i = 0; i < 1; i++)
{
xTimers[i] = xTimerCreate("Timer", /* 定时器名字 */
xTimerPer[i], /* 定时器周期,单位时钟节拍 */
pdFALSE, /* 周期性 */
(void *) i, /* 定时器ID */
vTimerCallback); /* 定时器回调函数 */
if(xTimers[i] == NULL)
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
}
else
{
/* 启动定时器,系统启动后才开始工作 */
if(xTimerStart(xTimers[i], 100) != pdPASS)
{
/* 定时器还没有进入激活状态 */
}
}
}
}
/*
*********************************************************************************************************
* 函 数 名: vTimerCallback
* 功能说明: 定时器回调函数
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void vTimerCallback(xTimerHandle pxTimer)
{
uint32_t ulTimerID;
configASSERT(pxTimer);
/* 获取那个定时器时间到 */
ulTimerID = (uint32_t)pvTimerGetTimerID(pxTimer);
/* 处理定时器0任务 */
if(ulTimerID == 0)
{
// bsp_LedToggle(1);
for(i = 1; i < 2; i++)
{
xTimers[i] = xTimerCreate("Timer", /* 定时器名字 */
xTimerPer[i], /* 定时器周期,单位时钟节拍 */
pdFALSE, /* 周期性 */
(void *) i, /* 定时器ID */
vTimerCallback); /* 定时器回调函数 */
if(xTimers[i] == NULL)
{
printf("ulTimerID000");
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
}
else
{
/* 启动定时器,系统启动后才开始工作 */
if(xTimerStart(xTimers[i], 100) != pdPASS)
{
/* 定时器还没有进入激活状态 */
printf("ulTimerID1111");
}
}
}
}
/* 处理定时器1任务 */
if(ulTimerID == 1)
{
printf("ulTimerID333");
bsp_LedToggle(2);
}
}
/***************************** 安富莱电子 [url]www.armfly.com[/url] (END OF FILE) *********************************/