当前位置: 首页 > news >正文

FreeRTOS大杂烩

文章目录

        • Freertos移植
        • 任务切换基础
        • 同步互斥与通信
          • 队列:
            • 邮箱:
            • 队列集合:
          • 信号量:
          • 互斥量:
          • 事件组:
          • 任务通知:
        • 定时器使用:

Freertos移植

  • 其核心文件为,tasks.c、timers.c、queue.c、event_groups.c、croutine.c、list.c。源码兼顾了很多平台,但是我们可以删除一些不用的平台以及例程等,只保留我们要的。
  • 比如RVDS/ARM_CM3,这表示cotexM3架构再RVDS或Keil工具上的移植文件(比如下图中的port.c、portmacro.h)
  • 在编程过程中的大部分宏配置都在FreeRTOSConfig.h这个配置文件(调度、优先级、空闲任务等)
    在这里插入图片描述

任务切换基础

在这里插入图片描述

  • 任务间的切换,是利用tick中断实现的(关于这个时间片轮转的时间通过上面提到过的配置文件设置)

  • 任务状态有。就绪态、运行态、挂起态、阻塞态(延时、同步机制),其中每种状态下若有多个任务使用链表进行扩充
    空闲任务(pvIdleTask):(只能是就绪态或运行态)是为了帮别人收尸的(别人杀你,由别人清理。但是自杀自己是无法清理的).但是空闲任务不会直接供你使用,而是提供了一个钩子函数vApplicationIdleHook(执行的要快)让我在内部进行实现代码。

  • 首先空闲任务的目的是可以执行一些低优先级,后台的需要连续执行的函数。

  • 任务调度算法: 在FreeRTOSConfig.h文件中有宏可以配置
    (1)是否可抢占(高优先级可抢占、或者只有我自动说我不用了,你才能用)
    (2)同优先级是否可以交替执行(是否支持时间片轮转)
    (3)空闲任务是否礼让(一般空闲任务是最低优先级)

同步互斥与通信

这里其实可以把多任务看成是多线程,可知多线程是在一个进程的且文件资源共享。此时最高的办法就是使用全局变量。但是会出现资源竞争的问题,为此提出了同步机制来解决。

实现同步互斥的方法:队列、事件组、信号量、任务通知、互斥量
在这里插入图片描述

队列:

在这里插入图片描述

  • 队列像是一个传送带,而这传送带的两端可以是任务到任务、任务到中断、中断到任务直接传输信息

  • 队列结构体内部含有一个环形buffer以及Ready_Send_List、Ready_Receive_List.

    //创建队列
    QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,// Nitem
    							UBaseType_t uxItemSize ); //item_size
    //往队列写
    BaseType_t xQueueSend( QueueHandle_t xQueue, 
    						const void*pvItemToQueue,//数据的地址
    						TickType_t xTicksToWait ); //阻塞时间
    //关于往队列里面写(往尾部写、往头部写以及扩展特定的为中断服务任务使用的xxxxFrom_ISR)
    //从队列读
    BaseType_t xQueueReceive( QueueHandle_t xQueue, 
    						void * const pvBuffer, //数据地址
    					TickType_t xTicksToWait );//阻塞时间
    
邮箱:
  • FreeRTOS的邮箱概念与其它RTOS不一样。它是一个特殊的队列,因为队列的长度固定为1
  • 写邮箱:新数据覆盖旧数据,在任务中使用xQueueOverwrite(),
    在中断中使用 xQueueOverwriteFromISR() 。
    既然是覆盖,那么无论如何,数据总可以写入成功
  • 读邮箱:读数据时,数据不会被移除;在任务中使用xQueuePeek(),
    在中断中使用xQueuePeekFromISR(),
    意味着,第一次调用时会因为无数据而阻塞,一旦写入数据,以后读邮箱总能成功
队列集合:

在这里插入图片描述

  • 检测多个队列,挑出有数据的队列,进行读队列
  • 举例:有三个任务队列,鼠标任务队列queueA、按键任务队列queueB、触摸屏任务队列queueC
    *1)直接创建一个队列集
    	queue_set=xQueueCreateSet(3)
    *2)建立联系,即把单个队列依次放到队列集里面
    	xQueueAddToSet(queueA)xQueueAddToSet(queueB)
    	xQueueAddToSet(queueC)
    *3)写完队列A一次,就会写队列集一次(写队列自动会写队列集)
    	touch=>(data)=>touch_queue=>(handle)=>QueueSet
    *4)读queue_set一次,返回某一个队列(有数据的队列),并且读这个返回的队列
    
信号量:
  • 背景:关于上面的任务队列,可以用于任务与任务、任务与中断中间的数据传输,但是队列传输涉及到数据的复制等。而信号量只需要传递状态,并不需要传递具体的信息
  • 信号量:信号起通知作用、量用来表示资源的数量,
    用give给出资源,计数值+1,
    用take获得资源,计数值-1;
  • 二进制信号量:二进制信号量与计数型的唯一差别就是二值型的最大值被限定为1
    *申请二进制信号量句柄 
    	SemaphoreHandle_t xBinarySemaphore; 
    *创建二值信号量 
    	SemaphoreHandle_t xSemaphoreCreateBinary( void ); 
    *计数型信号量
    	SemaphoreHandle_t xSemaphoreCreateCounting(
    			UBaseType_t uxMaxCount,//3 			
    			UBaseType_t uxInitialCount);//0
    *1/1:
    	BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
    	BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,  
    									TickType_t xTicksToWait); 
    * 二值信号量初始值为1,互斥。
    * 二值信号量初始值为0,同步。
    
互斥量:
  • 上面的队列和二值信号量和队列都可以实现互斥的功能。但是有个问题。
    关于信号量的互斥,只要是个人都可以give和take。如果现在ab互斥,c来捣乱。就出现了很大问题
    为此出现了互斥量
  • 互斥量的核心:谁上锁,就只能谁解锁,但是FreeRTOS的互斥锁并没有代码实现(其实linux也是如此),只是靠程序员的自觉了。(这样导致谁上锁谁释放只是一种约定,好在RT-Thead中实现了)
  • 互斥量的重点:优先级的反转(优先级继承)、扩展递归锁
  • 互斥量函数:互斥量不能在ISR中使用。
    创建互斥量
    	SemaphoreHandle_t xSemaphoreCreateMutex( void ); 
    释放
    	BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
    获得
    	BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
    									TickType_t xTicksToWait );
    删除
    	void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ); 
    
事件组:

在这里插入图片描述

  • 解释:上述bit0用来表示串口是否就绪,bit1用来表示按键是否被按下。
    (值为1表示事件发生,值为0表示事件没发生)
    一个或多个任务、ISR都可以去写这些位;一个或多个任务、ISR都可以去读这些位
    可以等待某一位、某些位中的任意一个,也可以等待多位
  • 操作:或"、"与
    唤醒谁?
    *1队列、信号量:事件发生时,只会唤醒一个任务
    *2事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有“广播”的作用
    是否清除事件?
    *1队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
    *2事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件
  • 事件组操作函数:
    要先创建,得到一个句柄;
    创建
    	EventGroupHandle_t xEventGroupCreate( void ); 
    设置事件 
    	EventBits_t xEventGroupSetBits( EventGroupHandle_t
    										 xEventGroup,//事件组
    						const EventBits_t uxBitsToSet ); //设置哪些位
    等待事件
    	EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, 
    							const EventBits_t uxBitsToWaitFor, //等待哪些位
    							const BaseType_t xClearOnExit,//是否要清除事件 
    							const BaseType_t xWaitForAllBits,//等待1位还是all位 
    							TickType_t xTicksToWait );//等待事件
    删除
    	void vEventGroupDelete( EventGroupHandle_t xEventGroup ); 
    
任务通知:

在这里插入图片描述
使用队列、信号量、事件组等。并不知道对方是谁,
但是使用任务通知时,可以明确指定:通知哪个任务

  • 优势:
    (1)可以明确指定通知哪个任务
    (2)节省内存,TCB中内置通知结构体成员,无须另外创建
    通知成员为:通知值ulNotifiedValue(计数值、位、任意数值)
    通知状态ucNotifyState(无等待通知、在等待通知、接受通知待处理)
  • 缺点:
    (1)不能发送给ISR,ISR并没有TCB即内部无通知功能
    (2)数据只能该任务独享
    (3)无法缓冲数据
    (4)无法广播
    (5)若发送受阻,发送方无法进入阻塞状态等待
  • 任务通知函数操作:
    发出通知xTaskNotifyGive 与 vTaskNotifyGiveFromISR
    取出通知ulTaskNotifyTake

定时器使用:

在这里插入图片描述

  • 定时器三要素:超时时间、函数(回调函数)、单独触发还是周期触发
  • 操作函数:
    //创建 
    TimerHandle_t xTimerCreate( const char * const pcTimerName, 
    						const TickType_t xTimerPeriodInTicks, 
    								const UBaseType_t uxAutoReload, 
    										void * const pvTimerID, 
    					TimerCallbackFunction_t pxCallbackFunction ); 
    					
    //回调函数
    void ATimerCallback( TimerHandle_t xTimer ); 
    typedef void (* TimerCallbackFunction_t)( TimerHandle_t xTimer ); 
    
    //启动/停止/复位(启动定时器设置为运行态,停止定时器设置为睡眠态,复位即是冬眠转运行态)
    BaseType_t xTimerStart( TimerHandle_t xTimer, 
    					TickType_t xTicksToWait ); 
    BaseType_t xTimerStop( TimerHandle_t xTimer, 
    					TickType_t xTicksToWait );
    BaseType_t xTimerReset( TimerHandle_t xTimer,
     					TickType_t xTicksToWait ); 
     					
    //修改定时器周期:
    BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, 
    								TickType_t xNewPeriod, 
    							TickType_t xTicksToWait ); 
    							
    //删除定时器
    BaseType_t xTimerDelete( TimerHandle_t xTimer, 
    						TickType_t xTicksToWait ); 
    

相关文章:

  • 都这麽大了还不快了解防病毒网关?
  • HTML 笔记(八):SVG
  • 15.5 - 边界值法
  • 图解MySQL 记录
  • Effective C++学习笔记——确定对象被使用前已先被初始化
  • 一文弄懂 HashMap 中的位运算
  • 【易购管理系统】路由界面基础搭建
  • Linux系统常规异常报错解决汇总:
  • 【编程语言】什么是闭包?你可能经常在用它,但不知道它叫闭包!
  • 【live2D看板娘】为你的网站添加萌萌的二次元板娘,这都拿不下你?
  • 信息学奥赛一本通:1014:与圆相关的计算
  • 【APP 逆向百例】Frida 初体验,root 检测与加密字符串定位
  • 安卓中listview中性能优化的处理
  • 期刊论文-写作-投稿-工具等的经验合集
  • Java 属性文件乱码问题
  • android图片蒙层
  • css布局,左右固定中间自适应实现
  • DataBase in Android
  • ES6 ...操作符
  • JS题目及答案整理
  • React 快速上手 - 07 前端路由 react-router
  • 阿里云购买磁盘后挂载
  • 构建二叉树进行数值数组的去重及优化
  • 机器学习 vs. 深度学习
  • 通过git安装npm私有模块
  • 用Canvas画一棵二叉树
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • # centos7下FFmpeg环境部署记录
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #vue3 实现前端下载excel文件模板功能
  • (¥1011)-(一千零一拾一元整)输出
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (定时器/计数器)中断系统(详解与使用)
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)linux 命令大全
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .mysql secret在哪_MYSQL基本操作(上)
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net web项目 调用webService
  • .NET 发展历程
  • .NET 回调、接口回调、 委托
  • .NET上SQLite的连接
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @RunWith注解作用
  • [Android]How to use FFmpeg to decode Android f...
  • [autojs]逍遥模拟器和vscode对接
  • [CISCN 2019华东南]Web11
  • [DNS网络] 网页无法打开、显示不全、加载卡顿缓慢 | 解决方案
  • [FFmpeg学习]从视频中获取图片
  • [Flex] PopUpButton系列 —— 控制弹出菜单的透明度、可用、可选择状态
  • [Fri 26 Jun 2015 ~ Thu 2 Jul 2015] Deep Learning in arxiv
  • [iOS]-NSTimer与循环引用的理解