野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 4762|回复: 2

如何使用固件库的assert功能

[复制链接]
发表于 2017-9-2 14:12:22 | 显示全部楼层 |阅读模式
不想看原理可直接在帖子尾部下载工程代码。
以下为说明:
在stm32固件库里有个 断言检测 assert_param功能,就是在库函数开头里常见的对输入参数检测,如下GPIO_Init库函数的源 代码(stm32f4xx_gpio.c):

  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
  2. {
  3.   uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;

  4.   /* Check the parameters */
  5.   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  6.   assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
  7.   assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  8.   assert_param(IS_GPIO_PUPD(GPIO_InitStruct->GPIO_PuPd));
复制代码
这个assert_param是如何实现参数检测呢?
可以看到这个assert_param输入参数为一些  IS_xxxxx  开头的宏,我们可以在库函数的头文件找到定义,
如下代码(stm32f4xx_gpio.h):
  1. /** @defgroup GPIO_pins_define
  2.   * @{
  3.   */
  4. #define GPIO_Pin_0                 ((uint16_t)0x0001)  /* Pin 0 selected */
  5. #define GPIO_Pin_1                 ((uint16_t)0x0002)  /* Pin 1 selected */
  6. #define GPIO_Pin_2                 ((uint16_t)0x0004)  /* Pin 2 selected */
  7. #define GPIO_Pin_3                 ((uint16_t)0x0008)  /* Pin 3 selected */
  8. #define GPIO_Pin_4                 ((uint16_t)0x0010)  /* Pin 4 selected */
  9. #define GPIO_Pin_5                 ((uint16_t)0x0020)  /* Pin 5 selected */
  10. #define GPIO_Pin_6                 ((uint16_t)0x0040)  /* Pin 6 selected */
  11. #define GPIO_Pin_7                 ((uint16_t)0x0080)  /* Pin 7 selected */
  12. #define GPIO_Pin_8                 ((uint16_t)0x0100)  /* Pin 8 selected */
  13. #define GPIO_Pin_9                 ((uint16_t)0x0200)  /* Pin 9 selected */
  14. #define GPIO_Pin_10                ((uint16_t)0x0400)  /* Pin 10 selected */
  15. #define GPIO_Pin_11                ((uint16_t)0x0800)  /* Pin 11 selected */
  16. #define GPIO_Pin_12                ((uint16_t)0x1000)  /* Pin 12 selected */
  17. #define GPIO_Pin_13                ((uint16_t)0x2000)  /* Pin 13 selected */
  18. #define GPIO_Pin_14                ((uint16_t)0x4000)  /* Pin 14 selected */
  19. #define GPIO_Pin_15                ((uint16_t)0x8000)  /* Pin 15 selected */
  20. #define GPIO_Pin_All               ((uint16_t)0xFFFF)  /* All pins selected */

  21. #define GPIO_PIN_MASK              ((uint32_t)0x0000FFFF) /* PIN mask for assert test */
  22. #define IS_GPIO_PIN(PIN)           (((PIN) & GPIO_PIN_MASK ) != (uint32_t)0x00)
复制代码
这代码的最后一行即 IS_GPIO_PIN是一个用来判断输入参数是否合法的条件,
例如在这个检测中,IS_GPIO_PIN(0x00)则返回 假 ,
再把IS_GPIO_PIN(0x00) 为假的结果作为参数调用assert_param,即GPIO_Inii库函数的开头部分,
我们查看assert_param的定义,看看会是什么样的结果(stm32f4xx_conf.h):
  1. /* Uncomment the line below to expanse the "assert_param" macro in the
  2.    Standard Peripheral Library drivers code */
  3. /* #define USE_FULL_ASSERT    1 */

  4. /* Exported macro ------------------------------------------------------------*/
  5. #ifdef  USE_FULL_ASSERT

  6. /**
  7.   * @brief  The assert_param macro is used for function's parameters check.
  8.   * @param  expr: If expr is false, it calls assert_failed function which reports
  9.   *         the name of the source file and the source line number of the call
  10.   *         that failed. If expr is true, it returns no value.
  11.   * @retval None
  12.   */
  13.   #define assert_param(expr)     ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
  14. /* Exported functions ------------------------------------------------------- */
  15.   void assert_failed(uint8_t* file, uint32_t line);
  16. #else
  17.   #define assert_param(expr) ((void)0)
  18. #endif /* USE_FULL_ASSERT */
复制代码
这个assert_param函数分两种情况,
1.当没有定义宏USE_FULL_ASSERT的时候,assert_param为空函数,也就是断言参数检测功能没有作用,什么事都没干
2.当定义了宏USE_FULL_ASSERT的时候,assert_param是一个宏,若输入参数为真时什么也不做,若参数为假时调用assert_failed函数,
  而这个assert_failed函数在下面只有一个声明,需要我们去实现,例如我们可以定义这个函数printf信息到串口调试助手,或者点亮一个LED灯提示。


下面给出使用这个断言功能的工程代码,工程代码在帖子的尾部,适用于F429,F1原理类似,可以自己参考来改。
工程的思想:

1.使能断言检测,当输入参数错误触发断言时点亮红色的LED灯。
在stm32f4xx_conf.h使能断言,加入宏USE_FULL_ASSERT    并把assert_failed函数声明改成外部声明,我们将在bsp_led.c文件定义该函数:

  1. #define USE_FULL_ASSERT    1

  2. /* Exported macro ------------------------------------------------------------*/
  3. #ifdef  USE_FULL_ASSERT

  4. /**
  5.   * @brief  The assert_param macro is used for function's parameters check.
  6.   * @param  expr: If expr is false, it calls assert_failed function
  7.   *   which reports the name of the source file and the source
  8.   *   line number of the call that failed.
  9.   *   If expr is true, it returns no value.
  10.   * @retval None
  11.   */
  12.   #define assert_param(expr) ((expr) ? (void)0 : assert_failed())
  13. /* Exported functions ------------------------------------------------------- */
  14.   extern void assert_failed(void);
  15. #else
  16.   #define assert_param(expr) ((void)0)
  17. #endif /* USE_FULL_ASSERT */
复制代码


在bsp_led.c文件定义 assert_faild函数,直接点亮红灯:
  1. void assert_failed()
  2. {
  3.                 LED1_ON;
  4. }
复制代码



2.先初始化好红色LED灯,并默认为关闭状态


  1. /**
  2.   * @brief  初始化控制LED的IO
  3.   * @param  无
  4.   * @retval 无
  5.   */
  6. void LED_GPIO_Config(void)
  7. {               
  8.      /*定义一个GPIO_InitTypeDef类型的结构体*/
  9.     GPIO_InitTypeDef GPIO_InitStructure;

  10.      /*开启LED相关的GPIO外设时钟*/
  11.     RCC_AHB1PeriphClockCmd ( LED1_GPIO_CLK|
  12.                                    LED2_GPIO_CLK|
  13.                                    LED3_GPIO_CLK, ENABLE);

  14.     /*选择要控制的GPIO引脚*/                                                                                                                           
  15.     GPIO_InitStructure.GPIO_Pin = LED1_PIN;        

  16.     /*设置引脚模式为输出模式*/
  17.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   
  18.    
  19.     /*设置引脚的输出类型为推挽输出*/
  20.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  21.    
  22.     /*设置引脚为上拉模式*/
  23.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  24.     /*设置引脚速率为2MHz */   
  25.    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

  26.    /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
  27.   GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);        
  28.    
  29.                
  30.    /*关闭RGB灯*/
  31.    LED1_OFF;        
  32.                
  33.   //把LED 红灯确认关闭,再初始化LED2,LED2使用错误的参数,
  34.   //初始化LED2时会引起assert fail,触发调用,点亮红灯
  35.                
  36.                
  37.     /*选择要控制的GPIO引脚*/                                                                                                                           
  38.                 GPIO_InitStructure.GPIO_Pin = LED2_PIN;        
  39.     GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);        
  40.    
  41.     /*选择要控制的GPIO引脚*/                                                                                                                           
  42.                 GPIO_InitStructure.GPIO_Pin = LED3_PIN;        
  43.     GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);        
  44.                
  45.         
  46. }
复制代码


3.再次调用GPIO_Init函数时,给它输入一个错误的引脚参数,如0x00,
修改bsp_led.h文件,定义一个GPIO_Pin_16      宏,宏值为0x00,并把原来绿灯的引脚改成GPIO_Pin_16     
  1. #define GPIO_Pin_16      0x0000


  2. //G 绿色灯
  3. #define LED2_PIN                  GPIO_Pin_16                 
  4. #define LED2_GPIO_PORT            GPIOH                     
  5. #define LED2_GPIO_CLK             RCC_AHB1Periph_GPIOH
复制代码


4.在main函数调用LED_GPIO_Config(),该函数初始化完红灯后,红灯处于关闭状态,再初始化绿灯时,由于断言检测触发assert_faild导致红灯亮


工程代码: asserTemplate.zip (767.94 KB, 下载次数: 22)





回复

使用道具 举报

发表于 2017-9-2 15:53:16 | 显示全部楼层
good                 
回复 支持 反对

使用道具 举报

发表于 2017-9-5 19:59:45 | 显示全部楼层
顶顶顶
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-19 14:47 , Processed in 0.070044 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表