[应用相关] 基于STM32使用HAL库手把手移植FreeRTOS10.4.1

[复制链接]
3124|50
 楼主| paotangsan 发表于 2021-7-4 16:41 | 显示全部楼层 |阅读模式
(一)裸机工程创建

使用STM32CubeMX创建裸机工程:

这里我是用的芯片是STM32F103RBT6,时钟主频为72MHz,配置时钟树:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg


 楼主| paotangsan 发表于 2021-7-4 16:41 | 显示全部楼层

配置调试串口1:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg


 楼主| paotangsan 发表于 2021-7-4 16:42 | 显示全部楼层
配置两个LED灯:

4967460e1745e7fdc7.png
由于FreeRTOS使用系统嘀嗒定时器当作心跳,HAL库也使用了这个定时器当作超时计数用,如果使用STM32CUBEMX直接加入freertos会提示SysTim定时器和freertos冲突,由于现在我们是手动移植freertos所以可以同时将systim用为hal库的超时定时器和和freertos的心跳。


 楼主| paotangsan 发表于 2021-7-4 16:42 | 显示全部楼层

配置中断,注意这里一定要选择组4,也就是全部为抢占优先级:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg



 楼主| paotangsan 发表于 2021-7-4 16:42 | 显示全部楼层

输出工程:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg


 楼主| paotangsan 发表于 2021-7-4 16:42 | 显示全部楼层
(二)移植FreeRTOS

解压FreeRTOS源码包有如下文件结构:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg

在Keil工程目录下新建FreeRTOS文件夹用于存放freertos的源码。


 楼主| paotangsan 发表于 2021-7-4 16:42 | 显示全部楼层
拷贝FreeRTOS/Source/文件夹内的以下文件,放入keil工程目录FreeRTOS文件夹内,效果如下图:
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg

 楼主| paotangsan 发表于 2021-7-4 16:43 | 显示全部楼层

在Keil中将FreeRTOS源码加入到工程内:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxMTUzNDcxNTAz,size_16,color_FFFFFF,t_70#pic_center.jpg


 楼主| paotangsan 发表于 2021-7-4 16:43 | 显示全部楼层
打开stm32f1xx_it.c文件,在头部添加FreeRTOS的三个函数导入:

extern void xPortPendSVHandler(void);
extern void xPortSysTickHandler(void);
extern void vPortSVCHandler(void);
7487560e174b0bc165.png

 楼主| paotangsan 发表于 2021-7-4 16:43 | 显示全部楼层

在函数SVC_Handler中添加函数调用:

2884260e174dd9b006.png


 楼主| paotangsan 发表于 2021-7-4 16:43 | 显示全部楼层
在函数PendSV_Handler中添加函数调用:
3214260e174e966e6f.png
 楼主| paotangsan 发表于 2021-7-4 16:44 | 显示全部楼层
在函数SysTick_Handler中添加函数调用:
20210107114227568.png
 楼主| paotangsan 发表于 2021-7-4 16:45 | 显示全部楼层
新建一个名为FreeRTOSConfig.h的文件,这是FreeRTOS的配置文件,这里我贴一个我配置的:

#ifndef FREERTOS_CONFIG_H__
#define FREERTOS_CONFIG_H__

/*
* 关于本文件宏的详细说明可参考:https://blog.csdn.net/zhzht19861011/article/details/50134883#
*/

// 设置为1使用抢占式,为0使用时间片轮转调度。
#define configUSE_PREEMPTION                    1

// 设置为1使能低功耗tickless模式,为0保持系统节拍(tick)中断一直运行。
#define configUSE_TICKLESS_IDLE                 0

// 系统时钟主频
#define configCPU_CLOCK_HZ                      72000000

// 系统节拍中断的频率,即1s进中断的次数,配置为1000就是一秒进1000次中断,系统节拍就是1s。
#define configTICK_RATE_HZ                      1000

// 任务最大优先级
#define configMAX_PRIORITIES                    10

// 任务最小栈大小
#define configMINIMAL_STACK_SIZE                64

// FreeRTOR堆空间大小
#define configTOTAL_HEAP_SIZE                   8192

// 任务名称最大长度
#define configMAX_TASK_NAME_LEN                 16

// 系统节拍计数器的变量类型,即定义portTickType是表示16位变量还是32位变量。
#define configUSE_16_BIT_TICKS                  0

// 设置为1允许任务调度,为0不允许(时间片耗尽才让出CPU使用权),该参数抢占式方式下才生效
#define configIDLE_SHOULD_YIELD                 1

// 设置是否使用互斥量
#define configUSE_MUTEXES                       1

// 设置是否使用递归互斥量
#define configUSE_RECURSIVE_MUTEXES             0

// 设置是否使用计数信号量
#define configUSE_COUNTING_SEMAPHORES           0

// 设置可以记录的队列和信号量的最大数目
#define configQUEUE_REGISTRY_SIZE               10

// 是否使用空闲钩子函数
#define configUSE_IDLE_HOOK                     0

// 是否使用TICK嘀嗒钩子函数
#define configUSE_TICK_HOOK                     0

// 是否使用栈溢出检查
#define configCHECK_FOR_STACK_OVERFLOW          0

// 是否使用内存申请失败钩子函数
#define configUSE_MALLOC_FAILED_HOOK            0

// 是否使用软件定时器
#define configUSE_TIMERS                        1

// 设置软件定时器服务/守护进程的优先级
#define configTIMER_TASK_PRIORITY               3

// 设置软件定时器命令队列的长度
#define configTIMER_QUEUE_LENGTH                10

// 设置软件定时器服务/守护进程任务的堆栈深度
#define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE

// STM32的最低优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15

// 能够在中断服务函数中安全调用FreeRTOS API的中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1

#define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << 4 )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY         ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4 )


// 将以下定义设置为1以包含API函数,或设置为0排除API函数
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet               1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_xResumeFromISR                  1
#define INCLUDE_vTaskDelayUntil                 1
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_xTaskGetSchedulerState          1
#define INCLUDE_xTaskGetCurrentTaskHandle       1
#define INCLUDE_uxTaskGetStackHighWaterMark     0
#define INCLUDE_xTaskGetIdleTaskHandle          0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle  0
#define INCLUDE_pcTaskGetTaskName               0
#define INCLUDE_eTaskGetState                   0
#define INCLUDE_xEventGroupSetBitFromISR        1
#define INCLUDE_xTimerPendFunctionCall          0

#endif  /* FREERTOS_CONFIG_H__ */


 楼主| paotangsan 发表于 2021-7-4 16:45 | 显示全部楼层

修改main.c文件,添加头文件:


#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"


#include "task.h"


 楼主| paotangsan 发表于 2021-7-4 16:46 | 显示全部楼层
这里我创建了三个任务,任务一为led1灯每间隔500ms闪烁一次,任务二led2每间隔300ms闪烁一次,任务三为串口每隔1s打印一次helloworld。


void led1_task(void* arg)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
        vTaskDelay(500);
    }
}

void led2_task(void* arg)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
        vTaskDelay(300);
    }
}

void print_task(void* arg)
{
    while(1)
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)"HelloWorld\r\n", 12, 100);
        vTaskDelay(1000);
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();

        // xTaskCreate函数参数说明:
        // 1、任务入口函数
        // 2、任务名称
        // 3、堆栈大小,单位word
        // 4、传递给任务的参数
        // 5、任务优先级
        // 6、任务句柄
       
        // 创建任务led1灯任务
    xTaskCreate(led1_task, "led1_task", 64, NULL, 3, NULL);
       
        // 创建任务led2灯任务
        xTaskCreate(led2_task, "led2_task", 64, NULL, 4, NULL);
       
        // 创建串口打印任务
    xTaskCreate(print_task, "print_task", 128, NULL, 5, NULL);

        // 启动任务调度
    vTaskStartScheduler();

    while (1)
    {
    }
}



到此,移植完毕!


评论

楼主,请问我的三个任务只执行了一遍就不执行了,但是只创建一个任务就可以重复执行这是为什么呢?应该如何解决呢,我是用的是FreeRTOS 202112.00  发表于 2022-4-15 00:09
Jacquetry 发表于 2022-10-5 21:25 | 显示全部楼层
学习到了
Uriah 发表于 2022-10-7 11:30 | 显示全部楼层

会以switch-case的方式出现
Bblythe 发表于 2022-10-7 14:29 | 显示全部楼层

在实际的项目应用当中,单片机引脚的复用相当厉害
Pulitzer 发表于 2022-10-7 17:28 | 显示全部楼层

USART1可以有多个时钟源
backlugin 发表于 2022-10-23 14:14 | 显示全部楼层
stm32 跑 FreeRTOS 要多大的Flash比较好?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

80

主题

4345

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部