flyleaf 发表于 2017-9-2 14:12:22

如何使用固件库的assert功能

不想看原理可直接在帖子尾部下载工程代码。
以下为说明:
在stm32固件库里有个 断言检测 assert_param功能,就是在库函数开头里常见的对输入参数检测,如下GPIO_Init库函数的源 代码(stm32f4xx_gpio.c):

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

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

#define GPIO_PIN_MASK            ((uint32_t)0x0000FFFF) /* PIN mask for assert test */
#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):
/* Uncomment the line below to expanse the "assert_param" macro in the
   Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT    1 */

/* Exported macro ------------------------------------------------------------*/
#ifdefUSE_FULL_ASSERT

/**
* @briefThe assert_param macro is used for function's parameters check.
* @paramexpr: 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)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#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文件定义该函数:

#define USE_FULL_ASSERT    1

/* Exported macro ------------------------------------------------------------*/
#ifdefUSE_FULL_ASSERT

/**
* @briefThe assert_param macro is used for function's parameters check.
* @paramexpr: 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)0 : assert_failed())
/* Exported functions ------------------------------------------------------- */
extern void assert_failed(void);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */

在bsp_led.c文件定义 assert_faild函数,直接点亮红灯:void assert_failed()
{
                LED1_ON;
}


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


/**
* @brief初始化控制LED的IO
* @param无
* @retval 无
*/
void LED_GPIO_Config(void)
{               
   /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStructure;

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

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

    /*设置引脚模式为输出模式*/
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   
   
    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   
    /*设置引脚为上拉模式*/
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

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

   /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);      
   
               
   /*关闭RGB灯*/
   LED1_OFF;      
               
//把LED 红灯确认关闭,再初始化LED2,LED2使用错误的参数,
//初始化LED2时会引起assert fail,触发调用,点亮红灯
               
               
    /*选择要控制的GPIO引脚*/                                                                                                                           
                GPIO_InitStructure.GPIO_Pin = LED2_PIN;      
    GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);      
   
    /*选择要控制的GPIO引脚*/                                                                                                                           
                GPIO_InitStructure.GPIO_Pin = LED3_PIN;      
    GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);      
               
      
}

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


//G 绿色灯
#define LED2_PIN                  GPIO_Pin_16               
#define LED2_GPIO_PORT            GPIOH                     
#define LED2_GPIO_CLK             RCC_AHB1Periph_GPIOH

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


工程代码:





fire 发表于 2017-9-2 15:53:16

good               

田志 发表于 2017-9-5 19:59:45

{:3_48:}顶顶顶
页: [1]
查看完整版本: 如何使用固件库的assert功能