STM32第十九课:FreeRTOS移植和使用

目录

  • 需求
  • 一、FreeRtos概要
  • 二、移植FreeRtos
    • 1.复制源码
    • 2.内存空间分配和内核相关接口
    • 3.FreeRTOSConfig.h
    • 4.在工程中添加.c.h
  • 三、任务块操作
    • 1.创建任务
    • 2.任务挂起,恢复,删除
  • 四、需求实现代码


需求

1.将FreeRtos(嵌入式实时操作系统)移植到STM32中。
2.在该系统中实现任务的创建、挂起、恢复和删除。
3.将之前写的传感器模块的数据获取,移植到FreeRtos(嵌入式实时操作系统)环境下。
在这里插入图片描述
在这里插入图片描述


一、FreeRtos概要

STM32裸机运行代码:
在这里插入图片描述
加入FreeRtos后:
在这里插入图片描述
由此可见,由于单片机只有一个核心,同一时间下只能处理一件事。如果用户想要实现多个任务并行的效果,可以通过加入FreeRtos(嵌入式实时操作系统),操作系统可以让STM32实现任务的快速切换,从而给人一种多个任务并行的错觉。
在这里插入图片描述

二、移植FreeRtos

  打开想要移植FreeRtos的工程,把主函数清空,只留一个while(1)。由于FreeRtos是任务块操作,所以之前写的程序就没用了。
移植后使用了三个中断服务函数:
1.SVC中断服务函数:上下切换中断,FreeRtos实现任务切换
2.PendSVC中断服务函数:任务挂起中断。
3.SysTick中断服务函数:FreeRtos运行的时间基准

#define vPortSVCHandler SVC_Handler	  //上下切换中断,FreeRtos实现任务切换
#define xPortPendSVHandler PendSV_Handler		//任务挂起中断
#define xPortSysTickHandler SysTick_Handler	//FreeRtos运行的时间基准

1.复制源码

先打开移植的文件夹:

在这里插入图片描述
将源码直接复制到想要移植的工程文件下,改名为FreeRtos:
在这里插入图片描述

2.内存空间分配和内核相关接口

在这里插入图片描述
在portable文件夹中找到MemMang文件夹,该文件夹放着的就是内存分配文件,我们选择4就行。
在这里插入图片描述
port,就是内核相关的接口文件,是必要添加的。

3.FreeRTOSConfig.h

在这里插入图片描述
打开样例文件夹,找到相对应的芯片,将FReeRTOSconfig.h文件复制过来即可。

4.在工程中添加.c.h

.c
在这里插入图片描述
.h
在这里插入图片描述

其中,FreeRTOSConfig.h 是直接从 demo 文件夹下面拷贝过来的,该头文件对裁剪整个FreeRTOS 所需的功能的宏均做了定义,有些宏定义被使能,有些宏定义被失能,一开始我们只需要配置最简单的功能即可。要想随心所欲的配置 FreeRTOS 的功能,必须对这些宏定义的功能有所掌握。

#define configUSE_TIME_SLICING 1 //使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //硬件计算前导零指令,如果所使用的, MCU 没有这些硬件指令的话此宏应该设置为 0
#define configUSE_TICKLESS_IDLE 0 //置 1:使能低功耗 tickless 模式;置 0:保持系统节拍(tick)中断一直运行
#define configUSE_QUEUE_SETS 1 //启用队列
#define configUSE_TASK_NOTIFICATIONS 1 //开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //使用互斥信号量
#define configUSE_RECURSIVE_MUTEXES 1 //使用递归互斥信号量
#define configUSE_COUNTING_SEMAPHORES 1 //为 1 时使用计数信号量
#define configQUEUE_REGISTRY_SIZE 10 //设置可以注册的信号量和消息队列个数
#define configUSE_APPLICATION_TASK_TAG 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configUSE_MALLOC_FAILED_HOOK 0 //使用内存申请失败钩子函数
#define configCHECK_FOR_STACK_OVERFLOW 1// 大于 0 时启用堆栈溢出检测功能,如果使用此功能用户必须提供一个栈溢出钩子函数如果使用的话此值可以为 1 或者 2,因为有两种栈溢出检测方法
#define configGENERATE_RUN_TIME_STATS 0 //启用运行时间统计功能
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TIMERS 1 //启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 10 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
//可选函数配置选项
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
//中断服务函数 也可以修改起始文件
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

三、任务块操作

调度
和裸机操作不同,操作系统中执行的是一个一个任务块,通过任务调度器(使用相关的调度算法)来决定当前时刻要执行哪个任务。
调度方式主要有两种:
1.抢占式调度:任务优先级不同时使用。每个任务都有自己的优先级,高优先级的任务会抢占低优先级的任务。
2.时间片调度:任务优先级相同时使用。当多个任务优先级相同时,任务调度器会在每一次系统节拍到的时候切换任务。
其实说白了就是:STM32执行的是线性代码,只有中断能打断。而FreeRtos执行的是不同等级的任务块,等级越高任务块就越先执行相同等级的任务块执行时系统会来回切换
优先级不能设置为0,因为FreeRtos的空闲任务优先级为0,一般情况下我们不去抢。

任务状态

状态含义
运行态CPU正在执行的任务。注意:在STM32中,同一时间仅一个任务处于运行态
就绪态该任务能够被执行,但目前还未被执行,那么该任务就处于就绪态。
阻塞态如果一个任务因延时或等待外部事件发生,那么这个任务就处于阻塞态。
挂起态类似暂停,调用函数 vTaskSuspend() 进入挂起态,需要调用恢复函数vTaskResume()才可以进入就绪态 。

1.创建任务

添加FreeRTOS相关头文件

//使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h"
#include "FreeRtos.h"
#include "task.h"

创建一个句柄,TaskHandle_t 类型

TaskHandle_t LED_TaskHandle;//LED

写与句柄对应的任务函数,通常要加while(1)每个任务都是1个无限循环程序,内容根据需求来定。

void Led_Task(void *p)
{uint8_t i=0;while(1){i++;printf("i=%d\r\n",i);Led_Toggle(1);Delay_nms(300);}
}

定义一个BaseType_t变量

BaseType_t Ret = pdPASS;

使用xTaskCreate()创建任务块,返回值由BaseType_t类型变量承接,返回值为pdPASS(1)时即创建成功

	Ret = xTaskCreate(  Led_Task,"LED1_toggle",50,//栈深度,32位单片机*4NULL,2,&LED_TaskHandle);if(Ret==pdPASS){printf("LED_Task创建成功!\r\n");}

参数1:实现任务的函数名
参数2:自己起一个任务名
参数3:分配空间,栈深度(32位单片机*4)
参数4:任务函数传参时使用
参数5:任务优先级(越高优先级越高)
参数6:该任务的句柄

最后,使用vTaskStartScheduler()函数开始调度就完成了。

vTaskStartScheduler();

2.任务挂起,恢复,删除

挂起
使用vTaskSuspend()函数即可,参数只有一个:想要挂起任务的句柄。
恢复
使用vTaskResume()函数即可,参数只有一个:想要恢复任务的句柄。
删除
使用vTaskDelete()函数即可,参数只有一个:想要删除任务的句柄。

printf("挂起LED\r\n");vTaskSuspend(LED_TaskHandle);//挂起
printf("继续LED\r\n");vTaskResume(LED_TaskHandle);//继续
printf("删除LED\r\n");vTaskDelete(LED_TaskHandle);//删除

四、需求实现代码

在该系统中实现任务的创建、挂起、恢复和删除

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
//使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h"
#include "FreeRtos.h"
#include "task.h"
#include "usart.h"
#include "key.h"
TaskHandle_t LED_TaskHandle;//LED
TaskHandle_t KEY_TaskHandle;//KEYvoid Led_Task(void *p)
{uint8_t i=0;while(1){i++;printf("i=%d\r\n",i);Led_Toggle(1);Delay_nms(300);}
}void KEY_Task(void *p)
{while(1){switch(key_getvalue()){case 1:{printf("挂起LED\r\n");vTaskSuspend(LED_TaskHandle);}break;//挂起case 2:{printf("继续LED\r\n");vTaskResume(LED_TaskHandle);}break;//继续case 3:{printf("删除LED\r\n");vTaskDelete(LED_TaskHandle);}break;case 4:{	BaseType_t Ret = pdPASS;	Ret = xTaskCreate(  Led_Task, "LED1_toggle",50,NULL,2,&LED_TaskHandle);if(Ret==pdPASS){printf("LED_Task创建成功!\r\n");}};break;}vTaskDelay(10);}
}int main()
{Led_Init();key_Init();Usart1_Config();BaseType_t Ret = pdPASS;Ret = xTaskCreate(  Led_Task,"LED1_toggle",50,//栈深度,32位单片机*4NULL,2,&LED_TaskHandle);if(Ret==pdPASS){printf("LED_Task创建成功!\r\n");}Ret = xTaskCreate(  KEY_Task,"KEY_Task",80,//栈深度,32位单片机*4NULL,2,&KEY_TaskHandle);if(Ret==pdPASS){printf("KEY_Task创建成功\r\n");}printf("开始调度!\r\n");vTaskStartScheduler();while(1){}
}

将之前写的传感器模块的数据获取,移植到FreeRtos(嵌入式实时操作系统)环境下
main.c

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "delay.h"
#include "string.h"
#include "pwm.h"
#include "adc.h"
#include "su03t.h"
#include "dht11.h"
#include "kqm.h"//使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h"
#include "FreeRtos.h"
#include "task.h"
#include "usart.h"
#include "key.h"
TaskHandle_t Deal_TaskHandle;//数据处理void Data_Task(void *p)
{while(1){Get_Smoke_Light_MidValue();DHT11_ReadData();Delay_nms(300);KQM_DealData();Su03tDealData();}
}int main()
{RGBpwm_Config();Kqm_U4Config();Su03t_U5Config();DHT11_Config();	 Adc_Config();Led_Init();key_Init();Usart1_Config();BaseType_t Ret = pdPASS;Ret = xTaskCreate(  Data_Task,"DealData",100,//栈深度,32位单片机*4NULL,2,&Deal_TaskHandle);if(Ret==pdPASS){printf("语音创建成功!\r\n");}printf("开始调度!\r\n");vTaskStartScheduler();while(1){}
}

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

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

相关文章

白骑士的C++教学高级篇 3.2 多线程与并发

系列目录 上一篇:白骑士的C教学高级篇 3.1 文件操作 随着计算机硬件的发展,现代计算机通常配备了多核处理器,为并发编程提供了硬件基础。C11引入了一组强大的多线程库,使得开发多线程应用程序变得更加容易和安全。本篇内容将详细…

若依框架中Spring Cloud版本启动失败问题

RuoYiSystemApplication启动不了 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ruoyi.system.mapper.SysConfigMapper.selectConfigList 该问题是因为在我们拉取若依代码到本地之后,没有对配置作改动,而且若依…

在Python中字典是如何通过哈希表实现的以及哈希冲突是如何解决的

哈希表(散列表)是一种非常重要的数据结构,它提供了快速的插入、查找和删除操作,平均时间复杂度接近O(1)。哈希表通过哈希函数将键(key)映射到表中的一个位置来访问记录,以加快查找速度。下面分别…

如何使用Python抓取动态网站数据

引言 动态网站的特点和数据抓取的挑战 动态网站通过JavaScript动态生成内容,这使得数据抓取变得更加复杂。传统的静态HTML解析方法无法获取这些动态生成的数据,因为它们在初始加载时并不存在于HTML源代码中。对于数据科学家和开发者来说,从这…

React Hook 总结(React 萌新升级打怪中...)

1 useCallback useMemo 和 useCallback 接收的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于 useMemo 返回的是函数运行的结果,useCallback 返回的是函数。 当需要使用 useCallback 的情况通常包括以…

Kylin系列入门

Kylin是中国最流行的开源大数据平台之一,主要用于解决大数据存储、处理和分析问题。Kylin的目标是将大数据分析变得更简单、更快速和更高效。下面是Kylin系列的入门指南,带有一些示例。 什么是 Kylin? Kylin是Apache Kylin项目下的一个开源…

服务器基础1

服务器基础复习01 1.环境部署 系统:华为欧拉系统 网络简单配置nmtui 因为华为欧拉系统密码需要复杂度 所以我们可以进入后更改密码 echo 123 | passwd --stdin root也可以 echo "root:123" | chpasswd2.关闭防火墙,禁用SElinux 首先先关…

Socket 简介与 Java Socket 编程示例

Socket(套接字)是网络通信中的一个关键概念,它是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。 一、定义与概念 基本概念:Socket可以被视为网络环境中进程间通信的API(应用程序编程接口)&…

彻底理解Linux的DISPLAY变量的作用

背景 最近遇到个两年前遇到的问题,使用virt-manager提示(virt-manager:873): Gtk-WARNING **: 14:53:28.147: cannot open display: :1,当时专门运维的同事帮忙临时调了下DISPLAY变量,好像是将:1改成了SSH用户本地IP:10.0,当时的…

每日一题——第十四题

题目&#xff1a;输入一行数字&#xff0c;将其按升序输出&#xff0c;且奇数在前&#xff0c;偶数在后 #include<stdio.h>void bubbleSort(int* arr, int n); int main(){int n, i, input_nums;printf("请输入数字个数&#xff1a; ");scanf("%d",…

纠正和防止机器学习中的不公平现象

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识AI 进阶&#xff1a;企业项目实战 预处理、处理中、后处理方法和非定量方法 机器学习中的公平性是一个复杂的问题。更糟糕的是&#xff0c;负…

加密传输及相关安全验证:

1.1. 加密&#xff1a; 1.1.1. 对称加密&#xff1a; 特点&#xff1a;加解密用一个密钥&#xff0c;加解密效率高&#xff0c;速度快&#xff0c;有密钥交互的问题问题&#xff1a;双方如何交互对称密钥的问题&#xff0c;用非对称密钥的公钥加密对称密钥的混合加密方式常用…

[数据分析]脑图像处理工具

###############ATTENTION&#xff01;############### 非常需要注意软件适配的操作系统&#xff01;有些仅适用于Linux&#xff0c;可以点进各自软件手册查看详情。 需要自行查看支持的影像模态。 代码库和软件我没有加以区分。 不是专门预处理的博客&#xff01;&#xf…

C语言 底层逻辑详细阐述指针(一)万字讲解 #指针是什么? #指针和指针类型 #指针的解引用 #野指针 #指针的运算 #指针和数组 #二级指针 #指针数组

文章目录 前言 序1&#xff1a;什么是内存&#xff1f; 序2&#xff1a;地址是怎么产生的&#xff1f; 一、指针是什么 1、指针变量的创建及其意义&#xff1a; 2、指针变量的大小 二、指针的解引用 三、指针类型存在的意义 四、野指针 1、什么是野指针 2、野指针的成因 a、指…

深入理解TCP/IP协议:三次握手与四次挥手

以下是一篇关于TCP/IP握手和挥手过程的CSDN博客文章草稿&#xff1a; 摘要 TCP&#xff08;传输控制协议&#xff09;是互联网上使用最广泛的协议之一&#xff0c;它负责在网络中的两个主机之间提供可靠的、有序的和错误检测功能的数据传输。本文将详细介绍TCP的三次握手过程和…

《基于 Kafka + Quartz 实现时限质控方案》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

Activiti7+ SpringBoot+SpringMVC 开发

添加 Controller 类 代码如下&#xff1a; RestController public class MyController {Autowiredprivate ProcessRuntime processRuntime;Autowiredprivate TaskRuntime taskRuntime;Autowiredprivate SecurityUtil securityUtil; }实现任务完成 RequestMapping("test…

学习分布式事务遇到的小bug

一、介绍Seata 在处理分布式事务时我用到是Seata&#xff0c;Seata的事务管理中有三个重要的角色&#xff1a; TC (Transaction Coordinator) - 事务协调者&#xff1a;维护全局和分支事务的状态&#xff0c;协调全局事务提交或回滚。 TM (Transaction Manager) - 事务管理器…

从零开始学习cartographer源码 | 02.cartographer_ros—node_main.cc

从零开始学习cartographer源码 | 02.cartographer_ros—node_main.cc cartographer_ros程序的入口 main()函数程序的主函数Run()函数 特别&#xff08;防杠&#xff09;声明&#xff1a;《从零开始学习cartographer源码》系列文章仅仅是本人学习cartographer的学习笔记&#xf…

PHP pwn 学习 (2)

文章目录 A. 逆向分析A.1 基本数据获取A.2 函数逆向zif_addHackerzif_removeHackerzif_displayHackerzif_editHacker A.3 PHP 内存分配 A.4 漏洞挖掘B. 漏洞利用B.1 PHP调试B.2 exp 上一篇blog中&#xff0c;我们学习了一些PHP extension for C的基本内容&#xff0c;下面结合一…