细说HAL

您所在的位置:网站首页 hal啥意思 细说HAL

细说HAL

2024-07-15 04:51| 来源: 网络整理| 查看: 265

目录

1.HAL_GPIO_WritePin()函数

(1) 细说HAL_GPIO_WritePin()函数

(2)HAL_GPIO_WritePin()和HAl_GPIO_TogglePin()的异同

2.assert_param语句的功能

(1)首先,HAL_GPIO_TogglePin()中的assert_param

(2)再看,assert_param()定义

3.ifdef条件编译

1.HAL_GPIO_WritePin()函数

        HAL_GPIO_WritePin()函数也是很常用的实现GPIO引脚输出状态变化的库函数。

        该函数HAL_GPIO_WritePin()的定义:

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,GPIO_PinState PinState) { /*Check the parameter*/ assert_param(IS_GPIO_PIN(GPIO_Pin)); assert_param(IS_GPIO_PIN_ACTION(PinState)); if (PinState != GPIO_PIN_RESET) { GPIOx ->BSRR = (uint32_t)GPIO_Pin; //BSRR寄存器的低16位置位 } else { GPIOx ->BRR = (uint32_t)GPIO_Pin; //BRR寄存器的低16位复位等效于BSRR寄存器的高16位复位 } }

        HAL_GPIO_WritePin()函数有3个参数,前面两个与GPIO_TogglePin()相同;多出的参数为PinState,顾名思义,是引脚状态。PinState的类型是GPIO_PinState,可以在固件库中查看对GPIO_PinState的声明:

typedef enum { GPIO_PIN_RESET = 0U, GPIO_PIN_SET } GPIO_PinState;

        这是一个枚举类型,用typedef关键词将枚举类型定义成GPIO_PinState,其有两个成员:GPIO_PIN_RESET,被赋值为0;另一个是GPIO_PIN_SET,被赋值为1(后续枚举成员的值在前一个枚举值基础上自动+1)。

        HAL_GPIO_WritePin()函数前面两个参数用于指定端口和引脚号,第3个参数用于设置该I/O引脚的状态(0或1)。

(1) 细说HAL_GPIO_WritePin()函数

        在HAL_GPIO_WritePin()函数的定义中,首先是两行assert_param()的声明语句。if语句的条件是判断传递过来的参数PinState是否不等于0(GPIO_PIN_RESET);如果参数PinState为1(即不等于0),则通过BSRR寄存器的低16位(BS)置位,使得该引脚输出1;如果等于0,则通过BRR寄存器复位该引脚状态,使其输出0。

        固件库中的函数控制I/O,是通过操作BSRR和BRR寄存实现的。实际上,也可以直接给ODR寄存器赋值来实现对I/O引脚状态的控制,但相比于操作BSRR和BRR寄存器,这样做效率会低一些。

(2)HAL_GPIO_WritePin()和HAl_GPIO_TogglePin()的异同

        HAL_GPIO_WritePin()和HAl_GPIO_TogglePin()都可以实现对I/O引脚状态的控制,但实现的功能有区别。HAL_GPIO_WritePin()可以让I/O输出一个给定的电平(高或低电平);而函数HAl_GPIO_TogglePin()只是让相应的I/O引脚输出状态翻转,至于是输出高电平还是低电平,取决于之前的状态。

2.assert_param语句的功能

        在函数HAL_GPIO_TogglePin()中,该语句为:

assert_param(IS_GPIO_PIN(GPIO_Pin));

        在HAL_GPIO_WritePin()中,该语句为:        

assert_param(IS_GPIO_PIN(GPIO_Pin)); assert_param(IS_GPIO_PIN_ACTION(PinState));

        实际上assert_param()是一种宏,用于函数的参数检查。括号中是一个表达式为真(有效),则程序会继续执行下去;若表达式为假,则程序就会跳转,去执行可以发出错误信息的代码段。

(1)首先,HAL_GPIO_TogglePin()中的assert_param assert_param(IS_GPIO_PIN(GPIO_Pin));

        其中,GPIO_Pin是HAL_GPIO_TogglePin的参数,用于指定I/O的引脚号,例如PB3,则GPIO_Pin就是无符号数0x0008。

        IS_GPIO_PIN()是判断传递过来的GPIO_Pin是否为有效的GPIO引脚。GPIO_Pin是无符号数,GPIO端口通常为16个,GPIO_Pin从右边第1位开始,分别为0x0001、0x0004、0x0008、…、0x8000。也就是说,传递过来的GPIO_Pin应该是不为0并且只有16位的数。查看固件库中关于IS_GPIO_PIN()的声明,stm32g4xx_hal_gpio.h文件中,可知它是由define宏定义的:

# define IS_GPIO_PIN(__PIN__)((((uint32_t)(__PIN__) & GPIO_PIN_MASK) != 0x00U) && (((uint32_t)(__PIN_) & ~GPIO_PIN_MASK) = 0x00U))

        其中,__PIN__也是库函数中的宏定义,用来指明引脚号;GPIO_PIN_MASK也是通过宏定义的:

# define GPIO_PIN_MASK (0×0000FTTFU) /*PIN mask for assert test */

        在IS_GPIO_PIN(__PIN__)的定义中,当右侧两个表达式同时成立时IS_GPIO_PIN(__PIN__)才为真,这两个表达式通过&&连接。第一个表达式中,(__PIN__)&.GPIO_PIN_MASK)是用于判断传递过来的引脚号是否为GPIO_PIN_MASK为0x0000 FFFF,只要(__PIN__)不为0x0000,与0x0000 FFFF按位“与”的结果就不为0,此时第一个表达式即为真;否则为假。第二个表达式是将传递过来的引脚号和~GPIO_PIN_MASK进行逻辑“与”,只要传递过来的引脚号不多于16位,该表达式(==)就为真;否则表达式为假。两个表达式同时为真时,IS_GPIO_PIN(__PIN__)真;此时assert_param()中的表达式为真,程序会继续执行。否则就会调用assert_failed函数,输出错误信息。

        assert_param()的定义在固件库的stm32g4xx_hal_conf.h文件中,其声明如下:

#ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t *file, uint32_t line); #else #define assert_param(expr) ((void)0U) #endif /* USE_FULL_ASSERT */ (2)再看,assert_param()定义

        如果USE_FULL_ASSERT已定义过,则会编译下面两条语句:

# define assert_param(expr)((expr)?(void)0U:assert_failed((uint8_t *)__FILE__ , __LINE__)) void assert_failed(uint8_t * file,uint32_t line);

        第一句define宏定义中的(void)0U,是空语句的表达式。将assert_param(expr)定义为:

        如果表达式expr真,就是空语句(void)0U;如果表达式expr假,则为assert_failed()函数。define宏定义后,就是对assert_failed()的声明。

        如果USE_FULL_ASSERT未定义过,则会编译#else中的内容,就是用define宏定义直接将assert_param(expr)定义为空语句(void)0U。

        其中,在(void)0U中,“0”后跟个“U”表示此“0”为无符号数。"__FILE__,__LINE__"也是宏定义,用来表示文件和行数。函数assert_failed()在这个定义中只是进行了声明,并没有具体定义。

3.ifdef条件编译

        声明中用到了ifdef条件编译。它的定义格式如下:

# ifdef 标识符 程序段1 //标识符被定义过(通常是用#define命令定义的),则编译程序段1 # else //条件编译中可以没有#else部分 程序段2 //否则编译程序段2 # endif



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3