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

如何在云主机上建设网站大连市的网络平台有几家

如何在云主机上建设网站,大连市的网络平台有几家,自定义wordpress的字体,好用的app推荐大全一、FreeRTOS的介绍 什么是FreeRTOS#xff1f; Free即免费的#xff0c;RTOS的全称是Real Time Operating system,中文就是实时操作系统。 注意#xff1a;RTOS不是指某一个确定的系统#xff0c;而是指一类的操作系统。比如#xff1a;us/OS#xff0c;FreeRTOS Free即免费的RTOS的全称是Real Time Operating system,中文就是实时操作系统。 注意RTOS不是指某一个确定的系统而是指一类的操作系统。比如us/OSFreeRTOSRTXRT-Thread等这些都是RTOS类操作系统。 FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统功能包括任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等可基本满足较小系统的需要。 由于RTOS需占用一定的系统资源(尤其是RAM资源)只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对μC/OS-II、embOS等商业操作系统FreeRTOS操作系统是完全免费的操作系统具有源码公开、可移植、可裁减、调度策略灵活的特点可以方便地移植到各种单片机上运行其最新版本为10.4.4版。                                                                                                                 ------------来自百度                                                                                                               为什么选择FreeRTOS FreeRTOS是免费的 很多半导体厂商产品的SDKSoftware  Development Kit软件开发工具包就使用FreeRTOS作为其操作系统尤其是WiFi、蓝牙这些带有协议线的芯片或模块。 简单因为FreeRTOS的文件数量很少 FreeRTOS资料与源码下载 FreeRTOS™ - FreeRTOS™官网链接 裸机开发与FreeRTOS 上官课程里的简易举例 二、移植FreeRTOS到上官二号平台 手动移植 过程复杂且繁琐对新手(像我这种)不友好如需手动移植参考以下文章 FreeRTOS移植到STM32-CSDN博客链接 使用CubeMX快速移植 快速移植 1.在SYS选项里将Debug设为Serial  Wire并且将Timebase Source设为TIM2其他定时器也行。 2.将RCC里的HSE设置为Crystal/Ceramic Resonator。 3.时钟树配置 4.选择FREERTOS选项并将interface 改为CMSIS_V1。 5.配置项目名称导出项目即可 一些常见问题 1.Timebase Source 为什么不能设置SysTick 裸机时钟默认SysTick但是开启FreeRTOS后FreeRTOS会占用SysTick用来生成1ms的定时用于任务调度所以需要为其他总线提供另外的时钟源。 2.FreeRTOS的版本问题 V2的内核版本更高功能更多在大多数情况下V1版本的内核完全够用。 3.FreeRTOS各项配置选项卡的解释 4.内核配置、函数使能的一些翻译 参考博客FreeRTOS系列第6篇---FreeRTOS内核配置说明_vassertcalled-CSDN博客 三、任务的创建与删除 1.什么是任务 任务可以理解为进程/线程创建一个任务就会在内存开辟一个空间。 比如玩游戏、陪女朋友都可以视为任务 Windows系统中的MarkText、谷歌浏览器、记事本都是任务。 任务通常都有while(1)死循环。 2.任务创建与删除相关函数 任务创建与删除相关函数有如下三个 任务动态创建与静态创建的区别 动态创建任务的堆栈由系统分配而静态创建任务的堆栈由用户自己传递。 通常情况下使用动态方式创建任务。 xTaskCreate 函数原型 1.pvTaskCode指向任务函数的指针任务必须实现为永不返回即连续循环 2.pcName任务的名字主要是用来测试默认情况下最大长度是16 3.pvParameters指定的任务栈的大小 4.uxPriority任务优先级数值越大优先级越大 5.pxCreateTask用于返回已创建任务的句柄可以被引用。 官方案例 vTaskDelete函数原型 只需将待删除的任务句柄传入该函数即可将该任务删除。 当传入的参数为NULL则代表删除任务自身当前正在运行的任务。 3.实操 四、任务的状态 什么是任务调度 调度器就是使用相关的调度算法来决定当前需要执行的哪个任务。 FreeRTOS中开启任务调度的函数是vTaskStartScheduler()但在CubeMX中被封装为osKernelStart()。 FreeRTOS的任务调度规则是怎样的 FreeRTOS是一个实时操作系统它所奉行的调度规则 1.高优先级抢占低优先级任务系统永远执行最高优先级的任务即抢占式调度 2.同等优先级的任务轮转调度即时间片调度 还有一种调度规则是协程式调度但官方已明确表示不更新主要是用在小容量的芯片上用得也不多。 抢占式调度运行过程 egTask1玩游戏         Task2老妈喊你吃饭        Task3女朋友喊你看电视 总结 1.高优先级任务优先执行 2.高优先级任务不停止低优先级任务无法执行 3.被抢占的任务将会进入就绪态。 时间片调度运行过程 总结 1.同等优先级任务轮流执行时间片流转 2.一个时间片大小取决为滴答定时器中断周期 3.注意没有用完的时间片不会再使用下次任务Task3得到执行还是按照一个时间片的时钟节拍运行 五、任务的状态 FreeRTOS中任务共存在4种状态 Running 运行态 当任务处于实际运行状态称之为运行态即CPU的使用权被这个任务占用同一时间仅一个任务牌运行态。 Ready 准备态 处于就绪态的任务是指那些能够运行没有被阻塞和挂起但是当前没有运行的任务因为同优先级或更高优先级的任务正在运行。 Blocked 阻塞态 如果一个任务因延时或等待信号量、消息队列、事件标志组等而处于的状态被称之为阻塞态。 Suspended 挂起态 类似暂停通过调用函数vTaskSuspend()对指定任务进行挂起挂起后这个任务将不被执行只有调用函数xTaskResume()才可以将这个任务从挂起状态恢复。 总结 1.仅就绪态可转变成运行态 2.其他状态的任务想运行必须先转变成就绪态。 任务综合小实验 实验需求 创建4个任务taskLED,taskBEEP,taskKEY1,taskKEY2,任务要求如下 taskLED间隔100ms闪烁LED; taskBEEP间隔1000ms翻转BEEP taskKEY1如果taskLED存在则按下KEY1后删除taskLED否则创建taskLED taskKEY2如果taskBEEP正常运行则按下KEY2后挂起taskBEEP否则恢复taskBEEP。 CubeMX配置 代码实现 /* USER CODE END Header_StartTaskLED */ void StartTaskLED(void const * argument) {/* USER CODE BEGIN StartTaskLED *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);osDelay(100);}/* USER CODE END StartTaskLED */ }/* USER CODE BEGIN Header_StartTaskBeep */ /** * brief Function implementing the TaskBeep thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskBeep */ void StartTaskBeep(void const * argument) {/* USER CODE BEGIN StartTaskBeep *//* Infinite loop */for(;;){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);osDelay(1000);}/* USER CODE END StartTaskBeep */ }/* USER CODE BEGIN Header_StartTaskKEY1 */ /** * brief Function implementing the TaskKEY1 thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskKEY1 */ void StartTaskKEY1(void const * argument) {/* USER CODE BEGIN StartTaskKEY1 *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){printf(KEY1按下\r\n);if(TaskLEDHandle NULL){printf(任务1不存在准备创建任务\r\n);osThreadDef(TaskLED, StartTaskLED, osPriorityNormal, 0, 128);TaskLEDHandle osThreadCreate(osThread(TaskLED), NULL);if(TaskLEDHandle ! NULL)printf(任务1创建完成\r\n);}else{printf(删除任务1\r\n);osThreadTerminate(TaskLEDHandle);TaskLEDHandle NULL;}}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskKEY1 */ }/* USER CODE BEGIN Header_StartTaskKEY2 */ /** * brief Function implementing the TaskKEY2 thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskKEY2 */ void StartTaskKEY2(void const * argument) {/* USER CODE BEGIN StartTaskKEY2 */static int flag 0;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){printf(KEY2按下\r\n);if(flag 0){osThreadSuspend(TaskBeepHandle);printf(任务2已暂停\r\n);flag 1;}else{osThreadResume(TaskBeepHandle);printf(任务2已恢复\r\n);flag 0;}}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskKEY2 */ } 六、队列 什么是队列 队列又称消息队列是一种常用于任务间通信的数据结构队列可以在任务与任务间、中断和任务间传递信息。 为什么不使用全局变量 如果使用全局变量兔子任务1修改了变量a等待树懒任务3处理但树懒处理速度很慢在处理数据的过程中狐狸任务2有可能又修改了变量a导致树懒有可能得到的不是正确的数据。 在这种情况下就可以使用队列。兔子和狐狸产生的数据放在流水线上树懒可以慢慢一个一个依次处理。关于队列的几个名词 队列项目队列中的每一个数据 队列长度队列能够存储队列项目的最大数量 创建队列时需要指定队列长度及队列项目大小。 队列特点 1.数据入队出队方式 通常采用先进先出FIFO的数据存储缓冲机制即陷入队的数据会先从队列中被读取。 也可以配置为后进先出LIFO方式但用得比较少。 2.数据传递方式 采用实际值传递即将数据拷贝到队列中进行传递也可以传递指针在传递较大的数据的时候采用指针传递。 3.多任务访问 队列不属于某个任务任何任务和中断都可以向队列发送/读取消息。 4.出队、入队阻塞 当任务向一个队列发送消息时可以指定一个阻塞时间假设此时当队列已满无法入队。 阻塞时间如果设置为 0直接返回不会等待 0~port_MAX_DELAY:等待设定的阻塞时间若在该时间内还无法入队超时后直接返回不再等待 port_MAX_DELAY:死等一直等到可以入队为止出队阻塞与入队阻塞类似 队列相关的API函数 1.创建队列 参数 xQueuelength队列可同时容纳的最大数列 uxItemSize存储队列中的每个数据项所需的大小以字节为单位。 返回值 如果队列创建成功则返回所创建队列的句柄如果创建队列所需的内存无法分配则返回NULL。 2.写队列 写队列总共有以下几个函数 参数 xQueue队列的句柄数据项将发送到此队列 pvItemToQueue待写入数据 xTicksToWait:阻塞超时时间。 返回值 如果成功写入数据返回pdTURE否则返回errQUEUE_FULL。 3.读队列 读队列总共有以下几个函数 参数 xQueue待读取的队列 pvItemToQueue数据读取缓冲区 xTicksToWait阻塞超时时间。 实操 实验需求 创建一个队列按下KEY1向队列发送数据按下KEY2向队列读取数据 CubeMX配置 代码实现 #include stdio.h /* USER CODE END Header_StartTaskSend */ void StartTaskSend(void const * argument) {/* USER CODE BEGIN StartTaskSend */uint16_t buf 100;BaseType_t status;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){status xQueueSend(myQueue01Handle,buf,0);if(status pdTRUE)printf(写入队列成功写入值%d\r\n,buf);elseprintf(写入队列失败\r\n); }while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskSend */ }/* USER CODE BEGIN Header_StartTaskReceive */ /** * brief Function implementing the TaskReceive thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskReceive */ void StartTaskReceive(void const * argument) {/* USER CODE BEGIN StartTaskReceive */uint16_t buf;BaseType_t status;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){status xQueueReceive(myQueue01Handle,buf,0);if(status pdTRUE)printf(读取队列成功读取值%d\r\n,buf);elseprintf(读取队列失败\r\n); }while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskReceive */ } 七、二值信号量 什么是信号量 信号量Semaphore是在多任务环境下使用的一种机制是可以用来保证两个或多个关键代码不被并发调用。 信号量这个名字我们可以把它拆分来看信号可以起到通知信号的作用然后我们的量还可以用来表示资源的数量当我们的量只有0和1的时候它就可以被称作二值信号量只有两个状态当我们的那个量没有限制的时候它就可以被称作为计数型信号量。 信号量也是队列的一种。 什么是二值信号量 二值信号量其实就是一个长度为1大小为零的队列只有和1两种状态通常情况下我们用它来进行互斥访问或任务同步。 互斥访问比如门钥匙只有获取到钥匙才可以开门。 任务同步比如我录完视频你才可以看视频。 二值信号量相关API函数 1.创建二值信号量 参数 无 返回值 成功返回对应二值信号量的句柄; 失败返回NULL。 2.释放二值信号量 参数 xSemaphore要释放的信号量句柄。 返回值 成功返回pdPASS; 失败返回errQUEUE_FULL。 3.获取二值信号量 参数 xSemaphore要获取的信号量句柄 xTicksToWait超时时间0表示不超时portMAX_DELAY表示卡死等待。 返回值 成功返回pdPASS; 失败返回errQUEUE_FULL。 实操 实验需求 创建一个二值信号量按下KEY1则释放信号量按下KEY2获取信号量。 CubeMX配置 代码实现 #includestdio.h myBinarySem01Handle xSemaphoreCreateBinary();//自己创建的句柄 void StartTaskGive(void const * argument) {/* USER CODE BEGIN StartTaskGive *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){if(xSemaphoreGive(myBinarySem01Handle) pdTRUE)printf(二值信号量放入成功\r\n);elseprintf(二值信号量放入失败\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskGive */ }/* USER CODE BEGIN Header_StartTaskTake */ /** * brief Function implementing the TaskTake thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskTake */ void StartTaskTake(void const * argument) {/* USER CODE BEGIN StartTaskTake *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){if(xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY) pdTRUE)printf(二值信号量获取成功\r\n);elseprintf(二值信号量获取失败\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskTake */ } 八、计数型信号量 什么是计数型信号量 计数型信号量相当于队列长度大于1的队列因此计数型信号量能够容纳多个资源这在计数型信号量被创建的时候确定的。 计数型信号量相关API函数 计数型信号量的释放和获取与二值信号量完全相同 参数 uxMaxCount可以达到的最大计数值 uxInitialCount创建信号量时分配给信号量的计数值。 返回值 成功返回对应计数型信号量的句柄 失败返回NULL 实操 实验需求 创建一个计数型信号量按下KEY1则释放信号量按下KEY2获取信号量。 CubeMX配置 代码实现 #include stdio.h myCountingSem01Handle xSemaphoreCreateCounting(3,0);//自己写的 void StartTaskGive(void const * argument) {/* USER CODE BEGIN StartTaskGive *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){if(xSemaphoreGive(myCountingSem01Handle) pdTRUE)printf(二值信号量放入成功\r\n);elseprintf(二值信号量放入失败\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskGive */ }/* USER CODE BEGIN Header_StartTaskTake */ /** * brief Function implementing the TaskTake thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskTake */ void StartTaskTake(void const * argument) {/* USER CODE BEGIN StartTaskTake *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){if(xSemaphoreTake(myCountingSem01Handle,0) pdTRUE)printf(二值信号量获取成功\r\n);elseprintf(二值信号量获取失败\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskTake */ } 九、 互斥量 什么是互斥量 在多数情况下互斥型信号量和二值型信号非常相似但是从功能上二值型信号量用于同步而互斥型信号量用于资源保护。 互斥型信号量和二值型信号量还有一个最大的区别互斥型信号量可以有效解决优先级反转现象。 什么是优先级反转 以上图为例系统中有3个不同优先级的任务H/M/L最高优先级任务H和最低优先级任务L通过信号量机制共享资源目前任务L占有资源锁定了信号量TaskH运行后将被阻塞直到TaskL释放信号量后TaskH才能够退出阻塞状态继续运行。但是TaskH在等待TaskL释放信号量的过程中中等优先级任务M抢占了任务L从而延迟了信号量的释放时间导致TaskH阻塞了更长的时间这种现象称为优先级倒置或反转。 优先级继承当一个互斥信号量正在被一个低优先级的任务持有时如果此时有个高优先级的任务也尝试获取这个互斥信号量那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。 优先级继承并不能完全的消除优先级反转的问题它只是尽可能的降低优先级反转带来的影响。 互斥量相关API函数 互斥信号量不能用于中断服务函数中 参数 无 返回值 成功返回对应互斥量的句柄 失败返回NULL。 实操 实验需求 1.演示优先级反转 2.使用互斥量优化优先级反转问题 CubeMX配置 优先级反转演示配置 现象 互斥量优化优先级反转配置 现象 代码实现 优先级反转与互斥量优化的区别在于句柄不同 #include stdio.h void StartTaskH(void const * argument) {/* USER CODE BEGIN StartTaskH *//* Infinite loop */for(;;){xSemaphoreTake(myMutex01Handle,portMAX_DELAY);printf(TaskH:我获取到信号量正在运行中。\r\n);HAL_Delay(1000);printf(TaskH:我运行完成了。\r\n);xSemaphoreGive(myMutex01Handle);osDelay(1000);}/* USER CODE END StartTaskH */ }/* USER CODE BEGIN Header_StartTaskM */ /** * brief Function implementing the TaskM thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskM */ void StartTaskM(void const * argument) {/* USER CODE BEGIN StartTaskM *//* Infinite loop */for(;;){printf(TaskM:我就是为了占用CPU资源。。\r\n);osDelay(1000);}/* USER CODE END StartTaskM */ }/* USER CODE BEGIN Header_StartTaskL */ /** * brief Function implementing the TaskL thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskL */ void StartTaskL(void const * argument) {/* USER CODE BEGIN StartTaskL *//* Infinite loop */for(;;){xSemaphoreTake(myMutex01Handle,portMAX_DELAY);printf(TaskL:我获取到信号量正在运行中。\r\n);HAL_Delay(3000);printf(TaskL:我运行完成了。\r\n);xSemaphoreGive(myMutex01Handle);osDelay(1000);}/* USER CODE END StartTaskL */ } 十、事件标志组 什么是事件标志组 事件标志位表明某个事件发生联想全局变量flag通常按位表示每一个位表示一个事件高八位不算。 事件标志组是一组事件标志位的集合可以简单的理解事件标志组就是一个整数。 事件标志组本质是一个16位或32位无符号的数据类型EventBits_t由configUSE_16_BIT_TICKS决定。 虽然使用了32位无符号的数据类型变量来存储标志但其中的高8位用作存储事件标志组的控制信息低24位用作存储事件标志所以说一个事件组最多可以存储24个事件标志 事件标志组相关API函数 1.创建事件标志组 参数 无 返回值 成功返回对应事件标志组的句柄 失败返回NULL。 2.设置事件标志位 参数 xEventGroup对应事件的句柄 uxBitsToSet指定要在事件组中设置的一个或多个位的按位值。 返回值 设置之后事件组中的事件标志位值。 3.清除事件标志位 参数 xEventGroup对应事件的句柄 uxBitsToClear指定要在事件组中清除一个或多个的按位值。 返回值 返回之前清除事件组中事件标志位的值。 4.等待事件标志位 参数 xEventGroup对应事件的句柄 uxBitsToWaitFor指定事件组中要等待的一个或多个事件位的按位值 xClearOnExitpdTRUE——清除对应事件位pdFALSE——不清除 xWaitForAllBitspdTRUE——所有等待事件全为1逻辑与pdFALSE——等待的事件位有一个为1逻辑或 xTicksToWait超时。 返回值 等待的事件标志位值等待事件标志位成功返回等待到的事件标志位 其他值等待事件标志位失败返回事件组中的事件标志位。 实操 实验需求 创建一个事件标志组和两个任务Task01和Task02Task01检测按键如果检测到KEY1和KEY2都按过则执行Task02。 CubeMX配置 代码实现 #include stdio.h /* USER CODE BEGIN Variables */EventGroupHandle_t eventgroup_handle; /* USER CODE END Variables *//* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */eventgroup_handle xEventGroupCreate(); /* USER CODE END RTOS_THREADS */void StartTask01(void const * argument) {/* USER CODE BEGIN StartTask01 *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){ xEventGroupSetBits(eventgroup_handle,0x01);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){xEventGroupSetBits(eventgroup_handle,0x02);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(1); }/* USER CODE END StartTask01 */ }/* USER CODE BEGIN Header_StartTask02 */ /** * brief Function implementing the Task02 thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTask02 */ void StartTask02(void const * argument) {/* USER CODE BEGIN StartTask02 */EventBits_t event_bit 0;/* Infinite loop */for(;;){event_bit xEventGroupWaitBits(eventgroup_handle,0x01 | 0x02,pdTRUE,pdFALSE,portMAX_DELAY);printf(返回值%#x,逻辑或成功\r\n,event_bit);//内容根据xWaitForAllBits参数来更改或/与osDelay(1);}/* USER CODE END StartTask02 */ } 十一、任务通知 什么是任务通知 FreeRTOS从版本V8.2.0开始提供任务通知这个功能每个任务都有一个32位的通知值。按照FreeRTOS官方的说法使用消息通知比通过二进制信号量方式解除阻塞任务快45%并且更加省内存无需创建队列。 在大多数情况下任务通知可以代替二值信号量、计数信号量、信号标志组可以代替长度为1的队列可以保存一个32位整数或指针值并且任务通知速度更快、使用的RAM更少 任务通知值的更新方式 FreeRTOS提供一下几种方式发送通知给任务 发送消息给任务如果有通知未读不覆盖通知值 发送消息给任务直接覆盖通知值 发送消息给任务设置通知值的一个或者多个位 发送消息给任务递增通知值。 通过对以上方式的合理使用可以在一定场合下代替原本的队列、信号量、事件标志组等。 任务通知的优势和劣势 任务通知的优势 1.使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多。 2.使用其他方法时都要先创建对应的结构体使用任务通知时无需额外创建结构体。 任务通知的劣势 1.只有任务可以等待通知中断服务函数中不可以因为中断没有TCB。 2.通知只能一对一因为通知必须指定任务。 3.等待通知的任务可以被阻塞但是发送消息的任务任何情况下都不会被阻塞等待。 4.任务通知是通过更新任务通知值来发送数据的任务结构体中只有一个任务通知值只能保持一个数据。 任务通知相关API函数 1.发送通知 参数 xTaskToNotify需要接收通知的任务句柄 ulValue用于更新接收任务通知值具体如何更新由形参eAction决定 eAction一个枚举代表如何使用任务通知的值。 返回值 如果被通知任务还没取走上一个通知又接收了一个通知则这次通知值未能更新并返回pdFALSE,而其他情况均返回pdPASS。 参数 xTaskToNotify需要接收通知的任务句柄 ulValue用于更新接收任务通知值具体如何更新由形参eAction决定 eAction一个枚举代表如何使用任务通知的值 pulPreviousNotifyValue对象任务的上一个任务通知值如果为NULL则不需要回传这个时候就等价于函数xTaskNotify()。 返回值 如果被通知任务还没取走上一个通知又接收了一个通知则这次通知值未能更新并返回pdFALSE,而其他情况均返回pdPASS。 参数 xTaskNotify接收通知的任务句柄并让其自身的任务通知值加1。 返回值 总是返回pdPASS。 2.等待通知 等待通知API通知只能用在任务不可应用于中断中 参数 xClearCountOnExit指定在成功接收通知后将通知值清零或减1pdTRUE把通知值清零二值信号量pdFALSE把通知值减1计数型信号量 xTicksToWait阻塞等待任务通知值的最大时间。 返回值 0接收失败 非0接收成功返回任务通知的通知值。 ulBitsToClearOnEntry函数执行前清零任务通知值那些位 ulBitsToClearOnExit表示在函数退出前清零任务通知值那些位在清零前接收到的任务通知值会先被保存到形参*pulNotificationValue中 pulNotificationValue:用于保存接收到的任务通知值。如果不需要使用则设置为NULL即可 xTicksToWait等待消息通知的最大等待时间。 实操 实验需求 1.模拟二值信号量 2.模拟计数型信号量 3.模拟事件标志组 4.模拟邮箱 CubeMX配置 代码实现 1.模拟二值信号量 #include stdio.hvoid StartTaskSend(void const * argument) {/* USER CODE BEGIN StartTaskSend *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){xTaskNotifyGive(TaskReceiveHandle);printf(任务通知模拟二值信号量发送成功\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskSend */ }/* USER CODE BEGIN Header_StartTaskReceive */ /** * brief Function implementing the TaskReceive thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskReceive */ void StartTaskReceive(void const * argument) {/* USER CODE BEGIN StartTaskReceive */uint32_t rev 0;/* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){rev ulTaskNotifyTake(pdTRUE,portMAX_DELAY);if(rev ! 0)printf(任务通知模拟二值信号量接收成功\r\n);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}osDelay(10);}/* USER CODE END StartTaskReceive */ } 2.模拟计数型信号量 rev ulTaskNotifyTake(pdFALSE,portMAX_DELAY);//区别于二值信号量的接收任务中参数变成pdFALSE 3. 模拟事件标志组 #include stdio.h void StartTaskSend(void const * argument) {/* USER CODE BEGIN StartTaskSend *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){ printf(将bit0位置1\r\n);xTaskNotify(TaskReceiveHandle,0x01,eSetBits);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){printf(将bit1位置1\r\n);xTaskNotify(TaskReceiveHandle,0x02,eSetBits); }while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);} osDelay(10);}/* USER CODE END StartTaskSend */ }/* USER CODE BEGIN Header_StartTaskReceive */ /** * brief Function implementing the TaskReceive thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskReceive */ void StartTaskReceive(void const * argument) {/* USER CODE BEGIN StartTaskReceive */uint32_t notify_val 0,event_bit 0;/* Infinite loop */for(;;){xTaskNotifyWait(0,0xFFFFFFFF,notify_val,portMAX_DELAY);if(notify_val 0x01)event_bit | 0x01;if(notify_val 0x02)event_bit | 0x02;if(event_bit (0x01 | 0x02)){printf(任务通知模拟标志组成功\r\n);event_bit 0;}osDelay(1);}/* USER CODE END StartTaskReceive */ } 4.模拟邮箱大小为1的队列 void StartTaskSend(void const * argument) {/* USER CODE BEGIN StartTaskSend *//* Infinite loop */for(;;){if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET){                printf(按键1按下\r\n);xTaskNotify(TaskReceiveHandle,0x01,eSetValueWithOverwrite);}while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) GPIO_PIN_RESET);}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){osDelay(20);if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET){printf(按键2按下\r\n);xTaskNotify(TaskReceiveHandle,0x02,eSetValueWithOverwrite);                }while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) GPIO_PIN_RESET);}        osDelay(10);}/* USER CODE END StartTaskSend */ }/* USER CODE BEGIN Header_StartTaskReceive */ /** * brief Function implementing the TaskReceive thread. * param argument: Not used * retval None */ /* USER CODE END Header_StartTaskReceive */ void StartTaskReceive(void const * argument) {/* USER CODE BEGIN StartTaskReceive */uint32_t notify_val 0;/* Infinite loop */for(;;){xTaskNotifyWait(0,0xFFFFFFFF,notify_val,portMAX_DELAY);printf(接收到的通知值%d\r\n,notify_val);osDelay(1);}/* USER CODE END StartTaskReceive */ } 十二、延时函数 什么是延时函数 延时函数是一种暂停程序执行一段时间的函数可以用来实现简单的延迟效果 延时函数分类 相对延时vTaskDelay 绝对延时vTaskDelayUntil。 vTaskDelay与HAL_Delay的区别 vTaskDelay作用是让任务阻塞任务阻塞后RTOS系统调用其它处于就绪状态的优先级最高的任务来执行 HAL_Delay一直不停的调用获取系统时间的函数直到指定的时间流逝然后退出。故其占用了全部CPU时间。 十三、软件定时器 什么是定时器 简单可以理解为闹钟到达指定一段时间后就会响铃。 STM32芯片自带硬件定时器精度较高达到定时时间后会触发中断也可以生成PWM、输入捕获、输出比较等等功能强大但是由于硬件的限制。个数有限。 软件定时器也可以实现定时功能达到定时时间后可调用回调函数可以在回调函数里处理信息。 软件定时器优缺点 优点 1.简单、成本低 2.只要内存足够可创建多个。 缺点 精度较低容易受中断影响在大多数情况下够用但对于精度要求比较高的场合不建议使用。 软件定时器原理 定时器是一个可选的、不属于FreeRTOS内核的功能它是由定时器服务任务来提供的。在调用函数vTaskStartScheduler()开启任务调度器的时候会创建一个用于管理软件定时器的任务这个任务就叫做软件定时器服务任务。 1.负责软件定时器超时的逻辑判断 2.调用超时软件定时器的超时回调函数 3.处理软件定时器命令队列 FreeRTOS提供了很多定时器有关的API函数这些API函数大多都使用FreeRTOS的队列发送命令给定时器服务任务。这个队列叫做定时器命令队列。定时器命令队列是提供给FreeRTOS的软件定时器使用的用户不能直接访问。 软件定时器相关配置 软件定时器有一个定时器服务和定时器命令队列这两个东西肯定是要配置的相关的配置也是放到文件FreeRTOSConfig.h中的涉及到的配置如下 1、configUSE_TIMERS 如果要使用软件定时器的宏configUSE_TIMERS一定要设置为1当设置为1的话定时器服务任务就会在启动FreeRTOS调度器的时候自动创建。 2、configTIMER_TASK_PRIORITY 设置软件定时器服务任务的任务优先级可以为0~configMAX_PRIORITIES-1。优先级一定要根据实际的应用要求来配置。如果定时器服务任务的优先级设置的高的话定时器命令从队列中的命令和定时器回调函数就会及时的得到处理。 3、configTIMER_QUEUE_LENGTH 此宏用来设置定时器命令队列长度。 4、configTIMER_TASK_STACK_DEPTH 此宏用来设置定时器服务任务的任务堆栈大小 单次定时器和周期定时器 单次定时器只超时一次调用一次回调函数可手动再开启定时器 周期定时器多次超时多次调用回调函数。 软件定时器相关的API函数 1.创建软件定时器 参数 pcTimerName软件定时器名称 xTimerPeriodInTicks定时超时时间单位系统时钟节拍。宏pdMS_TO_TICKS()可用于将以毫秒为单位指定的时间转化为以tick为单位指定的时间 uxAutoReload定时器模式pdTRUE周期定时器pdFALSE单次定时器 pvTimerID软件定时器ID用于多个软件定时器公用一个超时回调函数 pxCallbackFunction软件定时器超时回调函数 返回值 成功定时器句柄 失败NULL。 2.开启软件定时器 参数 xTimer待开启的软件定时器的句柄 xTicksToWait发送命令到软件定时器命令队列的最大等待时间。 返回值 pdPASS开启成功 pdFAIL开启失败。 3.停止软件定时器 参数 xTimer待开启的软件定时器的句柄 xTicksToWait发送命令到软件定时器命令队列的最大等待时间。 返回值 pdPASS开启成功 pdFAIL开启失败。 4.复位软件定时器 该功能将使软件定时器的重新开启定时时复位后的软件定时器以复位时的时刻作为开启时刻。 参数 xTimer待开启的软件定时器的句柄 xTicksToWait发送命令到软件定时器命令队列的最大等待时间。 返回值 pdPASS开启成功 pdFAIL开启失败。 5.更改软件定时器定时时间 参数 xTimer待开启的软件定时器的句柄 xTicksToWait发送命令到软件定时器命令队列的最大等待时间 xNewPeriod新的定时超时时间单位系统时钟节拍。 返回值 pdPASS开启成功 pdFAIL开启失败。 实操 实验需求 创建两个定时器 定时器1周期定时器每1秒打印一次Periodic Timer 定时器2单次定时器启动后2秒打印一次Single Timer CubeMX配置 代码实现 #include stdio.h void StartDefaultTask(void const * argument) {/* USER CODE BEGIN StartDefaultTask *///osTimerStart(Timer01Handle,1000);xTimerChangePeriod(Timer01Handle,pdMS_TO_TICKS(1000),0);osTimerStart(Timer02Handle,2000);/* Infinite loop */for(;;){osDelay(1);}/* USER CODE END StartDefaultTask */ }/* Callback01 function */ void Callback01(void const * argument) {/* USER CODE BEGIN Callback01 */printf(Periodic Timer\r\n);/* USER CODE END Callback01 */ }/* Callback02 function */ void Callback02(void const * argument) {/* USER CODE BEGIN Callback02 */printf(Single Timer\r\n);/* USER CODE END Callback02 */ } 十四、中断管理 中断定义 程序执行过程中CPU会遇到一些特殊情况是正在执行的程序被“中断”cpu中止原来正在执行的程序转到处理异常情况或特殊事件的程序去执行结束后再返回到原被中止的程序处(断点)继续执行 中断优先级 任何中断的优先级都大于任务 在我们的操作系统中断同样是具有优先级的并且我们也可以设置它的优先级但是它的优先级并不是从0~15默认情况下它是从5~15,0~4这5个中断优先级不是FreeRTOS控制的5是取决于configMAX_SYSCALL_INTERRUPT_PRIORITY。 相关注意 1.在中断中必须使用中断相关的函数 2.中断服务函数运行时间越短越好。 实操 实验需求 创建一个队列及一个任务按下按键KEY1触发中断在中断服务函数里向队列里发送数据任务则阻塞接收队列数据。 CubeMX配置 代码实现 stm32f1xx_it.c #include cmsis_os.h /* USER CODE BEGIN PV */ extern osMessageQId myQueue01Handle; /* USER CODE END PV */ /* USER CODE BEGIN 1 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {uint32_t snd 1;xQueueSendFromISR(myQueue01Handle,snd,NULL); } /* USER CODE END 1 */ freertos.c #include stdio.h void StartDefaultTask(void const * argument) {/* USER CODE BEGIN StartDefaultTask */uint32_t rev 0;/* Infinite loop */for(;;){if(xQueueReceive(myQueue01Handle,rev,portMAX_DELAY) pdTRUE)printf(rev %d\r\n,rev);osDelay(1);}/* USER CODE END StartDefaultTask */ }
http://www.dnsts.com.cn/news/28550.html

相关文章:

  • 建设用地规划公示在哪个网站查免费软件英文
  • 30天网站建设实录视频云盘东莞哪里有做企业网站的
  • 萧山网站建设争锋网络企业网站快速优化排名
  • 阿里巴巴网站费用怎么做分录wordpress如何本地安装
  • 开源网站 做镜像 如何做企业建设网站公司哪家好
  • jsp网站维护大气婚庆网站源码
  • 怎么不花钱建立网站网站建设亿金手指花总12
  • 做网投网站好旅游网页设计模板网站免费
  • 可以推广的平台网站图片都是站外连接对seo
  • 公司建一个网站要多少钱当铺网站建设方案
  • 网站注销备案查询wordpress 用户发帖
  • 买app的网站建设wordpress入门主题
  • 中国新农村建设网站投稿网站的安全怎么做
  • 怎么建立自己公司的网站上海网站建设的英文
  • h5网站制作平台微信贷款怎么申请开通
  • 免费seo网站诊断免费网站建设带数据库模板下载
  • 潍坊高新区建设局网站无代码建站
  • 伍菲网站建设东源县住房和城乡建设部网站
  • 怎样做淘客网站东莞哪家公司做网站比较好
  • 建立一个网站怎样赚钱阜新小程序 阜新网站建设开发
  • 扬州电子商务网站建设北京网络营销顾问
  • 搜索郑州网站腾讯云服务器手动WordPress
  • 厚街镇网站仿做南京公司网站
  • 怎么做交易平台网站深圳哪家网站公司好
  • 自适应网站价格小火花自媒体平台
  • 黑龙江省建设工程网第三方关键词优化排名
  • 潍坊网站开发高手浦东网站制作
  • 怎么做属于自己的域名网站seo是什么意思 为什么要做seo
  • 网站建设收费明细表福州网站开发一般多少钱
  • 武安做网站北京seo优化技术