手把手教你在STM32F4上跑freeRTOS!

本文详细介绍了如何在STM32F407开发板上使用freeRTOS建立一个基础工程,并实现通过两个任务交替闪烁LED灯的效果。首先,从freeRTOS官网下载源码和移植例程,然后在IAR for ARM环境中创建新工程,添加必要的库文件和配置。接着,配置工程的包含路径和宏定义,最后编写LED初始化及任务代码,启动任务调度器。通过这个实例,读者可以了解freeRTOS在STM32上的初步应用。
摘要由CSDN通过智能技术生成

[导读] 大家好,我是逸珺。

之前挖了图解freeRTOS的坑,挖了坑就得填。今天就从使用开始,先把freeRTOS用起来。先聊一聊在STM32F407上的如何电灯,如果只用freeRTOS点灯,无疑有点杀鸡用牛刀的感觉。但是想用freeRTOS做产品,先照类似步骤则可以验证最小系统,验证freeRTOS是否能正确跑起来,再在此基础上开始做应用开发,就把任务分解了。本文主要梳理一下如何利用官方移植例子,创建一个自己demo工程,对于没用过的有点参考价值。

注:本文基于IAR for ARM 8.22.1(个人喜欢IAR),硬件采用正点原子的STM32F407探索者开发板,STLink V2。

准备工作

去官网https://www.freertos.org/a00104.html下载:

按图中所示下载,目前最新为202104.00,这个带多种移植好的例子。解压出来,是这样的:

  • tools为AWS iot配置工具,quick start例子以及cmake

  • FreeRTOS-Plus包含了MQTT,TCP,FAT等很多例子,先不去管

  • FreeRTOS为真正的操作系统源码以及多平台移植例子,如下:

使用开源软件,记得看看README,一般会有些介绍信息。分别介绍一下该文件夹下的大体内容:
  1. Demo:大部分硬件平台的官方移植例子

  2. Source:内核代码,包含硬件独立文件与可移植文件

  3. Test:内核测试代码

  4. license:MIT开源协议,可以直接商业应用。

建立工程

1.打开IAR,创建Workspace

2.创建工程

选择空工程(Empty project),命名为demo保存。

  1. 设置工程

    右键选择Options,进入设置界面设置单片机为STM32F407VGLibrary Configuration使能CMSIS

  2. 添加源文件

    4.1 新建freeRTOS文件夹4.2 添加内核文件,在工程文件夹下新建freeRTOS文件夹,将下列文件拷贝过来

4.3 添加进IAR工程

4.4 将freeRTOS下的include文件夹以及portable文件夹拷贝到当前工程下

4.5 portable文件夹下保留下面这几个文件夹

4.6 IAR文件夹下保留下面这两个文件夹

注:全保留也可以,就是其他的用不到,会使工程文件夹变的很大,如果用版本控制软件管理,会增加仓库的大小。ARM_CM4F_MPU文件夹暂时没用,这个留做备用。

4.7 在IAR工程中新建portable文件夹,并加入相应的文件

4.8 将下面几个文件从官方例子中拷贝过来,并加入工程

FreeRTOSConfig.h是内核配置文件,本文配置如下:

  • #define configUSE_PREEMPTION   1
    #define configUSE_IDLE_HOOK    0
    #define configUSE_TICK_HOOK    0
    #define configCPU_CLOCK_HZ    ( SystemCoreClock )
    #define configTICK_RATE_HZ    ( ( TickType_t ) 1000 )
    #define configMAX_PRIORITIES   ( 5 )
    #define configMINIMAL_STACK_SIZE  ( ( unsigned short ) 130 )
    #define configTOTAL_HEAP_SIZE   ( ( size_t ) ( 75 * 1024 ) )
    #define configMAX_TASK_NAME_LEN   ( 10 )
    #define configUSE_TRACE_FACILITY  1
    #define configUSE_16_BIT_TICKS   0
    #define configIDLE_SHOULD_YIELD   1
    #define configUSE_MUTEXES    1
    #define configQUEUE_REGISTRY_SIZE  8
    #define configCHECK_FOR_STACK_OVERFLOW 0
    #define configUSE_RECURSIVE_MUTEXES  1
    #define configUSE_MALLOC_FAILED_HOOK 0
    #define configUSE_APPLICATION_TASK_TAG 0
    #define configUSE_COUNTING_SEMAPHORES 1
    #define configGENERATE_RUN_TIME_STATS 0
    
    /* Co-routine definitions. */
    #define configUSE_CO_ROUTINES   0
    #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
    
    /* Software timer definitions. */
    #define configUSE_TIMERS    1
    #define configTIMER_TASK_PRIORITY  ( 2 )
    #define configTIMER_QUEUE_LENGTH  10
    #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
    
    /* Set the following definitions to 1 to include the API function, or zero
    to exclude the API function. */
    #define INCLUDE_vTaskPrioritySet  1
    #define INCLUDE_uxTaskPriorityGet  1
    #define INCLUDE_vTaskDelete    1
    #define INCLUDE_vTaskCleanUpResources 1
    #define INCLUDE_vTaskSuspend   1
    #define INCLUDE_vTaskDelayUntil   1
    #define INCLUDE_vTaskDelay    1
    

    将IDLE_HOOK/TICK_HOOK禁止了,先不去关注这两个功能。

  • 将STM32相关文件搬过来,如下加入到工程

  • 建立main.c

    正点原子的板子,有两个LED,我们就建立两个任务来闪灯吧,相当于hello world,容易理解。

    /* 操作系统头文件. */
    #include "FreeRTOS.h"
    #include "task.h"
    #include "timers.h"
    #include "semphr.h"
    
    #include "stm32f4xx.h"
    //LED管脚
    #define LED1_PIN        GPIO_Pin_9
    #define LED1_GPIO_PORT    GPIOF
    #define LED1_GPIO_CLK     RCC_AHB1Periph_GPIOF  
      
    #define LED2_PIN       GPIO_Pin_10
    #define LED2_GPIO_PORT    GPIOF
    #define LED2_GPIO_CLK    RCC_AHB1Periph_GPIOF  
    
    static void prvLedInitialise()
    {
      GPIO_InitTypeDef  GPIO_InitStructure;
      
      /* LED1时能时钟 */
      RCC_AHB1PeriphClockCmd(LED1_GPIO_CLK, ENABLE);
      /* LED1 GPIO 配置为输出 */
      GPIO_InitStructure.GPIO_Pin = LED1_PIN;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);  
      
      /* LED2时能时钟 */
      RCC_AHB1PeriphClockCmd(LED2_GPIO_CLK, ENABLE);
      /* LED2 GPIO配置为输出 */
      GPIO_InitStructure.GPIO_Pin = LED2_PIN;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);    
    }
    
    static void prvSetupHardware( void )
    {
      /* 配置时钟,PLL,FLASH */
      SystemInit();
    
      /* 配置NVIC优先级. */
      NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
        
      /*LED GPIO配置*/
      prvLedInitialise();
    }
    
    //500ms LED1灯状态翻转一次
    static void led1Task( void * pvParameters )
    {
      while(1)
      {
         LED1_GPIO_PORT->ODR ^= LED1_PIN;
         vTaskDelay(500);
      }
    }
    //1000ms LED2灯状态翻转一次
    static void led2Task( void * pvParameters )
    {
      while(1)
      {
        LED2_GPIO_PORT->ODR ^= LED2_PIN;
        vTaskDelay(1000);
      }
    }
    
    int main(void)
    {
      prvSetupHardware();
        
      xTaskCreate(led1Task,"LED1",256,NULL,100,(TaskHandle_t *)NULL);
      xTaskCreate(led2Task,"LED2",256,NULL,101,(TaskHandle_t *)NULL);
        
      /* 启动任务调度器. */
      vTaskStartScheduler();    
    }
    

5.设置包含路径

5.1 右键打开options,设置C/C++编译器包含路径

5.2 设置包含路径为:

$PROJECT_DIR$是一个变量,表示当前路径,不要设成绝对路径,否则拷贝到不同路径就无法编译了。

  • $PROJ_DIR$\
    $PROJ_DIR$\hal\CMSIS\Device\ST\STM32F4xx\Include
    $PROJ_DIR$\hal\STM32F4xx_StdPeriph_Driver\inc
    $PROJ_DIR$\freeRTOS\include
    $PROJ_DIR$\freeRTOS\portable\IAR\ARM_CM4F
    $PROJ_DIR$\Common\include示当前工程目录,利用这个变量就可以设置和工程相关的路径了,不要设置为绝对路径,否则如果工程拷贝到其他路径,就无法正确编译了。

    并设置两个宏:

    USE_STDPERIPH_DRIVER
    STM32F4XX
    

5.3 设置汇编器包含路径

6. 设置链接配置文件

注:如果遇到下面的错误,应该是你使用了老版本的startup_stm32f4xx.s

Warning[25]: Label 'CAN2_SCE_IRQHandler' is defined pubweak in a p implicitly declared root 

官方例子中下面路径的startup_stm32f4xx.s为老版本

CMSIS\Device\ST\STM32F4xx\Source\Templates\iar

该警告详细信息可参考:

https://www.iar.com/knowledge/support/technical-notes/assembler/warning25-label-xxxxx-is-defined-pubweak-in-a-p-implicitly-declared-root/

编译运行

设置ST-Link

下载运行

闪灯效果

总结一下

官方的例子,要直接拿来开发产品有很多不需要的文件,可以按照本文的步骤做些删减,先建立这样一个基本工程,然后就可以结合自己的实际硬件以及需求,开始做应用开发了。

1.容器技术,与嵌入式系统有多大关系?

2.@关注RISC-V嵌入式系统开发已久的你

3.聊聊身边的嵌入式,热卖的九阳豆浆机,为什么藏着财富密码?

4.教你动手移植RT-Thread到国产MCU

5.一个小技巧,减少MCU现场的麻烦

6.MCU硬件延时和软件延时有什么区别?

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

DSP和标准外设库: 资源编号 : STSW-STM32065 资源名称 : STM32F4 DSP and standard peripherals library 文件名 : stm32_f105-07_f2_f4_usb-host-device_lib.zip 下载地址 : http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257901# USB库: 资源编号 : STSW-STM32046 资源名称 : STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and device library (UM1021) 文件名 : stm32_f105-07_f2_f4_usb-host-device_lib.zip 下载地址 : http://www.st.com/web/en/catalog/tools/PF257882 ETH以太网库: 资源编号 : STSW-STM32046 资源名称 : LwIP TCP/IP stack demonstration for STM32F4x7 microcontrollers (AN3966) 文件名 : stsw-stm32070.zip 下载地址 : http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257906 【CMSIS】 Cortex微控制器软件接口程序(Cortex Microcontroller Software Interface Standard (CMSIS). ) 版本: V4.2 发布日期: 31. July 2014 【STM32F4xx_StdPeriph_Driver】 STM32F40x系列CPU标准外设驱动程序 版本: V1.5.0 发布日期: 06-March-2015 【STM32_USB_OTG_Driver】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Device Library 版本: V2.1.0 发布日期: 2012-03-19 【STM32_USB_Device_Library】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Device Library 版本: V1.1.0 发布日期: 2012-03-05 【STM32_USB_HOST_Library】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Host Library 版本: V2.1.0 发布日期: 2012-03-19 【STM32F4x7_ETH_Driver】 STM32F4x7 Eth Library 版本: V1.1.0 发布日期: 31-July-2013 ********************************************************************************************************* * * 版 本 : V1.0 * 说 明 : 本实验主要实现FreeRTOS+STemWin+FatFS+USB Host综合 * 实验目的: * 1. 学习FreeRTOS+STemWin+FatFS+USB Host综合 * 2. 这里的USB Host主要实现U盘相关处理,支持U盘热插拔。 * 用户可以根据需要在usb_usr.c文件中的插入检测函数: * USBH_USR_Configuration_DescAvailable或者函数USBH_USR_Init函数加入插入标志 * 拔出检测函数: * USBH_USR_DeviceDisconnected * 实验内容: * 1. 按下按键K1可以通过串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1) * ================================================= * 任务名 任务状态 优先级 剩余栈 任务序号 * vTaskUserIF R 2 272 2 * vTaskGUI R 1 657 1 * IDLE R 0 113 6 * vTaskMsgPro B 4 1957 4 * vTaskLED B 3 483 3 * vTaskStart B 5 489 5 * * * 任务名 运行计数 使用率 * vTaskUserIF 5583 1% * vTaskGUI 10782 2% * IDLE 355589 91% * vTaskLED 0 <1% * vTaskMsgPro 16770 4% * vTaskStart 17 <1% * 串口软件建议使用SecureCRT(V6光盘里面有此软件)查看打印信息。 * 各个任务实现的功能如下: * vTaskGUI 任务: emWin任务 * vTaskTaskUserIF 任务: 接口消息处理 * vTaskLED 任务: LED闪烁 * vTaskMsgPro 任务: U盘中文件处理和浏览 * vTaskStart 任务: 启动任务,也就是最高优先级任务,这里实现按键扫描和触摸检测 * 2. 任务运行状态的定义如下,跟上面串口打印字母B, R, D, S对应: * #define tskBLOCKED_CHAR ( 'B' ) 阻塞 * #define tskREADY_CHAR ( 'R' ) 就绪 * #define tskDELETED_CHAR ( 'D' ) 删除 * #define tskSUSPENDED_CHAR ( 'S' ) 挂起 * 3. 本实验的USB Host主要是对U盘的操作,通过电脑端的串口软件SecureCRT软件, * 给板子发送相关命令实现操作,具体实现在demo_fatfs文件里面。 * printf("请选择操作命令:\r\n"); * printf("1 - 显示根目录下的文件列表\r\n"); * printf("2 - 创建一个新文件armfly.txt\r\n"); * printf("3 - 读armfly.txt文件的内容\r\n"); * printf("4 - 创建目录\r\n"); * printf("5 - 删除文件和目录\r\n"); * printf("6 - 读写文件速度测试\r\n"); * printf("7 - 挂载U盘\r\n"); * printf("8 - 卸载U盘\r\n"); * 注意事项: * 1. 本实验推荐使用串口软件SecureCRT,要不串口打印效果不整齐。此软件在 * V5开发板光盘里面有。 * 2. 务必将编辑器的缩进参数和TAB设置为4来阅读本文件,要不代码显示不整齐。 * * 修改记录 : * 版本号 日期 作者 说明 * V1.0 2016-03-15 Eric2013 1. ST固件库到V1.5.0版本 * 2. BSP驱动包V1.2 * 3. FreeRTOS版本V8.2.3 * 4. STemWin版本V5.28 * 5. FatFS版本V0.11a * * Copyright (C), 2016-2020, 安富莱电子 www.armfly.com * *********************************************************************************************************
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值