网络建站模板,网页系统,招远建网站,怎么样可以建设网站目录
RTOS(实时操作系统)
裸机开发模式
轮询方式
前后台#xff08;中断方式#xff09;
改进#xff08;前后台#xff08;中断#xff09;#xff09;定时器 裸机进一步优化
裸机的其他问题
RTOS的概念
什么是RTOS
为什么要使用 RTOS
RTOS的应用场景
RTOS的…目录
RTOS(实时操作系统)
裸机开发模式
轮询方式
前后台中断方式
改进前后台中断定时器 裸机进一步优化
裸机的其他问题
RTOS的概念
什么是RTOS
为什么要使用 RTOS
RTOS的应用场景
RTOS的选择
RTOS的工作原理
FreeRTOS特点
创建第一个FreeRTOS程序
搭建方法
1、官网源码下载
2、处理工程目录
3、打开编译工程
4、去掉无关代码
5、删除未定义报错内容
6、验证
串口打印实验
如何找串口仿真
命名规范
动态任务的创建
任务实验
实现
函数原型
实验
优先级
延时函数
查看延时时间验证
调度原理
抢占式调度
时间片调度
任务状态
挂起任务、恢复任务
挂起任务函数原型
恢复任务函数原型
任务删除
函数原型
空闲任务
空闲任务钩子函数用途
空闲任务钩子函数的实现限制
钩子函数的使用
使用CUBE配置FreeRTOS编写程序
1、更新安装freertos插件
2.配置FreeRTOS
3.配置基础硬件
4.最后生成工程MDK内编写程序 RTOS(实时操作系统) 裸机开发模式 轮询方式 对于简单的应用程序轮询无限循环的实现比较简单在硬件完成初始化后顺序的完成各种 任务。在外设的基础实验中常采用这种方式。 int main()
{ while(1){DHT11数据采集;读取WIFI数据;判断数据;}
} 在实际的嵌入式系统中存在周期性与触发型任务每个任务的执行时间与实时响应要求不同在采用轮询系统进行程序设计时很难应对这些场景。 前后台中断方式 前后台系统是在轮询的基础上加入了中断。外部事件的记录在中断中操作对事件的响应在轮询中 完成中断处理过程称之为前台main 函数中的轮询称为后台。 后台的程序顺序执行如果产生中断那么中断会打断后台程序的正常执行转而去执行中断服务 程序。如果事件的处理过程比较简单可以直接在中断服务程序中进行处理如果事件的处理过程比较 复杂可以在中断中对事件响应进行标记进而返回后台程序进行处理。 int main()
{ while(1){if(DHT111){DHT11数据处理DHT110;}if(wifi1){处理WIFI数据;wifi0;}}
}
void DHT11_irq()
{DHT111;
}
void WIFI_irq()
{wifi1;
}
//中断处理的速度高了
//触发之后又成为了轮询操作
//假如DHT11优先级高且处理时间过长 wifi的处理就不及时了 采用前后台系统进行程序时对后台的任务需要进行设计避免单个任务长时间占有处理器资源。 当任务的逻辑比较复杂任务的拆分难度增加同时随着中断事件的增加整个程序的设计与响应的 实时性将会降低。 改进前后台中断定时器 设置3S定时器中断DHT11采集 设置5s定时器中断Wifi数据处理 裸机进一步优化 void wifi(void)
{static int key0;switch(key){case 0:发送AT指令();key1return;case 1:接收数据();key2return;case 2:判断数据();key0return;}
}
void DHT11(void)
{static int DHT110;switch(DHT11){case 0:握手();DHT111return;case 1:接收数据();DHT112return;case 2:判断数据完整性();DHT113;return;case 3:数据处理();DHT110;return;}
}
//问题解决了但是程序的复杂度上来了
//基于裸机架构无法完美解决复杂耗时的多个函数 裸机的其他问题 while(1)
{ DHT11;if(key){delay(100);//程序在这停止了效率被影响了if(key){wifi();}}
}按键消抖优化 在按键中断服务程序开启定时器 在定时器中断服务程序执行按键操作并关掉定时器 RTOS的概念 什么是RTOS 为什么要使用 RTOS 主要是为了满足系统在时间和资源管理上的特殊需求 使用实时内核的理由可以从多个方面来描述包括可维护性、可扩展性、模块化、团队开发、测试、代码复用、效率、空闲时间、电源管理、中断处理以及混合处理需求。以下是对这些方面的详细解释 可维护性实时内核通常具有抽象化的时间细节这减少了模块间的依赖关系使软件更易于维护和演化。由于内核负责计时应用程序的执行受底层硬件变化的影响较小进一步提高了可维护性。模块化实时内核的每个任务通常被设计为独立的模块具有明确的设计目的。这种模块化设计有助于团队开发因为每个团队成员可以独立地负责一个模块的开发和维护提高开发效率和系统稳定性。可扩展性实时内核的设计通常允许添加新的功能或模块而不需要对现有系统进行大规模修改。这使得系统能够随着需求的变化而扩展保持长久的生命力。代码复用实时内核的模块化设计使得代码更容易被复用。通过低耦合设计代码可以在不同的模块之间共享和重用提高了开发效率并降低了维护成本。提升效率实时内核通常设计为事件驱动这意味着它仅在事件发生时才进行处理。这种设计有助于提高系统的响应速度和运行效率。 RTOS的应用场景 物联网IoTRTOS是专门为物联网设备设计的操作系统它提供了实时性、高效性和可靠性以满足物联网应用的特殊需求。RTOS通过任务调度算法管理任务的执行顺序确保高优先级任务能够及时响应满足物联网设备对实时性的要求。 智能家居RTOS在智能家居系统中用于控制各种智能设备如智能灯泡、智能插座、智能门锁等。RTOS提供了设备之间的实时通信和协同工作使用户能够方便地通过智能手机或其他设备控制家居环境。 医疗设备RTOS在医疗设备中发挥着重要作用如心脏起搏器、监护仪等设备需要实时处理生理参数确保患者的生命安全。RTOS的高可靠性和实时性使得这些设备能够在关键时刻发挥关键作用。SAFERTOS等RTOS产品特别针对医疗设备的需求提供响应迅速、稳健、确定性的嵌入式实时操作系统降低项目风险、开发成本并缩短上市时间。 汽车电子在汽车领域RTOS的应用越来越广泛。例如高级驾驶辅助系统ADAS需要实时处理大量的传感器数据以实现自动驾驶、车辆导航等功能。RTOS能够确保这些系统的实时性和稳定性提高驾驶安全性。 工业自动化和机器人技术RTOS在工业自动化系统中扮演关键角色通过精确定时和控制能力确保生产线的稳定运行提高生产效率和质量。在机器人技术中RTOS能够确保机器人实时响应指令执行复杂任务如无人机和机器人的飞行轨迹控制、任务执行等。 航空航天在航空航天领域RTOS的应用至关重要。由于航空电子系统的复杂性和对实时性的极高要求RTOS能够提供高度可靠的中断处理和任务调度机制确保飞行控制系统、导航系统和传感器数据处理的实时性和准确性。 RTOS的选择 安全性RTOS 是否有助于设备的安全性或损害设备的安全性容易出现用户错误吗 性能RTOS 能否促进应用程序代码的开发代码是否在所需参数内执行 可靠性RTOS 是否会影响设备的可靠性 功能RTOS 是否具备完成这项工作所需的设施 学习RTOS的3个步骤 学会使用API 了解API实现原理 可以优化改进API RTOS的工作原理 ① RTOS相当于实现了后台的主循环并能够处理ISR与主循环的交互 ② 使得用户可以只考虑任务的设计 ③ RTOS还提供了各种组件用于实现任务间交互及其他控制管理功能e.g. 存储管理 提供多个执行流虽然实际只有一颗CPU但通过虚拟化每个Task好像独占CPU 提供资源管理和通信组件 提供一些组件用于简化任务对资源的访问事件的处理以及任务之间的通信有效降低任务之间的代码耦合 FreeRTOS特点 创建第一个FreeRTOS程序 搭建方法 移植文件(FreeRTOS相关文件)时钟配置官网源码下的DEMO需要精简 去掉无关文件标准库CUBEMX直接生成就可以了 1、官网源码下载 1进入FreeRTOS官网 2点击下载FreeRTOS 2、处理工程目录 1下载后解压FreeRTOS文件 2删除多余文件红框里的 3删除FreeRTOSv202212.01\FreeRTOS\Demo目录下用不到的示例工程留下common这里放了一些公共文件 4FreeRTOSv202212.01\FreeRTOS\Source\portable目录下只保留如下两个文件夹其他全部删掉。 (5)FreeRTOSv202212.01\FreeRTOS\Source\portable\RVDS目录下只保留如下一个文件夹其他全部删掉 3、打开编译工程 1删除后文件后进入如下图打开工程 2弹出如下对话框说明该工程是用KeilMDK4创建的。点击“Migrate to Device Pack”更新为KeilMDK5。 3弹出对话框点击“确定”。 更新后关闭工程再重新打开编译。工程目录介绍(System里还有一个lcd也删掉) 4、去掉无关代码 1Demo Files文件下只保留“serial.c和main.c”文件其他都删掉删完之后main里去掉一些头文件。 2编译 5、删除未定义报错内容 (1)在文件STM32F10x.s中删除如下内容。 (2)删除其他未定义的相关内容再次编译。报错的内容均删除或者注释直到没错为止。 6、验证 在原有任务的基础上加个i验证 串口打印实验 1、重定向 这个fputc在main中 int fputc( int ch, FILE *f )//重定向 修改数据传输方向
{while(!(USART1-SR (17))){}USART1-DR ch;return ch;
} 2、配置串口 初始化删除多余的东西自己写一个串口一的初始化。 void Uart_Init(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE );//txGPIO_InitStructure.GPIO_PinGPIO_Pin_9;GPIO_InitStructure.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStructure);//rxGPIO_InitStructure.GPIO_PinGPIO_Pin_10;GPIO_InitStructure.GPIO_ModeGPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,GPIO_InitStructure); USART_InitStructure.USART_BaudRate 115200;USART_InitStructure.USART_WordLength USART_WordLength_8b;USART_InitStructure.USART_StopBits USART_StopBits_1;USART_InitStructure.USART_Parity USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx;USART_InitStructure.USART_Clock USART_Clock_Disable;USART_InitStructure.USART_CPOL USART_CPOL_Low;USART_InitStructure.USART_CPHA USART_CPHA_2Edge;USART_InitStructure.USART_LastBit USART_LastBit_Disable;USART_Init( USART1, USART_InitStructure ); USART_Cmd( USART1, ENABLE ); }如何找串口仿真 命名规范 数据类型 命名规范 动态任务的创建 任务是什么 任务是由 C 语言函数实现的。唯一特别的地方是其函数原型必须返回 void并带有一个 void 指针参数。 任务的外观一个永远不返回的函数 任务实验 实现 创建任务函数xTaskCreate任务也不是很复杂的东西任务也就是一个函数 xTaskCreate。简单得说创建一个任务你得提供它的执行函数你得提供它的栈的大小函数的执行空间函数的优先级等重要的条件。因为任务在运行中任务函数有调用关系有局部变量这些都保存在任务的栈里面任务有可能被切换有可能被暂停这时候CPU寄存器中断现场数据都保存在栈里面。 函数原型 BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName, const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask ) 参数说明 pvTaskCode指向任务函数的指针。该函数表示任务要执行的代码。 pcName任务名称字符串。用于调试和跟踪不影响任务功能。也可用于获取任务句柄 usStackDepth任务栈大小以单词为单位。根据任务需求设定过小可能导致栈溢出。 pvParameters传递给任务函数的参数。可以是任意类型的指针。 uxPriority任务优先级。数值越大优先级越高。 pxCreatedTask任务句柄指针。用于存储创建任务后的任务句柄可选参数。可为NULL 返回值 如果任务创建成功返回pdPASS。如果任务创建失败例如内存不足返回错误码。 任务创建成功后系统会自动将其加入到调度队列。调度器会根据任务优先级选择合适的任务执行。 实验 优先级 结论 FreeRTOS中优先级数越大优先级越高两个任务同优先级时通过时间片轮转执行如果有高优先级时高优先级执行一直到高优先级停止执行低优先级才能执行。 延时函数 void vTaskDelay( const TickType_t xTicksToDelay ); 查看延时时间验证 声明个变量a只有任务一执行时才为1其他时候为0然后进入仿真使用虚拟逻辑分析仪查看变量a状态 查看方法进入仿真使用 调度原理 调度器是内核中负责决定在任何特定时间应执行哪些任务的部分。内核可以在任务生命周期内多次挂起并且稍后恢复一个任务。调度策略是调度器用来决定在任何时间点执行哪个任务的算法。非实时多用户系统的策略极有可能使每个任务具有公平比例的处理时间。 FreeRTOS 共支持三种任务调度方式分别为抢占式调度、时间片调度和协程式调度。需要注意的是FreeRTOS 官方对协程式调度做了特殊说明协程式调度用于一些资源非常少的设备上但是现在已经很少用到。虽然协程式调度的相关代码还没有被删除FreeRTOS 官方并未计划继续开发协程式调度。因此不推荐在开发中继续使用协程式调度我们接着理解一下抢占式调度与时间片调度的概念。 抢占式调度 抢占式调度主要时针对优先级不同的任务每个任务都有一个优先级优先级高的任务可以抢占优先级低的任务只有当优先级高的任务发生阻塞或者被挂起低优先级的任务才可以运行。 时间片调度 时间片调度主要针对优先级相同的任务当多个任务的优先级相同时 任务调度器会在每一次系统时钟节拍到的时候切换任务也就是说 CPU 轮流运行优先级相同的任务每个任务运行的时间就是一个系统时钟节拍。 在 FreeRTOS 中的任务存在四种状态分别为运行态、就绪态、阻塞态和挂起态。在 FreeRTOS 运行时任务的状态一定是这四种状态中的一种下面是四种任务状态的介绍。 任务状态 同优先级的任务正在运行所以需要等待。 运行态Running如果一个任务得到 CPU 的使用权即任务被实际执行时那么这个任务处于运行态。如果运行 FreeRTOS 的 MCU 只有一个处理器核心那么在任务时刻都只能有一个任务处理运行态。 就绪态如果一个任务已经能够被执行不处于阻塞态或挂起态但当前还未被执行具有相同优先级或更高优先级的任务正持有 CPU 使用权那么这个任务就处于就绪态。 阻塞态Blocked如果一个任务因延时一段时间或等待外部事件发生那么这个任务就处理阻塞态。例如任务调用了函数 vTaskDelay()进行一段时间的延时那么在延时超时之前这个任务就处理阻塞态。任务也可以处于阻塞态以等待队列、信号量、事件组、通知或信号量等外部事件。通常情况下处于阻塞态的任务都 有一个阻塞的超时时间在任务阻塞达到或超过这个超时时间后即使任务等待的外部事件还没有发生 任务的阻塞态也会被解除。要注意的是处于阻塞态的任务是无法被运行的。 挂起态Suspended任务一般通过函数 vTaskSuspend()和函数 vTaskResums()进入和退出挂起态与阻塞态一样处于挂起态的任务也无法被运行。 挂起任务、恢复任务 挂起任务函数原型 vTaskSuspend( TaskHandle_t xTaskToSuspend ) 参数 xTaskToSuspend需要挂起任务的句柄 创建任务时加上句柄 句柄声明 恢复任务函数原型 void vTaskResume( TaskHandle_t xTaskToResume )参数 TaskToResumex需要恢复任务的句柄 任务删除 vTaskDelete()函数用于删除任务。在使用这个函数时需要提供一个任务句柄作为参数以便通知内核删除哪个任务。 函数原型 void vTaskDelete( TaskHandle_t xTaskToDelete ) 参数 xTaskToDelete需要删除任务的句柄 如果写的是NULL则自杀 空闲任务 当创建的任务大部分时间都处于阻塞状态。当任务处于阻塞状态时它们无法运行因此调度器无法选择它们。必须始终至少有一个任务可以进入运行状态即使在使用 FreeRTOS 的特殊低功耗功能时也是如此在这种情况下如果应用程序创建的任务都无法执行那么执行 FreeRTOS 的微控制器将被置于低功耗模式。为了确保这种情况当调用 vTaskStartScheduler()时调度器会自动创建一个空闲任务。空闲任务除了在一个循环中等待之外几乎不执行其他任何操作因此就像第一个示例中的任务一样它始终能够运行。 空闲任务具有尽可能低的优先级优先级为 0以确保它永远不会阻止更高优先级的应用程序任务进入运行状态。然而这并不妨碍应用程序设计者根据需要创建与空闲任务共享优先级的任务。可以使用 FreeRTOSConfig.h 中的 configIDLE_SHOULD_YIELD 编译时配置常量阻止空闲任务消耗处理时间可以更有效地分配给具有同样优先级的应用程序任务处理时间。运行在最低优先级确保了当更高优先级的任务进入就绪状态时空闲任务会立即从运行状态转换出来。 注意如果一个任务使用 vTaskDelete() API 函数来删除自己那么必须确保空闲任务不会因处理时间不足而受到影响。这是因为空闲任务负责清理由已删除自身的任务所使用的内核资源。 空闲任务钩子函数用途 可以通过使用空闲钩子或空闲回调函数直接在空闲任务中添加应用程序的相关功能。处理一些不紧急的任务。空闲钩子函数是一种函数它在空闲任务循环的每次迭代中自动由空闲任务调用。空闲任务钩子的常见用途包括 执行低优先级、后台或连续处理功能而无需为此目的创建应用程序任务所带来额外的 RAM开销。测量空闲处理能力空闲任务仅在所有更高优先级的应用程序任务没有工作要执行时空闲任务才会运行因此测量分配给空闲任务的处理时间可以清楚地表明有多少处理时间是空闲的。将处理器置于低功耗模式提供了一种简单且自动的方法在没有应用程序处理要执行时节省功耗。 空闲任务钩子函数的实现限制 空闲任务钩子函数绝对不能阻塞或挂起自己。以任何方式阻塞空闲任务都可能导致没有任务能够进入运行态如果一个应用程序任务使用 vTaskDelete() API 函数删除自己那么必须在合理的时间段内将闲任务钩子返回给调用者。这是因为任务被删除后空闲任务负责清理内核资源。如果空闲任务永久保持在空闲钩子函数中则无法进行这种清理。 钩子函数的使用 main函数中找到vTaskStartScheduler()并跳转 vTaskStartScheduler()内可以找到如图的函数 跳转空闲任务函数找到了vApplicationIdleHook()函数就是钩子函数但是需要configUSE_IDLE_HOOK1 右键跳转configUSE_IDLE_HOOK并将configUSE_IDLE_HOOK等于1 编译发现报错内容为vApplicationIdleHook未定义 接下来我们声明写一个vApplicationIdleHook函数并在里面写自己的任务程序就可以了 TaskHandle_t xTask1ToSuspend;
void vApplicationIdleHook( void )
{while(1){printf(我是钩子我的优先级为0\n);}
}
void task1( void *pvParameters )
{for(;;){printf(我是任务1我的优先级高\n);vTaskDelay(10);}
}
void task2( void *pvParameters )
{for(;;){printf(我是任务2我的优先级低\n);vTaskDelete(xTask1ToSuspend);}
}使用CUBE配置FreeRTOS编写程序 1、更新安装freertos插件 2.配置FreeRTOS 创建一个新的工程 3.配置基础硬件 4.最后生成工程MDK内编写程序 void StartTask02(void *argument)
{/* USER CODE BEGIN myTask02 *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);osDelay(100);}/* USER CODE END myTask02 */
}