移植步骤
1、下载FreeRTOS
2、在项目中建立目录freeRTOS
3、将FreeRTOS/Source文件夹转移到项目中的freeRTOS
4、根据平台的不同复制portable
文件,拷贝到freeRTOS
中
- 源文件
port.c
拷贝到freeRTOS
- 头文件
portmacro.h
拷贝到freeRTOS/include
下
STM32F103(Cortex-M3)对应的是在
portable/RVDS/ARM_CM3
中
5、工程中添加头文件对应的路径、添加源文件
6、编译,报错说:不能打开FreeRTOSConfig.h头文件。
我们需要到Demo文件夹处找到与我们单片机型号相同或相似的Demo,这里在
FreeRTOS/Demo/CORTEX_STM32F103_Keil
文件夹内可找到FreeRTOSConfig.h
文件
7、编译,提示:
Error: L6218E: Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o).
实际上TaskHandle_t xTaskGetCurrentTaskHandle
是用于获取当前任务句柄。
在文件FreeRTOSConfig.h中,宏INCLUDE_xTaskGetCurrentTaskHandle必须设置为1,此函数才有效。
所以只要在FreeRTOSConfig.h
中加入这句话即可:
#define INCLUDE_xTaskGetCurrentTaskHandle 1
8、重新编译,提示:
Error: L6218E: Undefined symbol pvPortMalloc (referred from event_groups.o).
Error: L6218E: Undefined symbol vPortFree (referred from event_groups.o).
这是因为我们没有选择堆内存管理方式,portable/MemMang
中的每一个文件对应一种方式,拷贝出来,这里选择heap_4.c
。
9、仿真在线运行,发现调用vTaskStartScheduler
进入了HardFault_Handler
。
需要:修改中断向量指向RTOS-port.c文件中定义函数入口
打开startup_stm32f10x_hd.s
文件
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
;添加这3行
IMPORT xPortPendSVHandler
IMPORT xPortSysTickHandler
IMPORT vPortSVCHandler
; 结束
PRESERVE8
THUMB
; 将 SVC_Handler 改为 vPortSVHandler
;DCD SVC_Handler ; SVCall Handler
DCD vPortSVCHandler ; SVCall Handler
; 将 PendSV_Handler 改为 xPortPendSVHandler
;DCD PendSV_Handler ; PendSV Handler
DCD xPortPendSVHandler ; PendSV Handler
; 将 SysTick_Handler 改为 xPortSysTickHandler
;DCD SysTick_Handler ; SysTick Handler
DCD xPortSysTickHandler ; SysTick Handler
简单的例程
下面的代码实现了创建一个任务,并定期打印。
添加下列代码
#if 1 // 使用printf
#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
/* 重定向printf*/
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart2, (uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
/* 重定向scanf */
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart2, &ch, 1, 0xffff);
return ch;
}
#endif
#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)
{
while(1)
{
vTaskDelay(200);
printf("start_task\r\n");
}
}
int main(void)
{
// HAL_Init(); // 如果Systick没有改为其他时钟源,则运行异常。需要注释掉。
SystemClock_Config();
MX_USART2_UART_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(); //开启任务调度
}