KeilMDK环境 stm32f10x快速移值FreeRTOS
stm32f10x快速移值FreeRTOS
FreeRTOS由于其短小精悍,开源免费被广泛的应用。在使用FreeRTOS之前不可避免的就是移值。在这里分享一个快速简单、亲测可用的freertos移值教程。其他类型的编译器和单片机也可做为参考。
准备工作
在进行FreeRTOS移值之前首先得先拿到FreeRTOS源码,并分析它得目录结构。
源码可以在FreeRTOS官网获得,下载下来为一个可执行文件,双击解压可获得源码。
我们将要使用的是FreeRTOS里的文件,另一个FreeRTOS-Plus不必管它,它包含了FreeRTOS的其他一下可选和扩展功能。
Demo文件夹包含了官方提供的大量的基于不同硬件和编译器的例程,有很大的参考价值。在移值程序的时候可以用到。
Source里包含了移值所必须的文件如下图:
红框标出的是操作系统内核正常工作所需要的必要文件。其他的为一些可选功能:事件组,协程,软件定时器等。
include为头文件需要在工程中包含该文件夹。
protable文件夹中的文件不是所有是必须的,只需要选择对应处理器和平台的文件夹中的文件使用即可。
框选出来的为必须选的,MemMang中的heap_x.c是不同的内存管理方案,任意选择一种即可,这里选择heap_4.c,关于他们之间的差异可以自行百度。
由于在Keil文件夹下See-also-the-RVDS-directory.txt文件明确说了去RVDS找,于是乎还需要RVDS文件夹中的 \RVDS\ARM_CM3文件夹中的源代码。
最后需要准备的是例程里的FreeRTOSConfig.h源码,这个头文件已经将大部分配置工作给做好了,大大简化了移值。可以在 \FreeRTOS\Demo\CORTEX_STM32F103_Keil找到。
到这里需要的文件就准备齐了。将他们复制到已有的工程目录下,然后添加进工程,并包含头文件所在位置。如图所示:
添加源文件到工程里面。并索引头文件所在位置。
移值
添加完程序,还需要少量修改。
将一些中断向量交给操作系统内核管理
在 FreeRTOSConfig.h中添加宏定义:
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
为了避免重定义,我们将stm32f10x_it.h中的申明给注释掉。
然后进行编译。
测试程序
#include "stm32f10x.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//定义相关参数
#define START_TASK_PRIO 1
#define START_STK_SIZE 128
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
#define LED0_TASK_PRIO 2
#define LED0_STK_SIZE 50
TaskHandle_t LED0Task_Handler;
void led0_task(void *pvParameters);
#define LED1_TASK_PRIO 3
#define LED1_STK_SIZE 50
TaskHandle_t LED1Task_Handler;
void led1_task(void *pvParameters);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
uart_init(115200);
LED_Init();
xTaskCreate((TaskFunction_t )start_task, //创建开始任务
(const char* )"start_task",
(uint16_t )START_STK_SIZE,
(void* )NULL,
(UBaseType_t )START_TASK_PRIO,
(TaskHandle_t* )&StartTask_Handler);
vTaskStartScheduler();
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
xTaskCreate((TaskFunction_t )led0_task, //创建led0任务
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
xTaskCreate((TaskFunction_t )led1_task, //创建led1任务
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
vTaskDelete(StartTask_Handler);//删除开始任务
taskEXIT_CRITICAL(); //推出临界区
}
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
}
}
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
一共创建三个任务,在开始任务中创建了led0闪烁和led1闪烁任务。然后在主函数中创建开始任务,并删除开始任务,最后启动任务调度。
总结
统过宏定义的方法,可以免去在启动文件中进行修改,简单快速。提高开发效率。