彻底掌握FreeRTOS中的务通知(Task Notifications)

2023-05-16

​在之前的文章中已经讲解了很多种用于任务件通信的机制,包括队列、事件组和各种不同类型的信号量。使用这些机制都需要创建一个通信对象

事件和数据不会直接发送到接收任务或接收ISR,而是发送到通信对象(也就是发送到队列、事件组、信号量)。同样,任务和ISR从通信对象接收事件和数据,而不是直接从发送事件或数据的任务或ISR接收事件和数据。

任务通知允许任务与其他任务交互,并与ISR同步,而不需要单独的通信对象。通过使用任务通知,任务或ISR可以直接向接收任务发送事件。

原文链接:FreeRTOS全解析-11.任务通知(Task Notifications)

目录

1.任务通知的优缺点

1.1优点

1.2缺点

2.使用任务通知

2.1简易版

2.2复杂版


1.任务通知的优缺点

1.1优点

1.更快,使用任务通知将事件或数据发送到任务要比使用队列、信号量或事件组更快。

2.更节约内存,使用任务通知将事件或数据发送到任务所需的RAM比使用队列、信号量或事件组执行等效操作所需的RAM少得多。因为通信对象(队列、信号量或事件组),要先创建,才能使用,而启用任务通知功能每个任务只有8字节的RAM的固定开销。

1.2缺点

部分情况无法使用

(1)向ISR发送事件或数据

通信对象可用于将事件和数据从ISR发送到任务,并从任务发送到ISR。任务通知可用于将事件和数据从ISR发送到任务,但是它们不能用于将事件或数据从任务发送到ISR。

(2)有多个接收任务

通信对象可以被任何知道其句柄的任务或ISR访问。任意数量的任务和ISR都可以接收通信对象。任务通知直接发送到接收任务,因此只能由接收通知的任务处理。

(3)缓冲多个数据项

队列是一种通信对象,一次可以保存多个数据项。已发送到队列但尚未从队列接收的数据将在队列对象中进行缓冲。任务通知通过更新接收任务的通知值来向任务发送数据。任务的通知值一次只能保存一个值。

(3)发送到多个任务

事件组是一个通信对象,可用于一次向多个任务发送事件。任务通知直接发送给接收任务,因此只能由接收任务处理。

(3)在阻塞态下等待发送完成

如果一个通信对象暂时处于不能再写入数据或事件的状态(例如,当队列已满时,不能再向队列发送数据),那么尝试写入该对象的任务可以选择进入阻塞态,等待机会去完成写入操作。如果任务试图将任务通知发送给已经有通知挂起的任务,则发送任务不能在阻塞态下等待接收任务重置其通知状态。

2.使用任务通知

要开启任务通知功能,首先需要在FreeRTOSConfig.h中将configUSE_TASK_NOTIFICATIONS设置为1。

当configUSE_TASK_NOTIFICATIONS设置为1时,每个任务都有一个“通知状态”,可以是“Pending”或“Not-Pending”,以及一个“通知值”,这是一个32位无符号整数。当任务收到通知时,其通知状态设置为“Pending”。当任务读取其通知值时,其通知状态设置为“Not-Pending”。任务可以在Blocked状态下等待其通知状态变为“Pending”。

2.1简易版

xTaskNotifyGive() API函数

xTaskNotifyGive()直接向任务发送通知,并增加接收任务的通知值。调用xTaskNotifyGive()将把接收任务的通知状态设置为pending(如果它还没有挂起的话)。

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

ulTaskNotifyTake() API函数

ulTaskNotifyTake()允许任务在Blocked状态下等待其通知值大于零,并在返回之前减少(减去1)或清除任务的通知值。

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );

例子1:延迟中断处理

const TickType_t xInterruptFrequency = pdMS_TO_TICKS( 500UL );static void vHandlerTask( void *pvParameters ){  const TickType_t xMaxExpectedBlockTime = xInterruptFrequency + pdMS_TO_TICKS( 10 );  uint32_t ulEventsToProcess;  for( ;; )  {    ulEventsToProcess = ulTaskNotifyTake( pdTRUE, xMaxExpectedBlockTime );    if( ulEventsToProcess != 0 ) {      while( ulEventsToProcess > 0 ) {        vPrintString( "Handler task - Processing event.\r\n" );        ulEventsToProcess--;      }    } else {      //如果运行到这,表示超时时间内,中断没有发生    }  }}static uint32_t ulExampleInterruptHandler( void ){  BaseType_t xHigherPriorityTaskWoken;  xHigherPriorityTaskWoken = pdFALSE;  vTaskNotifyGiveFromISR( xHandlerTask,&xHigherPriorityTaskWoken );  portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}#define mainINTERRUPT_NUMBER 3static void vPeriodicTask( void *pvParameters ){  const TickType_t xDelay500ms = pdMS_TO_TICKS( 500UL );  vTaskDelay( xDelay500ms );  vPrintString( "Periodic task - About to generate an interrupt.\r\n" );  vPortGenerateSimulatedInterrupt( mainINTERRUPT_NUMBER );  vPrintString( "Periodic task - Interrupt generated.\r\n\r\n\r\n" );}

如上是一个利用任务通知来延迟中断处理的例子vPeriodicTask函数模拟周期性中断,在中断前会打印Periodic task - About to generate an interrupt.中断后会打印Periodic task - Interrupt generated.

ulExampleInterruptHandler函数为中断处理函数,但在这个函数中并不真正进行处理,只是采用vTaskNotifyGiveFromISR函数,给出任务通知,vHandlerTask函数,才是真正的处理函数,vHandlerTask函数作为一个任务来运行,调用ulTaskNotifyTake函数进入阻塞态,以等待任务通知的到来。

ulTaskNotifyTake()中xClearCountOnExit参数被设置为pdTRUE,这将导致在ulTaskNotifyTake()返回之前,接收任务的通知值被清除为零。也就是说必须处理所有的任务通知。

例子2:UART发送

外围设备上的一些操作需要较长的时间才能完成。比如高精度ADC转换,以及在UART上传输大数据包。可以通过轮询(重复读取)外设的状态寄存器,以确定操作何时完成。然而,轮询非常浪费CPU,因为它占用CPU,而没有执行任何实质性操作。

当然我们可以利用中断,操作处理任务take信号量进入阻塞,等待发生中断,在其对应中断处理函数中give信号量,来替代轮询。

比如uart发送函数,利用二进制信号量

BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength ){  BaseType_t xReturn;  /* 确保信号量为0 */  xSemaphoreTake( pxUARTInstance->xTxSemaphore, 0 );  /* 启动传输*/  UART_low_level_send( pxUARTInstance, pucDataSource, uxLength );  /* 等待传输完毕 */  xReturn = xSemaphoreTake( pxUARTInstance->xTxSemaphore, pxUARTInstance->xTxTimeout );  return xReturn;}/*发送完毕中断服务函数*/void xUART_TransmitEndISR( xUART *pxUARTInstance ){  BaseType_t xHigherPriorityTaskWoken = pdFALSE;  /* 清除中断 */  UART_low_level_interrupt_clear( pxUARTInstance );  /* give信号量 */  xSemaphoreGiveFromISR( pxUARTInstance->xTxSemaphore, &xHigherPriorityTaskWoken );  portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}

但是这种方式需要创建信号量才能使用,创建信号量就涉及占用RAM。可以用任务通知代替:

BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength ){  BaseType_t xReturn;  /* 保存调用该函数的任务句柄. */  pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();  /* 确保任务通知为0. */  ulTaskNotifyTake( pdTRUE, 0 );  /*启动传输. */  UART_low_level_send( pxUARTInstance, pucDataSource, uxLength );  /* 阻塞等待发送完成.*/  xReturn = ( BaseType_t ) ulTaskNotifyTake( pdTRUE, pxUARTInstance->xTxTimeout );  return xReturn;}/*-----------------------------------------------------------*//* 发送完成中断服务函数. */void xUART_TransmitEndISR( xUART *pxUARTInstance ){  BaseType_t xHigherPriorityTaskWoken = pdFALSE;  /* 清除中断. */  UART_low_level_interrupt_clear( pxUARTInstance );  /* 发送任务通知. */  vTaskNotifyGiveFromISR( pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken );  portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}

2.2复杂版

xTaskNotify()API函数

xTaskNotify()比xTaskNotifyGive()更灵活、更强大,由于这种额外的灵活性和强大功能,使用起来也稍微复杂一些。

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,                        uint32_t ulValue,                        eNotifyAction eAction );BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,                        uint32_t ulValue,                        eNotifyAction eAction,                        BaseType_t *pxHigherPriorityTaskWoken );

eAction是一个枚举型变量

eAction的值

作用

eNoAction

接收任务的通知状态设置为挂起,而不更新其通知值。未使用xTaskNotify() ulValue参数。替代二进制信号量

eSetBits

接收任务的通知值与xTaskNotify() ulValue参数中传递的值按位或匹配。例如,如果ulValue设置为0x01,则接收任务的通知值将设置0位。另一个例子,如果ulValue是0x06(二进制0110),那么接收任务的通知值将设置第1位和第2位。替代事件组

eIncrement

接收任务的通知值递增。未使用xTaskNotify() ulValue参数。替代计数信号量

eSetValueWithoutOverwrite

如果在调用xTaskNotify()之前接收任务有一个挂起的通知,则不采取任何操作,xTaskNotify()将返回pdFAIL。如果在调用xTaskNotify()之前接收任务没有挂起的通知,则将接收任务的通知值设置为xTaskNotify() ulValue参数中传递的值。

eSetValueWithOverwrite

接收任务的通知值被设置为xTaskNotify() ulValue参数中传递的值,而不管在调用xTaskNotify()之前接收任务是否有挂起的通知。

xTaskNotifyWait()API函数

xTaskNotifyWait()是ulTaskNotifyTake()的一个更强大的版本。它允许任务使用可选的超时等待,以便调用任务的通知状态变为挂起(如果它尚未挂起)。xTaskNotifyWait()提供了在进入函数和退出函数时在调用任务的通知值中清除比特的选项。

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,                          uint32_t ulBitsToClearOnExit,                          uint32_t *pulNotificationValue,                          TickType_t xTicksToWait );
参数作用

ulBitsToClearOnEntry

如果调用任务在调用xTaskNotifyWait()之前没有通知挂起,那么在进入该函数时,在任务的通知值中清除在ulBitsToClearOnEntry中设置的任何位。例如,如果ulBitsToClearOnEntry是0x01,那么任务通知值的第0位将被清除。如果将ulBitsToClearOnEntry设置为0xffff (ULONG_MAX)将清除任务通知值中的所有位。

ulBitsToClearOnExit

如果调用任务因为收到通知而退出xTaskNotifyWait(),或者因为在调用xTaskNotifyWait()时已经有通知挂起,那么在ulBitsToClearOnExit中设置的任何位将在任务退出xTaskNotifyWait()函数之前在任务的通知值中被清除。当任务的通知值保存在*pulNotificationValue(参见下面的pulNotificationValue的描述)中后,这些位将被清除。例如,如果ulBitsToClearOnExit是0x03,那么任务的通知值的第0位和第1位将在此之前被清除将ulBitsToClearOnExit设置为0xfffffff (ULONG_MAX)将清除任务通知值中的所有位。

pulNotificationValue

用于传递出任务的通知值(被清除前的值)。pulNotificationValue是一个可选参数,如果不需要,可以设置为NULL。

xTicksToWait

调用任务保持阻塞态以等待其通知状态变为挂起的最长时间。

返回值

pdTRUE成功接到通知,pdFALSE未接收到通知

例子:ADC

void vADCTask( void *pvParameters ){  uint32_t ulADCValue;  BaseType_t xResult;  const TickType_t xADCConversionFrequency = pdMS_TO_TICKS( 50 );  for( ;; ) {    xResult = xTaskNotifyWait(0,0,&ulADCValue,xADCConversionFrequency * 2 );    if( xResult == pdPASS ) {      ProcessADCResult( ulADCValue );    } else {    }  }}void ADC_ConversionEndISR( xADC *pxADCInstance ){  uint32_t ulConversionResult;  BaseType_t xHigherPriorityTaskWoken = pdFALSE, xResult;  ulConversionResult = ADC_low_level_read( pxADCInstance );  xResult = xTaskNotifyFromISR( xADCTaskToNotify,ulConversionResult, eSetValueWithoutOverwrite,&xHigherPriorityTaskWoken );  configASSERT( xResult == pdPASS );  portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}

ADC_ConversionEndISR函数是ADC转换结束的ISR,vADCTask函数是等待ADC值的任务。

ADC_low_level_read是读取ADC值函数,读取后调用xTaskNotifyFromISR函数发送任务通知,ulValue参数为ulConversionResult,即ADC转换的结果,eAction参数为eSetValueWithoutOverwrite,如果在调用xTaskNotify()之前接收任务有一个挂起的通知,则不采取任何操作,xTaskNotify()将返回pdFAIL。如果在调用xTaskNotify()之前接收任务没有挂起的通知,则将接收任务的通知值设置为xTaskNotify() ulValue参数中传递的值。

可见xTaskNotify()API函数和xTaskNotifyWait()API函数组合实现了传值的功能,这是简易版做不到的,不过大多数情况下,使用简易版就够了

往期精彩:
STM32F4+FreeRTOS+LVGL实现快速开发(缝合怪)

嵌入式C语言几个重点(const、static、voliatile、位运算)

嵌入式Linux驱动学习-5.驱动的分层分离思想

从Linux内核中学习高级C语言宏技巧

嵌入式Linux学习经典书籍-学完你就是大佬

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

彻底掌握FreeRTOS中的务通知(Task Notifications) 的相关文章

  • 如何摆脱CRUD等打杂状态,从事更高价值工作

    每个月都会有十来个来询者向我抱怨工作低端 xff0c 程序员说自己每天CRUD xff0c 重复 枯燥 没技术含量 xff0c 销售助理说自己天天搜集客户信息 打印资料 帮老大带饭 xff0c 繁琐 无聊 不重要 xff0c 他们都说自己整
  • Windows下Qt 5.2 for Android开发入门

    Qt 5 2 发布了 xff0c 支持 Android 平台 xff0c 太好了 之前公司项目 xff0c 为了移植一个依赖 Qt 的程序到安卓平台上 xff0c 我自己交叉编译了 Qt Embedded 4 5 2 xff0c 费了老大劲
  • Qt Quick 之 QML 与 C++ 混合编程详解

    Qt Quick 技术的引入 xff0c 使得你能够快速构建 UI xff0c 具有动画 各种绚丽效果的 UI 都不在话下 但它不是万能的 xff0c 也有很多局限性 xff0c 原来 Qt 的一些技术 xff0c 比如低阶的网络编程如 Q
  • 漫谈程序员系列:一张图道尽程序员的出路

    推背图 相传由唐太宗时期的司天监李淳风和袁天罡合著 xff08 此两人其实是超级武学高手 xff0c 参见小椴的 开唐 xff09 xff0c 推算大唐以后中国两千多年的国运盛衰 xff0c 在中国七大预言书中居首 xff0c 是当之无愧的
  • 漫谈程序员系列:咦,你也在混日子啊

    戳你一下 xff0c 疼吗 xff1f 混日子的定义 来自百度百科的定义 xff1a 生活等方面过得不怎么好 xff0c 无目标 xff0c 混混沌沌 混日子 xff1a 即没有理想 xff0c 没有抱负 xff0c 糊里糊涂地生活 也指工
  • QtAndroid详解(1):QAndroidJniObject

    Qt 5 3之后 xff0c 新增了 QtAndroid 名字空间 xff0c 内有下列四个方法 xff1a QAndroidJniObject AndroidActivity int androidSdkVersion void star
  • freeSWITCH安装、配置与局域网测试

    这次来说说 freeSWITCH 的安装和配置 1 安装 freeSWITCH 下载页面 xff1a https freeswitch org confluence display FREESWITCH Installation 我们 Wi
  • 就 3 点,提升工作效率

    要想提高工作效率 xff0c 不论你看什么书 xff0c 看什么文章 xff0c 用什么工具 xff0c 只有下面这三点最重要 xff1a 动力剖析自己 xff0c 找到改善的切入点付诸行动并且坚持 目标驱动 有目标才能高效 我们爬山 xf
  • Python3 下 ROS 的使用 cv_bridge

    Python 3 下 ROSmsg 转 cv2 项目中用到的 Tensorflow2 4 的环境 xff0c 该环境只支持python3 版本 xff0c 项目中遇到不少需要和 ROS 交互的地方 xff0c 所以不断探索 python3
  • 深度图和RGB图对齐

    深度图 canny RGB canny Alignment xff1a code span class token function import span cv2 span class token function import span
  • 认识romfs文件系统

    1 1 什么是romfs romfs 是一个只读文件系统 xff0c 主要用在 mainly for initial RAM disks of installation disks 使用romfs 文件系统可以构造出一个最小的内核 xff0
  • Livox Lidar 特征提取方式总结

    传统的 旋转式雷达 xff0c 激光固定在雷达的旋转部件上 xff0c 依靠转子的转动而获得360的旋转视野 xff0c 由于旋转部件的存在 xff0c 为了获得更加精准的数据 xff0c 需要跟多的人工校准和更复杂的设计 xff0c 也因
  • C++ 菜鸟之路 (四) boost::thread 多线程全解析

    boost thread 的一般用法 boost thread的几个函数 锁 lock 函数多线程函数的限制 官方解释 xff1a http www cplusplus com reference thread thread joinabl
  • ROS 之 advertise 详解

    在学习过程中接触到如下的一段话 span class hljs comment ROS handles span ros span class hljs tag NodeHandle span node tf span class hljs
  • Linux 下 openMP 效率并未提升的解决方案

    OpenMP 正确观察计算时间OpenMP 经验总结 xff08 1 xff09 openmp 线程使用范围 xff08 2 xff09 openmp 多层嵌套的问题 OpenMP 正确观察计算时间 在使用 openmp的过程中 xff0c
  • C++ Yaml文件解析安装及使用 yaml-cpp

    C 43 43 Yaml文件解析安装及使用 安装 yaml cpp克隆官方库编译 yaml cpp 示例代码robot cpprobot yaml编译 robot cpp运行结果 难点分析与总结什么是 a 与 so 文件静态链接库 a 与动
  • 点云数据格式解析 sensor_msgs::PointCloud2

    在使用多线激光的时候需要总是会碰到点云数据 xff0c 这里简单的接受一下点云数据 xff0c 并堆数据结构进行分析 xff0c 方便自己后期对点云特征数据进行处理 文章目录 Rviz中的点云数据点云数据结构分析点云数据 python 解析
  • Arduino 读取GPS 数据发送解析并发布ROS topic(二)

    Arduino 读取GPS 数据发送解析并发布ROS topic 一 https blog csdn net Fourier Legend article details 84107494 概述 本部分将主要讲将串口接受到的数据 xff0c
  • LOAM进行点云地图创建

    3D激光点云数据处理入门 xff08 一 xff09 使用LOAM进行点云地图创建 LOAM 原理简述topic关系算法分析算法伪代码 LOAM 建图实践创建你的 ROS Workspace下载LOAM Package下载数据包运行 LOA
  • ROS - teb_local_planner 参数总结

    参考官方教程 http wiki ros org teb local planner Tutorials 全英文看着有点累 在此总结一下调试的过程和小小的经验 安装 teb local planner sudo apt get instal

随机推荐

  • 路径规划算法(2) - A*寻路算法 python实现及解析

    代码 span class token comment coding 61 utf 8 span span class token keyword import span math span class token comment 启发距离
  • 使用FSMC驱动LCD以及数据线偏移的问题

    FSMC的理解 使用FSMC功能将8080接口的LCD当外部RAM来使用 xff08 数据传给LCD时没经过内部SRAM xff0c 所以一帧图片很大也可以直接传 xff09 xff0c 根据STM的地址分配图可以看出外部RAM的地址由0x
  • C++调用HTTP实现方式

    转自 xff1a http blog 163 com lyz sea blog static 11558670720118245052189 Http访问有两种方式 xff0c GET和POST xff0c 就编程来说GET方式相对简单点
  • 跟我学c++中级篇——STL智能指针再述

    一 智能指针 xff08 smart pointer xff09 在前面的文章分析中对智能指针分析的还是比较多的 xff0c 这里把一具体的遗漏以及一些新的感悟再总结一下 xff0c 以之为鉴 什么是智能指针 xff1f 在C C 43 4
  • 从CAN到CANOpen——准入门大全(二)

    第二节 关于CAN ID xff1a 一个标准帧的ID共11位 xff0c 一个扩展帧的ID共29位 扩展帧的ID分11位和18位的两段 xff0c 如下图所示 RTR显性 xff1a 数据帧 xff1b 隐性 xff1a 远程帧 SRR隐
  • vscode使用clang-format格式化C++代码

    1 安装c c 43 43 插件 2 在首选项 设置中搜索format xff0c 设置Editor Default Formatter为ms vscode cpptools 3 在扩展C C 43 43 中设置 Clang format
  • EC20 GPS RMC格式数据转化

    文章目录 目录 前言 一 RMC是什么 xff1f 二 EC20 输出的RMC解析 1 EC20返回的RMC报文 2 RMC报文解析 3 NMEA数据ddmm mmmm转换成dd ddddd 4 RMC UTC时间转化成北京时间 总结 前言
  • C++ 第三方常用网络库

    From xff1a https www cnblogs com aitantianderuangutou p 11416902 html 1 ACE 庞大 复杂 xff0c 适合大型项目 开源 免费 xff0c 不依赖第三方库 xff0c
  • Postman 使用方法详解

    From xff1a https zhuanlan zhihu com p 534078123 Postman V9 16 绿色版汉化 xff1a https www cr173 com soft 1497202 html Postman是
  • 串口波形分析

    本文使用逻辑分析仪 xff0c 抓取串口波形 xff0c 进而分析串口数据 串口配置为115200波特率 xff0c 8个数据位 xff0c 1个停止位 xff0c 无校验方式 字符1的波形如下图 xff1a 从图中可以看到8个数据位 xf
  • 电影资源 BT PT下载的电影命名 规则 资源 详解

    初识 一般来说 xff0c 正规压制组压制的电影 xff0c 都采用 0day 命名方式 xff0c 即 xff1a 英文名称 版本说明 年份 片源 分辨率 视频编码 音频格式 压制小组 例如文件名 xff1a Jumanji The Ne
  • 对于51单片机的RAM内存分配(包含栈的分配)

    对于51单片机的RAM内存分配 xff08 包含栈的分配 xff09 我使用的是SH79F3283 xff0c 内部RAM有256字节 xff0c 由常规寄存器 静态存储区和堆栈组成的 xff0c 创建一个新的程序默认占用9个字节RAM x
  • 忘记windows密码解决办法(用户密码或SYSKEY)

    64 TOC 还有朋友问第一层的BIOS密码怎么解 xff1a 拔电池就能解 xff0c 断电 xff0c 打开电脑主板 xff0c 找到一个纽扣电池 xff0c 拔掉 xff0c 长按电源键 xff0c 再插电 xff0c 第一层就没了
  • 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

    超详细讲解哈夫曼树 Huffman Tree 以及哈夫曼编码的构造原理 方法 xff0c 并用代码实现 1哈夫曼树基本概念 路径 从树中一个结点到另一个结点之间的分支构成这两个结点间的路径 结点的路径长度 两结点间路径上的分支数 树的路径长
  • Makefile命令参数、调用其他Makefile、嵌套

    更多单片机 嵌入式内容及参考资料 xff1a 大叔的嵌入式小站 xff1a Makefile学习 3 make命令参数 调用其他makefile 嵌套 一 Make命令运行参数 参数 参数的作用 C dir读入指定目录下的makefile
  • ARM学习-ARM指令集详解

    目录 1 ARM 存储器访问指令 1 1 LDR 和STR 加载 存储字和无符号字节指令 1 2 LDM和STM 批量加载 存储指令 1 3 SWP 寄存器和存储器交换指令 2 ARM 数据处理指令 2 1数据传送指令 2 1 1 MOV
  • IIC(I2C)协议详解

    1 简介 IIC 即I C xff0c 全称 Inter Integrated Circuit xff0c 字面上的意思是集成电路之间 xff0c 它其实是I C Bus简称 xff0c 所以中文应该叫 集成电路总线 xff0c 它是一种串
  • STM32F4+FreeRTOS+LVGL实现嵌入式快速开发(缝合怪)

    极速进行项目开发 xff0c 只需要懂一款芯片架构 43 一个操作系统 43 一个GUI 各种部件程序全靠抄 xff0c 成为究极缝合怪 本文用stm32f407 43 FreeRTOS 43 lvgl演示一些demo 原文链接 xff1a
  • 彻底弄清FreeRTOS中的事件组(Event Groups)

    之前已经学过两个任务之间可以利用信号量 队列来通信 xff0c 任务可以利用这两个机制等待某一个事件发生 xff0c 但是假如需要等待多个事件发生呢 xff1f 这就需要用到事件组了 事件组可以让任务进入阻塞态 xff0c 等待一个或多个事
  • 彻底掌握FreeRTOS中的务通知(Task Notifications)

    在之前的文章中已经讲解了很多种用于任务件通信的机制 xff0c 包括队列 事件组和各种不同类型的信号量 使用这些机制都需要创建一个通信对象 事件和数据不会直接发送到接收任务或接收ISR xff0c 而是发送到通信对象 xff08 也就是发送