基于STM32CubeMX创建FreeRTOS—以STM32F429为例

news2025/1/12 15:47:14

目录

1. 实验任务

2. 使用STM32CubeMX创建基础工程

2.1 打开STM32CubeMX

2.2 创建新项目

2.3 时钟设置

2.5 修改时钟基准,打开串行调试

2.6 配置串口

2.7 配置状态指示灯

2.8 FreeRTOS

2.9 配置工程输出项

3. 代码编辑

3.1 printf重映射

3.1.1 使用ARMCC 5编译器时的printf重映射方法

3.2 使用FreeRTOS任务编写代码

3.3  运行效果

4 多任务相关知识

4.1 任务基础知识

4.2 任务状态

4.3 任务优先级

4.4 任务实现


 

1. 实验任务

利用STM32CubeMX,创建MDK工程,STM32CubeMX移植FreeRTOS。

开发环境准备:

Win11、MDK5、STM32CubeMX、STM32F429IGT6开发板

STM32CubeMX v6.10

2. 使用STM32CubeMX创建基础工程

2.1 打开STM32CubeMX

0a5154f9efce4dddb1b38b7df035c195.png

2.2 创建新项目

MCU型号选择STM32F429IGT6,开始项目。

fbea6d54b74248fe90eb74824f430ffb.png

2.3 时钟设置

选择使用外部高速时钟,时钟源为外部晶振(25MHz),配置系统时钟,根据外部晶振频率,将系统时钟配置到180MHz。

d13fbb6831ac44f7ac0d41d14f6e30d4.png

2.4 时钟配置树

0ca734433eaf46d6ab5fb24549c3bc72.png

2.5 修改时钟基准,打开串行调试

  • FreeRTOS使用systick系统嘀嗒定时器当作心跳,此处须修改HAL库的时钟基准。
  • 由于FreeRTOS和HAL库不能同时使用SysTick定时器,将HAL库的定时器改成TIM4

f03cb0bdd9f94a23852b0f559a1bdec4.png

2.6 配置串口

采用异步通信方式,通讯参数此处为默认值。

4719c78c016249d0889bef61aa31f189.png

2.7 配置状态指示灯

88ed322f4714405aac83ee6d5225e1b7.png

 

2.8 FreeRTOS配置

STM32CubeMX已经将FreeRTOS集成到工具中,并且将RTOS的接口封装为CMSIS-RTOS V1/V2,相较之于V1版本的CMSIS-RTOS API,V2版本的API的兼容性更高,为了将来的开发和移 植,建议开发者使用V2版本的API。

选择Middleware-FreeRTOS,Interface中选择CMSIS_V2:

ddf2631d34e1474cb265a107ae0a402c.png

选择CMSIS V2接口后,还要进一步配置FreeRTOS的参数和功能。
FreeRTOS的参数包括时基频率、任务堆栈大小、是否使能互斥锁等等,需要开发者根据自己对FreeRTOS的了解以及项目开发的需求,来定制参数。此处使用默认参数不需要修改。
使用STM32CubeMX,可以手工添加任务、队列、信号量、互斥锁、定时器等等。为提高代码的可移植性和灵活性,建议大家不要严重依赖STM32CubeMX,尽量不使用STM32CubeMX来添加这些对象,而是手写代码来使用这些对象。

建立双任务:

任务1:LED指示灯闪烁

任务2:串口打印输出

94da16ba15f9407bb841ad713d153315.png

提示:留意下串口中断的问题,由于FreeRTOS只允许5以上的中断级别,需要中断的话请设置大于等于5的值。

2.9 配置工程输出项

e77c2463f8b0486b9dca41f9c34509b5.png

6e7c0a73545743e8ab3d182dc1114c5b.png

 

3. 代码编辑

3.1 printf重映射

3.1.1 使用ARMCC 5编译器时的printf重映射方法

printf函数重映射,可以直接使用printf在串口一中打印数据,定位到usart.c文件中。

/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f)
{
    HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,10);
    return(ch);
}
/* USER CODE END 1 */

注意:重写printf后运行代码前一定要勾选Use MicroLiB,否则项目烧录后无法执行。

eca30f0165d74349ba36aa3515d1d3a6.png

3.1.2 使用ARM 6编译器时的printf重映射方法

参见博文:

基础篇007. 串行通信(一)--阻塞方式发送接收_串口阻塞-CSDN博客文章浏览阅读1.7k次,点赞2次,收藏10次。在学习C语言时我们经常使用C语言标准函数库输入输出函数,比如printf、scanf、getchar等。为让开发板也支持这些函数需要把USART发送和接收函数添加到这些函数的内部函数内。在C语言HAL库中,fputc函数是printf函数内部的一个函数,功能是将字符ch写入到文件指针f所指向文件的当前写指针位置。fgetc函数与fputc函数非常相似,实现字符读取功能。在使用scanf函数时需要注意字符输入格式。文中引入可使用#if …… #elif …… #endif方式调试代码。_串口阻塞https://blog.csdn.net/qcmyqcmy/article/details/130674914

基础篇007. 串行通信(二)--中断方式接收数据_串口设备通信0xffff-CSDN博客文章浏览阅读2.1k次。目录1. 实验任务2. 硬件原理3. 利用STM32CubeMX创建MDK工程3.1 STM32CubeMX工程创建3.2 配置调试方式3.3 配置时钟电路3.4 配置GPIO3.5 配置串口参数3.6 配置时钟3.7 项目配置4. 串行通信实验4.1 UART串口printf,scanf函数串口重定向4.2 开启中断4.3 中断回调函数4.4 main()函数修改5.调试与验证6.总结利用STM32CubeMX,创建MDK工程,使用中断方式,实现串口接收数据,然后在转发到串口。本实验是串行通信的第二部分,_串口设备通信0xffffhttps://blog.csdn.net/qcmyqcmy/article/details/130716056

3.2 使用FreeRTOS任务编写代码

在freertos.c中的任务函数里面写相应的程序

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */

84a54a428adf42bea6fff2f6e7de2841.png

/* USER CODE BEGIN Variables */
uint8_t USART1_BUF[] = "Hello FreeRTOS\r\n";
/* USER CODE END Variables */

825a2e34c8a748c19a8ef4aea6a07edd.png

/* USER CODE BEGIN Header_StartTask01 */
/**
  * @brief  Function implementing the myTask01 thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTask01 */
void StartTask01(void *argument)
{
  /* USER CODE BEGIN StartTask01 */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
    osDelay(1000);
  }
  /* USER CODE END StartTask01 */
}

0091760d0cff49308bfad957353a4324.png

/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  for(;;)
  {
    printf("USART1: %s", USART1_BUF);
    osDelay(1000);
  }
  /* USER CODE END StartTask02 */
}

40ef596dc8364a5fa6be11b2f5d66979.png

 

一点说明:

main.c函数中,osKernelStart()是任务调度函数,通过它可以进入操作系统,注释该语句后,程序就可进入后面的while语句了。

  /* Start scheduler */
  osKernelStart();

b71ec3c652d24e98807c85cd39ebb7ea.png

 

3.3  运行效果

待补充...

 

4 多任务相关知识

4.1 任务基础知识

 

单片机裸机(未使用系统)运行时,一般都是在main函数中用循环来处理所有事件,循环调用相应的函数完成事件的处理。有时候也可以通过中断完成一些处理。相对多任务系统而言,这种就是单任务系统,也称作前后台系统,中断服务函数作为前台程序,大循环while(1)作为后台程序。

e7fc79b8aba64298b89ad3f8a1e57c5e.png

多任务系统会把大问题划成很多的小问题,逐个将小问题解决掉,大问题也就会随之解决。这些小问题是并发处理的,并不是说同一时刻一起执行很多任务,而是由于每个任务执行的时间很短,看起来像同一时刻执行了很多任务。通过FreeRTOS里面的任务调度器完成任务的先后执行。在FreeRTOS中是一个抢占式的实时多任务系统,其任务调度器也是抢占式的。

20f9db76ef6446468682c7daa3a07bb1.png

高优先级的任务可以打断低优先级任务的运行而取得CPU的使用权,这样就保证了那些紧急任务的运行。高优先级的任务执行完成以后重新把CPU的使用权归还给低优先级的任务,这个就是抢占式多任务系统的基本原理。

4.2 任务状态

FreeRTOS中的任务永远只有运行态、就绪态、阻塞态、挂起态。任务状态图切换如下:

095c5619c6e14cf2a3e937f7513ac29a.png

(1)运行态

当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。

(2)就绪态

处于就绪态的任务是那些已经准备就绪(这些任务没有被阻塞或者挂起),可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!

(3)阻塞态

如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态,比如说如果某个任务调用了函数vTaskDelay0的话就会进入阻塞态,直到延时周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使所等待的事件还没有来临!

(4)挂起态

像阻塞态一样,任务进入挂起态以后也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用函数vTaskSuspend()和xTaskResume()。

4.3 任务优先级

每个任务都可以分配一个从0~(configMAX_PRIORITIES-1)的优先级,configMAX_PRIORITIES在文件FreeRTOSConfig.h中有定义。如果所使用的硬件平台支持类似计算前导零这样的指令(可以通过该指令选择下一个要运行的任务,Cortex-M处理器是支持该指令的),并且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也设置为了1,那么宏configMAX_PRIORITIES不能超过32!也就是优先级不能超过32级。其他情况下宏configMAX_PRIORITIES可以为任意值,但是考虑到RAM的消耗,宏configMAX_PRIORITIES最好设置为一个满足应用的最小值。优先级数字越低表示任务优先级越低,0的优先级最低,configMAX_PRIORITIES-1的优先级最高。空闲任务的优先级最低,为0。FreeRTOS调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,换句话说就是处于就绪态的最高优先级的任务才会运行。当宏configUSE_TIME_SLICING定义为1的时候多个任务可以共用一个优先级,数量不限。默认情况下宏configUSE_TIME_SLICING在文件FreeRTOS.h中已经定义为1。此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。

4.4 任务实现

在使用FreeRTOS的过程中,需要使用xTaskCreat()或者xTaskCreatStatic()来创建任务,这两个函数的第一个参数为pxTaskCode,就是任务函数本体。任务函数就是完成本任务工作的函数。FreeRTOS官方给出的任务函数模板为:

void vATaskFunction(void *pvParameters){        (1)
    for(;;){                                    (2)
       --任务应用程序--                          (3)
       vTaskDelay();                            (4)
}
    VTaskDelete(NULL);                          (5)
}

(1)、任务函数本质也是函数,所以肯定有任务名什么的,不过这里要注意:任务函数的返回类型一定要为void类型,也就是无返回值,而且任务的参数也是void指针类型的!任务函数名可以根据实际情况定义。

(2)、任务的具体执行过程是一个大循环,for(;;)就代表一个循环,作用和while(1)一样,笔者习惯用while(1)。

(3)、循环里面就是真正的任务代码了,此任务具体要干的活就在这里实现!

(4)、FreeRTOS的延时函数,此处不一定要用延时函数,其他只要能让FreeRTOS发生任务切换的API函数都可以,比如请求信号量、队列等,甚至直接调用任务调度器。只不过最常用的就是FreeRTOS的延时函数。

(5)、任务函数一般不允许跳出循环,如果一定要跳出循环的话在跳出循环以后一定要调用函数vTaskDelete(NULL)删除此任务!FreeRTOS的任务函数和UCOS的任务函数模式基本相同的,不止FreeRTOS,其他RTOS的任务函数基本也是这种方式的。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1401587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

资产及价值导入

文章目录 1 Introduction2 Code3 Summary 1 Introduction We will implement the following fuction for importing asset value . In the code we introduce that how to transfer value for BAPI. 2 Code DATA: key TYPE bapi1022_key,generaldata …

ROS第 13 课 TF 坐标系广播与监听的编程 实现

文章目录 第 13 课 TF 坐标系广播与监听的编程 实现1.机器人的坐标变换2.创建功能包3.编程方法3.1 编写广播和监听程序3.2 运行程序 第 13 课 TF 坐标系广播与监听的编程 实现 1.机器人的坐标变换 在进行编程前,先需要了解机器人的坐标变换。这里以运行海龟案例来…

洛谷-P1002-[NOIP2002 普及组]-过河卒

[NOIP2002 普及组] 过河卒 题目描述 棋盘上 A A A 点有一个过河卒,需要走到目标 B B B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C C C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为…

代码随想录第十八天 513 找树左下角的值 112 路径之和 106 从中序与后序遍历序列构造二叉树

LeetCode 513 找树左下角的值 题目描述 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 思路 1.确定递…

多级缓存

一、多级缓存 传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图: 存在下面的问题: •请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈 •Redis缓存失效时&#xff…

打折:阿里云国外服务器价格购买优惠活动

阿里云国外服务器优惠活动「全球云服务器精选特惠」,国外服务器租用价格24元一个月起,免备案适合搭建网站,部署独立站等业务场景,阿里云服务器网aliyunfuwuqi.com分享阿里云国外服务器优惠活动: 全球云服务器精选特惠…

77. 组合 - 力扣(LeetCode)

题目描述 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 输入示例 n 4, k 2输出示例 [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]解题思路 我们使用回溯、深度优先遍历的思想,我们使用一个栈 path…

linux驱动(八):block,net

本文主要探讨210的block驱动和net驱动。 block 随机存取设备且读写是按块进行,缓冲区用于暂存数据,达条件后一次性写入设备或读到缓冲区 块设备与字符设备:同一设备支持块和字符访问策略,块设备驱动层支持缓冲区,字符设备驱动层没有缓冲 块设备单位:扇…

Leetcode的AC指南 —— 栈与队列:20. 有效的括号

摘要: **Leetcode的AC指南 —— 栈与队列:20. 有效的括号 **。题目介绍:给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。 有效字…

基于JavaWeb+SSM+Vue智能社区服务小程序系统的设计和实现

基于JavaWebSSMVue智能社区服务小程序系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相…

【计算机硬件】4、练习题

根据冯诺依曼原理,计算机硬件的基本组成是() A.输入、输出设备、运算器、控制器、存储器 B.磁盘、软盘、内存、CPU、显示 C.打印机、触摸屏、键盘、软盘 D.鼠标、打印机、主机、显示器、存储器 CPU执行算术运算或者逻辑运算时,常…

class_14:继承

C继承有点类似于c语言 结构体套用 #include <iostream> #include <string> using namespace std;//基类,父类 class Vehicle{ public:string type;string contry;string color;double price;int numOfWheel;void run();void stop(); };//派生类&#xff0c…

Python基础第五篇(Python数据容器)

文章目录 一、数据容器入门二、数据容器 list 列表(1),list 列表定义(2),list列表的索引(3),list列表的常见操作(4),list列表的遍历 三、数据容器&#xff1a;tuple&#xff08;元组&#xff09;(1),tuple元组定义(2),tuple元组的索引(3),tuple元组的常见操作(4),tuple元组的遍…

力扣【四数之和】

一、题目描述 18. 四数之和 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#x…

PyQt5 快速入门(一)

第一节按钮控件,文本控件,输入框,app图标 文章目录 一.GUI按钮控件 二.文本控件 三.输入框 四.让窗口显示在屏幕中央 五.让窗口显示在屏幕中央 总结 一.GUI按钮控件 import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButtonif __name__ __main__:app …

python爬虫知识点:5种线程锁

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 线程安全 线程安全是多线程或多进程编程中的一个概念&#xff0c;在拥有共享数据的多条线程并行执行的程序中&#xff0c;线程安全的代码会通过同步机制保证各个…

Python使用graphviz绘制模块间数据流

graphviz官方参考链接&#xff1a; http://www.graphviz.org/documentation/ https://graphviz.readthedocs.io/en/stable/index.html 文章目录 需求描述环境配置实现思路代码实现 需求描述 根据各模块之间的传参关系绘制出数据流&#xff0c;如下图所示&#xff1a; 并且生成…

Redis(01)——常用指令

基础指令 select 数字&#xff1a;切换到其他数据库flushdb&#xff1a;清空当前数据库flushall&#xff1a;清空所有数据库dbsize&#xff1a;查看数据库大小exists key1[key2 …]&#xff1a;判断当前的key是否存在keys *&#xff1a;查看所有的keyexpire key 时间&#xff…

深入Matplotlib:画布分区与高级图形展示【第33篇—python:Matplotlib】

文章目录 Matplotlib画布分区技术详解引言方法一&#xff1a;plt.subplot()方法二&#xff1a;简略写法方法三&#xff1a;plt.subplots()实例展示添加更多元素 进一步探索Matplotlib画布分区自定义子图布局3D子图结语 Matplotlib画布分区技术详解 引言 Matplotlib是一个强大…

第13节-简历中的开放性问题

(点击即可收听) 不少公司的开放式题目每年不会有太大的变化&#xff0c;所以在答题前可先去相关求职论坛看看这些公司往年的问题&#xff0c;分析和思考自己应当怎么回答 开放式问题回答技巧 开放式问题主要考察的是求职者的求职动机、解决问题的能力、创造力等软实力&#xff…