STM32标准库、HAL库特点与应用

2023-05-16

新手在入门STM32的时候,一般大多数都会选用标准库和HAL库,而极少部分人会通过直接配置寄存器进行开发。
对于刚入门的朋友可能没法直观了解这些不同开发发方式彼此之间的区别,本文试图以一种非常直白的方式,用自己的理解去将这些东西表述出来。

配置寄存器
不少先学了51的朋友可能会知道,会有一小部分人或是教程是通过汇编语言直接操作寄存器实现功能的,这种方法到了STM32就变得不太容易行得通了。

因为STM32的寄存器数量是51单片机的十数倍,如此多的寄存器根本无法全部记忆,开发时需要经常的翻查芯片的数据手册,此时直接操作寄存器就变得非常的费力了。也有人喜欢去直接操作寄存器,因为这样更接近原理,代码更少,知其然也知其所以然。

标准库
上面也提到了,STM32有非常多的寄存器,而导致了开发困难,所以为此ST公司就为每款芯片都编写了一份库文件,也就是工程文件里stm32F1xx…之类的。在这些.c与.h文件中,包括一些常用量的宏定义,把一些外设也通过结构体变量封装起来,如GPIO、时钟等。

所以我们只需要配置结构体变量成员就可以修改外设的配置寄存器,从而选择不同的功能。也是目前最多人使用的方式,也是学习STM32接触最多的一种开发方式,我也就不多阐述了。

HAL库
HAL库是ST公司目前主推的开发方式,全称就是Hardware Abstraction Layer(抽象印象层),简单来说就是弱化了开发者对硬件底层知识的依赖。

同样的功能,标准库可能要用几句话,HAL库只需用一句话就够了。并且HAL库也很好的解决了程序移植的问题。不同型号的STM32芯片它的标准库是不一样的,例如在F4上开发的程序移植到F3上是不能通用的,而使用HAL库,只要使用的是相同的外设,程序基本可以完全复制粘贴,注意是相同外设,意思也就是不能无中生有。例如F7比F3要多几个定时器,不能明明没有这个定时器却非要配置,但其实这种情况不多,绝大多数都可以直接复制粘贴。

而且使用ST公司研发的STMcube软件,可以通过图形化的配置功能,直接生成整个适用于HAL库的工程文件,可以说是方便至极。相关推荐:STM32CubeMX安装教程。但是方便的同时也造成了它执行效率偏低。

综合上面说的,其实笔者还是强烈推荐HAL库的,理由:

ST公司已经停止更新标准库,公司主打HAL库的目的已经非常明显了

模块化的HAL库是趋势,低效的短板会被硬件的增强所弥补

当然底层的基本原理必需是要懂的,HAL库也不是万能的,结合对底层的理解相信一定会让你的开发水准大大提高。

STM32的HAL库、标准库区别
1 句柄

在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例) 我们首先要初始化他们的各个寄存器。

在标准库中,这些操作都是利用固件库结构体变量+固件库Init函数实现的:

 USART_InitTypeDef USART_InitStructure;

 USART_InitStructure.USART_BaudRate = bound;//串口波特率
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
 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_Init(USART3, &USART_InitStructure); //初始化串口1

可以看到,要初始化一个串口,需要对六个位置进行赋值,然后引用Init函数,并且USART_InitStructure并不是一个全局结构体变量,而是只在函数内部的局部变量,初始化完成之后,USART_InitStructure就失去了作用。

而在HAL库中,同样是USART初始化结构体变量,我们要定义为全局变量。

UART_HandleTypeDef UART1_Handler;

结构体成员:

typedef struct
{
   USART_TypeDef                 *Instance;        /*!< UART registers base address        */
   UART_InitTypeDef              Init;             /*!< UART communication parameters      */
uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
uint16_t                      TxXferCount;      /*!< UART Tx Transfer Counter           */
uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
uint16_t                      RxXferCount;      /*!< UART Rx Transfer Counter           */
   DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */
   DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
   HAL_LockTypeDef               Lock;             /*!< Locking object                     */
   __IO HAL_UART_StateTypeDef    State;            /*!< UART communication state           */
   __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
}UART_HandleTypeDef;

我们发现,与标准库不同的是,该成员不仅包含了之前标准库就有的六个成员(波特率,数据格式等),还包含过采样、(发送或接收的)数据缓存、数据指针、串口 DMA 相关的变量、各种标志位等等要在整个项目流程中都要设置的各个成员。

该UART1_Handler就被称为串口的句柄 它被贯穿整个USART收发的流程,比如开启中断:

HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);

比如后面要讲到的MSP与Callback回调函数:

void HAL_UART_MspInit(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

在这些函数中,只需要调用初始化时定义的句柄UART1_Handler就好。

2 MSP函数
MCU Specific Package单片机的具体方案

MSP是指和MCU相关的初始化,引用一下正点原子的解释,个人觉得说的很明白:


我们要初始化一个串口,首先要设置和 MCU 无关的东西,例如波特率,奇偶校验,停止位等,这些参数设置和 MCU 没有任何关系,可以使用 STM32F1,也可以是STM32F2/F3/F4/F7上的串口。而一个串口设备它需要一个 MCU 来承载,例如用 STM32F4 来做承载,PA9 做为发送,PA10 做为接收,MSP 就是要初始化 STM32F4 的 PA9,PA10,配置这两个引脚。所以 HAL驱动方式的初始化流程就是:HAL_USART_Init()—>HAL_USART_MspInit(),先初始化与 MCU无关的串口协议,再初始化与 MCU 相关的串口引脚。在 STM32 的 HAL 驱动中HAL_PPP_MspInit()作为回调,被HAL_PPP_Init()函数所调用。当我们需要移植程序到 STM32F1平台的时候,我们只需要修改 HAL_PPP_MspInit 函数内容而不需要修改 HAL_PPP_Init 入口参数内容。


在HAL库中,几乎每初始化一个外设就需要设置该外设与单片机之间的联系,比如IO口,是否复用等等,可见,HAL库相对于标准库多了MSP函数之后,移植性非常强,但与此同时却增加了代码量和代码的嵌套层级。可以说各有利弊。

同样,MSP函数又可以配合句柄,达到非常强的移植性:

void HAL_UART_MspInit(UART_HandleTypeDef *huart);

3 Callback函数
类似于MSP函数,个人认为Callback函数主要帮助用户应用层的代码编写。还是以USART为例,在标准库中,串口中断了以后,我们要先在中断中判断是否是接收中断,然后读出数据,顺便清除中断标志位,然后再是对数据的处理,这样如果我们在一个中断函数中写这么多代码,就会显得很混乱:

void USART3_IRQHandler(void) //串口1中断服务程序
{
 u8 Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
 {
  Res =USART_ReceiveData(USART3); //读取接收到的数据
/*数据处理区*/
 } 
}

而在HAL库中,进入串口中断后,直接由HAL库中断函数进行托管:

void USART1_IRQHandler(void)                 
{ 
 HAL_UART_IRQHandler(&UART1_Handler); //调用HAL库中断处理公用函数
 /*****************省略无关代码******************/ 
}

HAL_UART_IRQHandler这个函数完成了判断是哪个中断(接收?发送?或者其他?),然后读出数据,保存至缓存区,顺便清除中断标志位等等操作。比如我提前设置了,串口每接收五个字节,我就要对这五个字节进行处理。在一开始我定义了一个串口接收缓存区:

/*HAL库使用的串口接收缓冲,处理逻辑由HAL库控制,接收完这个数组就会调用HAL_UART_RxCpltCallback进行处理这个数组*/
/*RXBUFFERSIZE=5*/
u8 aRxBuffer[RXBUFFERSIZE];

在初始化中,我在句柄里设置好了缓存区的地址,缓存大小(五个字节)

/*该代码在HAL_UART_Receive_IT函数中,初始化时会引用*/
huart->pRxBuffPtr = pData;//aRxBuffer
huart->RxXferSize = Size;//RXBUFFERSIZE
huart->RxXferCount = Size;//RXBUFFERSIZE

则在接收数据中,每接收完五个字节,HAL_UART_IRQHandler才会执行一次Callback函数:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

在这个Callback回调函数中,我们只需要对这接收到的五个字节(保存在aRxBuffer[]中)进行处理就好了,完全不用再去手动清除标志位等操作。

所以说Callback函数是一个应用层代码的函数,我们在一开始只设置句柄里面的各个参数,然后就等着HAL库把自己安排好的代码送到手中就可以了~

综上,就是HAL库的三个与标准库不同的地方之个人见解。

个人觉得从这三个小点就可以看出HAL库的可移植性之强大,并且用户可以完全不去理会底层各个寄存器的操作,代码也更有逻辑性。但与此带来的是复杂的代码量,极慢的编译速度,略微低下的效率。看怎么取舍了。

HAL库结构
说到STM32的HAL库,就不得不提STM32CubeMX,其作为一个可视化的配置工具,对于开发者来说,确实大大节省了开发时间。另外STM32CubeIDE集成了STM32CubeMX的功能,是一个集配置与编译与一体的软件,可以尝试一下。软件更新频率很高,持续优化某些bug及性能问题。

在这里插入图片描述

上面两个开发软件是以HAL库为基础的,且目前仅支持HAL库及LL库!

首先看一下,官方给出的HAL库的文件结构:

在这里插入图片描述

下图是STM32库文件结构。

在这里插入图片描述

stm32f2xx.h 主要包含STM32同系列芯片的不同具体型号的定义,是否使用HAL库等的定义,接着,其会根据定义的芯片信号包含具体的芯片型号的头文件:

#if defined(STM32F205xx)
#include "stm32f205xx.h"
#elif defined(STM32F215xx)
#include "stm32f215xx.h"
#elif defined(STM32F207xx)
#include "stm32f207xx.h"
#elif defined(STM32F217xx)
#include "stm32f217xx.h"
#else
#error "Please select first the target STM32F2xx device used in your application (in stm32f2xx.h file)"
#endif

紧接着,其会包含 stm32f2xx_hal.h。

stm32f2xx_hal.h:stm32f2xx_hal.c/h 主要实现HAL库的初始化、系统滴答相关函数、及CPU的调试模式配置

stm32f2xx_hal_conf.h :该文件是一个用户级别的配置文件,用来实现对HAL库的裁剪,其位于用户文件目录,不要放在库目录中。

接下来对于HAL库的源码文件进行一下说明,HAL库文件名均以stm32f2xx_hal开头,后面加上_外设或者模块名(如:stm32f2xx_hal_adc.c):

库文件:
 stm32f2xx_hal_ppp.c/.h   // 主要的外设或者模块的驱动源文件,包含了该外设的通用API
 stm32f2xx_hal_ppp_ex.c/.h  // 外围设备或模块驱动程序的扩展文件。这组文件中包含特定型号或者系列的芯片的特殊API。以及如果该特定的芯片内部有不同的实现方式,则该文件中的特殊API将覆盖_ppp中的通用API。
 stm32f2xx_hal.c/.h    // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的时间延迟等相关的API
 其他库文件
用户级别文件:
 stm32f2xx_hal_msp_template.c // 只有.c没有.h。它包含用户应用程序中使用的外设的MSP初始化和反初始化(主程序和回调函数)。使用者复制到自己目录下使用模板。
 stm32f2xx_hal_conf_template.h // 用户级别的库配置文件模板。使用者复制到自己目录下使用
 system_stm32f2xx.c    // 此文件主要包含SystemInit()函数,该函数在刚复位及跳到main之前的启动过程中被调用。**它不在启动时配置系统时钟(与标准库相反)**。时钟的配置在用户文件中使用HAL API来完成。
 startup_stm32f2xx.s    // 芯片启动文件,主要包含堆栈定义,终端向量表等
 stm32f2xx_it.c/.h    // 中断处理函数的相关实现
 main.c/.h

根据HAL库的命名规则,其API可以分为以下三大类:

初始化/反初始化函数:HAL_PPP_Init(), HAL_PPP_DeInit()
IO 操作函数:HAL_PPP_Read(), HAL_PPP_Write(),HAL_PPP_Transmit(), HAL_PPP_Receive()
控制函数:HAL_PPP_Set (), HAL_PPP_Get ().
状态和错误:HAL_PPP_GetState (), HAL_PPP_GetError ().

注意:目前 LL 库是和 HAL 库捆绑发布的,所以在 HAL 库源码中,还有一些名为 stm32f2xx_ll_ppp 的源码文件,这些文件就是新增的LL库文件。使用 CubeMX 生产项目时,可以选择LL库。


HAL 库最大的特点就是对底层进行了抽象。在此结构下,用户代码的处理主要分为三部分:

处理外设句柄,实现用户功能

处理MSP

处理各种回调函数,外设句柄定义

HAL库在结构上,对每个外设抽象成了一个称为ppp_HandleTypeDef的结构体,其中ppp就是每个外设的名字。*所有的函数都是工作在ppp_HandleTypeDef指针之下。

每个外设/模块实例都有自己的句柄。因此,实例资源是独立的。

外围进程相互通信:该句柄用于管理进程例程之间的共享数据资源。

下面,以ADC为例,

/** 
 * @brief  ADC handle Structure definition
 */
typedef struct
{
 ADC_TypeDef                   *Instance;                   /*!< Register base address */
 ADC_InitTypeDef               Init;                        /*!< ADC required parameters */
  __IO uint32_t                 NbrOfCurrentConversionRank;  /*!< ADC number of current conversion rank */
 DMA_HandleTypeDef             *DMA_Handle;                 /*!< Pointer DMA Handler */
 HAL_LockTypeDef               Lock;                        /*!< ADC locking object */
 __IO uint32_t                 State;                       /*!< ADC communication state */
 __IO uint32_t                 ErrorCode;                   /*!< ADC Error code */
}ADC_HandleTypeDef;

从上面的定义可以看出,ADC_HandleTypeDef中包含了ADC可能出现的所有定义,对于用户想要使用ADC只要定义一个ADC_HandleTypeDef的变量,给每个变量赋好值,对应的外设就抽象完了。接下来就是具体使用了。

当然,对于那些共享型外设或者说系统外设来说,他们不需要进行以上这样的抽象,这些部分与原来的标准外设库函数基本一样。例如以下外设:

GPIO
SYSTICK
NVIC
RCC
FLASH
以GPIO 为例,对于HAL_GPIO_Init()函数,其只需要GPIO地址以及其初始化参数即可。

1 三种编程方式
HAL库对所有的函数模型也进行了统一。在HAL库中,支持三种编程模式:轮询模式、中断模式、DMA模式(如果外设支持)。其分别对应如下三种类型的函数(以ADC为例):

HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc);

HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);

HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc);

其中,带_IT的表示工作在中断模式下;带_DMA的工作在DMA模式下(注意:DMA模式下也是开中断的);什么都没带的就是轮询模式(没有开启中断的)。至于使用者使用何种方式,就看自己的选择了。

此外,新的HAL库架构下统一采用宏的形式对各种中断等进行配置(原来标准外设库一般都是各种函数)。针对每种外设主要由以下宏:

__HAL_PPP_ENABLE_IT(HANDLE, INTERRUPT):使能一个指定的外设中断
__HAL_PPP_DISABLE_IT(HANDLE, INTERRUPT):失能一个指定的外设中断
__HAL_PPP_GET_IT (HANDLE, __ INTERRUPT __):获得一个指定的外设中断状态
__HAL_PPP_CLEAR_IT (HANDLE, __ INTERRUPT __):清除一个指定的外设的中断状态
__HAL_PPP_GET_FLAG (HANDLE, FLAG):获取一个指定的外设的标志状态
__HAL_PPP_CLEAR_FLAG (HANDLE, FLAG):清除一个指定的外设的标志状态
__HAL_PPP_ENABLE(HANDLE) :使能外设
__HAL_PPP_DISABLE(HANDLE) :失能外设
__HAL_PPP_XXXX (HANDLE, PARAM) :指定外设的宏定义
_HAL_PPP_GET IT_SOURCE (HANDLE, __ INTERRUPT __)检查中断源

2 三大回调函数
在 HAL 库的源码中,到处可见一些以__weak开头的函数,而且这些函数,有些已经被实现了,比如:

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/*Configure the SysTick to have interrupt in 1ms time basis*/
 HAL_SYSTICK_Config(SystemCoreClock/1000U);
/*Configure the SysTick IRQ priority */
 HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0U);
/* Return function status */
return HAL_OK;
}

有些则没有被实现,例如:

__weak void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
/* Prevent unused argument(s) compilation warning */
  UNUSED(hspi);
/* NOTE : This function should not be modified, when the callback is needed,the HAL_SPI_TxCpltCallback should be implemented in the user file
  */
}

所有带有__weak关键字的函数表示,就可以由用户自己来实现。如果出现了同名函数,且不带__weak关键字,那么连接器就会采用外部实现的同名函数。通常来说,HAL库负责整个处理和MCU外设的处理逻辑,并将必要部分以回调函数的形式给出到用户,用户只需要在对应的回调函数中做修改即可。

HAL 库包含如下三种用户级别回调函数(PPP为外设名):

外设系统级初始化/解除初始化回调函数(用户代码的第二大部分:对于MSP的处理):HAL_PPP_MspInit()和HAL_PPP_MspDeInit 例如:__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)。在HAL_PPP_Init() 函数中被调用,用来初始化底层相关的设备(GPIOs, clock, DMA, interrupt)

处理完成回调函数:HAL_PPP_ProcessCpltCallback(Process指具体某种处理,如UART的Tx),例如:__weak void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)。当外设或者DMA工作完成后时,触发中断,该回调函数会在外设中断处理函数或者DMA的中断处理函数中被调用

错误处理回调函数:HAL_PPP_ErrorCallback例如:__weak void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)。当外设或者DMA出现错误时,触发终端,该回调函数会在外设中断处理函数或者DMA的中断处理函数中被调用。

参考文档:

ST-Description of STM32F4 HAL and LL drivers.pdf
ST-en.stm32_embedded_software_offering.pdf

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

STM32标准库、HAL库特点与应用 的相关文章

  • 程序员每天工作多少个小时_程序员每天实际工作几个小时?

    程序员每天工作多少个小时 您如何看待 xff0c 程序员每天实际工作多长时间 xff1f 大多数人会说答案是8到9个小时 有人说他们每天工作12个小时或更长时间 尽管这是正确的 xff0c 但它并不是大多数程序员实际工作的数量 xff0c
  • 九轴姿态传感器的介绍和应用

    总体设计 姿态传感器是基于MEMS技术的高性能三维运动姿态测量系统 它包含三轴陀螺仪 三轴加速度计 xff0c 三轴电子罗盘等运动传感器 xff0c 通过内嵌的低功耗ARM处理器得到经过温度补偿的三维姿态与方位等数据 利用基于四元数的三维算
  • CAN总线简单介绍

    什么是CAN总线 xff1f Controller Area Network xff0c 简称CAN或者CAN bus 是一种功能丰富的串行总线标准 xff0c 最早的CAN控制芯片在奔驰车上应用并量产 xff0c 因为支持多主机 xff0
  • Ubuntu18.04 下realsense编译与安装

    相机型号 xff1a realsense SR300 系统环境 xff1a Ubuntu18 04 我这里是下载并编译源码的方式进行编译安装 具体编译安装可以参照https github com IntelRealSense libreal
  • Linux gvim 编辑器修改配色方案、字体、字号

    1 gvim相比于vim xff0c 目前知道gvim是可以单独窗口运行的 xff0c 像gedit一样 vim打开的文件貌似只能显示在终端内 但是二者安装的位置以及配置文件是很有联系的 xff0c 暂时的感觉是gvim是对vim的封装 x
  • 【路径规划】(3) RRT 算法求解最短路,附python完整代码

    大家好 xff0c 今天和各位分享一下机器人路径规划中的 RRT 算法 xff0c 感兴趣的点个关注 xff0c 文末有 python 代码 xff0c 那我们开始吧 1 算法介绍 RRT 算法是由学者 S M LaValle 提出来的路径
  • 【自动化测试】【安卓android】python 发送adb命令方法

    command 命令列表 xff0c 可以传入任意命令 xff0c 类型为list cmdMode可以选择发送命令方式为直接发送adb 命令还是先进入shell def sendAdbcmd command deviceID 61 34 3
  • 选择恐惧症的福音!教你认清MVC,MVP和MVVM

    相信大家对MVC xff0c MVP和MVVM都不陌生 xff0c 作为三个最耳熟能详的Android框架 xff0c 它们的应用可以是非常广泛的 xff0c 但是对于一些新手来说 xff0c 可能对于区分它们三个都有困难 xff0c 更别
  • FreeRtos嵌入式操作系统学习1--操作系统原理初探

    这里由于是第一篇文章 xff0c 不讲复杂的数据机构 xff0c 也不进行代码分析 xff0c 只讲嵌入式操作系统原理 先看下面一个简单的程序 xff1a void task1 while 1 Led1 1 xff08 1 xff09 de
  • 初学四旋翼之定高

    本项目使用US 100超声波模块测高 xff0c 与飞控的通讯方式为UART 硬件连接应注意 xff1a 通常飞控的发送管脚连超声波的接收管脚 xff0c 飞控的接收管脚连超声波的发送管脚 xff08 即tx rx xff1b rx tx
  • 初学四旋翼之光流定点

    本项目使用px4flow模块测速 xff0c 与飞控的通讯方式为I2C 安装时因注意光流模块与飞控的方向 xff08 一 xff09 为什么使用光流模块 xff1f 在悬停时 xff0c 若采用开环控制 xff0c 由于一些不可控的外界因素
  • 初学JetsonTX2之部署YOLO

    本人准备使用 YOLO进行人脸检测 xff0c 硬件设备为 Jetson TX2 查阅 YOLO 官网 xff0c 要部署 YOLO xff0c 首先要安装 CUDA CUDNN OPENCV xff0c 然后部署 Darknet xff0
  • C语言,超过10位数的字符串转整型函数

    include lt stdio h gt static long str2int const char str long temp 61 0 const char p 61 str if str 61 61 NULL return 0 i
  • C语言去掉MAC地址中的冒号

    include lt stdio h gt include lt string h gt void strdel char s char del x char p char q for p 61 s q 61 s p 61 39 0 39
  • Jetson Xavier NX 套件将系统装到SSD

    目录 第一步 xff1a 虚拟机 第二步 xff1a 装SDK Manager 第三步 xff1a 将系统装到eMMC 第四步 xff1a 将系统装到SSD内 xff0c 我以新买的500G硬盘为例 第五步 xff1a 装各种库 解决问题时
  • MySQL使用.ibd文件恢复或者迁移数据库

    使用86的Alice数据库的 ibd文件备份 恢复到76数据库 xff0c 该数据库版本为8 0 17 1 创建一个表确认与原始表结构一致 将86数据库的表结构导出 xff0c 在76上执行 xff08 注 xff1a 在5 5 26版本需
  • 学习ARM反汇编工具objdump和一个简单实例

    学习ARM反汇编工具objdump和一个简单实例 参考朱有鹏ARM裸机编程 1 反汇编的原理 amp 为什么需要反汇编 arm linux objdump D led elf gt led elf dis objdump是gcc工具链中的反
  • 从零开始学习UCOSII操作系统1--UCOSII的基础知识

    从零开始学习UCOSII操作系统1 UCOSII的基础知识 前言 xff1a 首先比较主流的操作系统有UCOSII FREERTOS LINUX等 xff0c UCOSII的资料相对比其余的两个操作系统的资料是多很多的 更重要的原因是自己本
  • 从零开始学习UCOSII操作系统2--UCOSII的内核实现

    从零开始学习UCOSII操作系统2 UCOSII的内核实现 参考书籍 xff1a 嵌入式实时操作系统 COS II原理及应用 嵌入式实时操作系统uCOS II 邵贝贝 第二版 1 任务的结构 任务控制块 首先这个任务控制块是非常的大的 xf
  • 从零开始学习UCOSII操作系统4--任务管理

    从零开始学习UCOSII操作系统4 任务管理 1 重讲任务 1 任务可以是一个无限的循环 xff0c 也可以在一次执行完毕后被删除 这里需要注意的是 xff0c 任务的代码并不是真正的删除了 xff0c 而是UCOSII不再理会该任务代码

随机推荐

  • 从零开始学习UCOSII操作系统7--信号量

    从零开始学习UCOSII操作系统7 信号量 参考博客 xff1a 64 http blog csdn net gatiemehttps blog csdn net gatieme article details 21071379 前言 xf
  • 从零开始学习UCOSII操作系统15--总结篇

    从零开始学习UCOSII操作系统15 总结篇 前言 xff1a 在大学的时候 xff0c 我们班级上面都有很多人觉得学习UCOSII 包括UCOSIII 是没什么厉害的 xff0c 因为很多人都喜欢去学习Linux操作系统 xff0c 但是
  • 手把手教你搭建TFTP服务器

    手把手教你搭建TFTP服务器 前言 xff0c 东西来自于网络 xff0c 但是根据自己的理解写了一下建议 xff0c 记录下来 xff0c 让下次不要在网络上面浪费时间搜索 1 保证自己的虚拟机能够上网 测试方法 xff1a 里面一般都有
  • 从零开始写一个单向不循环链表

    从零开始写一个单向不循环链表 总结 xff1a 郝斌数据结构与算法课程 数据结构概述 xff1a 定义 xff1a 我们如何把现实中大量的而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器 xff08 内存 xff09 中 xff0
  • STM32-CAN通信协议

    STM32 CAN通讯协议 CAN协议简述 CAN Controller Area Network xff08 控制器局域网 xff09 xff0c 由Bosch开发的一种面向汽车的通信协议 这是目前应用最广泛的通信协议 xff0c 更是尤
  • FreeRTOS-任务运行时间统计

    FreeRTOS 任务运行时间统计 引入 上一章节中我们讲述了任务信息获取 xff0c 我们已经能够获取绝大部分任务信息了 xff0c 但是任务还有一个很重要的信息 xff0c 那就是运行时间 如果我们知道了每个任务的运行时间和占比我们就可
  • 【Linux】解决Nvidia Jetson Xavier NX开发套件开机启动时间过长问题

    环境 硬件 xff1a Jetson Xavier NX 套件 系统 xff1a Ubuntu 20 04 解决 0 现象 在使用Nvidia 的Jetson Xavier NX套件 xff0c 开发产品 xff0c 准备发布时 xff0c
  • FreeRTOS-信号量

    FreeRTOS 信号量 信号量其实就是队列的一种应用 xff0c 信号量的各种操作都是在队列的基础上建立起来的 那么既然是在队列的基础上建立的 xff0c 信号量一定具有和队列相同的属性 因此信号量也是为任务和任务 任务和中断之间通信做准
  • FreeRTOS-空闲任务及钩子函数

    FreeRTOS 空闲任务及钩子函数 FreeRTOS中空闲任务是开启任务调度器自动创建的一个任务 xff0c 这样可以保证系统中有任务可以运行 xff0c 这个任务优先级是最低的 xff0c 如果有其他任务处于就绪态 xff0c 那么空闲
  • FreeRTOS-内存管理-完结篇

    FreeRTOS 内存管理 无论是创建任务 队列 信号量还是其他的东西 xff0c 都需要为其分配一定空间 xff0c 前面我们都是运用动态内存申请的方法来申请空间 xff0c 并且我们所使用的的动态内存申请函数都是FreeRTOS自己提供
  • OpenCV环境搭建

    OpenCV环境搭建 VS2017安装 具体安装过程参考下面链接 xff1a https mp weixin qq com s NrrHFAXm57QblOf5CPUVmw 组件可以参考以下选项 xff1a OpenCV安装 如果还没有安装
  • W2-图像增强

    线性变换 imag span class token operator 61 span span class token function imread span span class token punctuation span span
  • 半天光速入门Python(上)

    文章目录 写在前面一 Python环境Python解释器与编辑器WinDows用户Linux用户 二 基础概念 运算符与表达式常量数类型字符串变量与标识符对象逻辑行与物理行缩进运算符注释方法与C语言区别 三 三种程序结构ifforwhile
  • 路径规划算法综述

    路径规划算法综述 路径规划算法综述 文章目录 路径规划算法综述路径规划算法主要问题一 主要问题及现有解决方案1 环境建模问题2 收敛速度和局部最优解 二 路径规划算法分类及简介2 1传统算法2 1 1全局路径规划算法2 1 1 1 A 算法
  • 图论基础介绍

    路径规划系列文章目录 路径规划算法综述 文章目录 路径规划系列文章目录图论基础介绍一 图的基本概念1 1 图的定义1 2 图的分类1 2 1 无向图1 2 2 有向图1 2 3 带权图 二 图的相关术语2 1 邻接 adjacent 2 2
  • 图论之邻接矩阵

    路径规划系列文章目录 路径规划算法综述图论基础介绍 目录 路径规划系列文章目录 一 图的存储方式介绍 二 邻接矩阵介绍 三 邻接矩阵实现 四 总结 一 图的存储方式介绍 图的结构比较复杂 xff0c 是非线性结构 xff0c 任意两点都可能
  • 图论之邻接表

    路径规划系列文章目录 路径规划算法综述图论基础介绍图论之邻接矩阵 目录 路径规划系列文章目录 一 邻接表 二 邻接表实现 2 1 链式前向星实现 2 2 链表实现 三 总结 一 邻接表 由于对于稀疏图来说 xff0c 使用邻接矩阵进行存储显
  • flashcache的实现与分析

    最近 xff0c 由于项目需要 xff0c 在做关于flashcache的一些工作 xff0c 主要涉及模块组织 元数据管理及数据分布 读写流程分析 数据在磁盘和 cache SSD 之间的调度 缺点及可优化方向等一些方面的分析研究 也想
  • 蛋花花分享人工智能概念的诞生与发展

    蛋花花分享人工智能概念的诞生与发展 xff01 如今人工智能非常的火 xff0c 在各行各业都有突出的变现 xff0c 让人期待它未来的发展 蛋花花认为了解人工智能向何处去 xff0c 首先要知道人工智能从何处来 1956年夏 xff0c
  • STM32标准库、HAL库特点与应用

    新手在入门STM32的时候 xff0c 一般大多数都会选用标准库和HAL库 xff0c 而极少部分人会通过直接配置寄存器进行开发 对于刚入门的朋友可能没法直观了解这些不同开发发方式彼此之间的区别 xff0c 本文试图以一种非常直白的方式 x