我们在学习STM32的时候,函数assert_param出现的概率很大。网上搜索一下,网上一般都有关于断言机制的解释,在程序开发调试阶段使用。下面我就谈谈我对这些应用的看法。当我学到一些东西的时候,我想知道为什么。
4断言机制函数assert_param
我们分析库函数的时候,几乎每个函数的原型都有这个函数assert _ param();以下是用assert _ param(is _ gpio _ all _ per iph(gpiox));为了说明我的理解,我们可以找到参数的原型是_GPIO_ALL_PERIPH(GPIOx)
# define IS _ GPIO _ ALL _ peri ph(peri ph)(((*(uint 32 _ t *)(peri ph))==GPIO a _ BASE)| | \
((*(uint 32 _ t *)(PERIPH))==GPIOB _ BASE)| | \
((*(uint 32 _ t *)(PERIPH))==GPIOC _ BASE)| | \
((*(uint 32 _ t *)(PERIPH))==gpio d _ BASE)| | \
((*(uint 32 _ t *)(PERIPH))==GPIOE _ BASE)| | \
((*(uint 32 _ t *)(PERIPH))==GPIOF _ BASE)| | \
(((*(uint 32 _ t *)(PERIPH))==gp IOG _ BASE))
这个宏定义的作用是检查参数PERIPH,确定参数PERIPH是否为GPIOX (A。g)基地址之一,只要其中一个为真,其值为真,否则为假。不用说,这是C语言中最基本的逻辑运算。当然这个库函数用起来也很有意思。看:首先是地址PERIPH,也就是地址PERIPH,然后强行把这个地址转换成一个32位的指针,也就是在它前面加上(uint32_t *),然后通过*访问这个地址(指针)里面的内容。不多说了,看几遍就明白了。
让我们回到assert_param函数。这个功能从何而来?在stm32f10x_conf.h中找到的原型如下:
#ifdef USE_FULL_ASSERT
# define assert _ param(expr)((expr)?(void)0:assert _ failed((uint 8 _ t *)_ _ FILE _ _,__LINE__))
void assert_failed(uint8_t*文件,uint32_t行);
#否则
# define assert _ param(expr)((void)0)
#endif
这是一个预编译文件。如果定义了文件USE_FULL_ASSERT,将执行下面的文件。一般我们在程序中没有定义,就是会执行下面的语句((void)0)。这个语句不需要考虑太多,如果不定义USE_FULL_ASSERT,就是不执行任何东西。需要说明的是,对上面的语句IS_GPIO_ALL_PERIPH(GPIOx)什么都不做。
如果定义了USE_FULL_ASSERT,当我们调用这个函数assert_param,并检查参数IS_GPIO_ALL_PERIPH(GPIOx)的正确性时,由C语言中的一个双目运算符判断。如果它返回1,将执行语句(void)0。如上,如果返回0,将执行下面的函数assert _ failed((uint 8 _ t *)_ _ file _ _,__LINE__)。库函数中解释了该函数,以指示出错的行数和文件数。注意:__FILE__,__LINE__是标准库函数中的宏定义!一定要记住
void assert_failed(uint8_t*文件,uint32_t行);一开始不明白为什么要加在这里。仔细考虑头文件中的函数声明。功能实体呢?我们可以从官方文档的模板中在main.c中找到。如下所示:
void assert_failed(u8*文件,u32行)
{
while (1) { }
}英语笔记也解释了如何应用。通过输入参数确定位置的最简单方法是串口打印。这个函数的主要思想是当输入参数有问题,但无法编译时。它可以帮助您检查参数的有效性。好处不用多说,自己理解就好。
继续解释如下:assert_param是如何包含的?头文件stm32f10x_conf.h中定义的函数声明或宏定义如何应用到其他文件中?还有,很多网上的朋友在学习之初就遇到了不会编的问题。最后,他们通过在文件中添加use _ stderiph _ driver解决了这个问题:
我们可以在整个项目中搜索use _ stderiph _ driver。从头文件可以看出,使用的是标准外设文件。在stm32f10x.h文件中,我们可以搜索到以下几种情况:
#如果!已定义的USE _ STDPERIPH _ DRIVER
/**
* @如果您不使用外围设备驱动程序,请对下面的行进行简短评论。
在这种情况下,将不包括这些驱动程序,而包括应用程序代码
基于对外设寄存器的直接访问
*/
#定义USE _ STDPERIPH _ DRIVER
#endif
# ifdef USE _ STDPERIPH _ DRIVER
#include"stm32f10x_conf.h"
#endif
很容易看出,我们没有在那里添加它,开关是在这个头文件中为我们设置的。只要去掉第一条的注释,就不需要在配置中添加use _ stderiph _ driver。在第二个文件中,我们可以知道如何包含这个控制开关文件,呵呵。我们也明白了为什么写程序的时候通过包含stm32f10x.h就可以轻松包含所有文件。我们可以通过配置stm32f10x_conf.h来包含所需的库文件
从上面可以看出,外设和调试文件的调用是通过头文件的相互包含来控制的,这样可以理清思路,理解起来就好很多。当然,可能有一些C语言的问题在学习中没有理解透彻。上网搜一下,或者多看看书,很快就会明白的。
PS 2:
STM32中assert_param的使用
在STM32的固件库和提供的例程中随处可见assert_param()的使用。如果在任何一个例程中打开stm32f10x_conf.h文件,可以看到assert_param实际上是一个宏定义;
在固件库中,它的作用是检查传递给函数的参数是否是有效参数。
所谓有效参数,是指满足规定范围的参数。例如,参数的取值范围只能是小于3的正整数。如果给定参数大于3,
那么这个assert_param()就可以在运行的程序调用这个函数的时候报错,让程序员及时发现错误,而不是等待程序运行结果的错误。
这是一种常见的软件技术,可以帮助程序员在调试阶段快速排除那些明显的错误。
它确实牺牲了程序运行中的效率(但只是在调试阶段),但它帮助你提高了项目开发中的效率。
当你的项目开发成功,在发布模式下编译,或者在stm32f10x_conf.h文件中注释掉USE_FULL_ASSERT的宏定义,所有的assert_param()测试都会消失,不会影响最终程序的运行效率。
# define assert _ param(expr)((expr)?(void)0:assert _ failed((u8 *)_ _ FILE _ _,__LINE__))。
assert _ param(IS _ ADC _ ALL _ peri ph(ADCx));
在执行assert_param()的验证时,如果在参数中发现错误,就会调用函数assert_failed()向程序员报告错误。任何例程的main.c中都有该函数的模板,如下所示:
void assert_failed(uint8_t*文件,uint32_t行)
{
while (1)
{}
}
您可以根据自己的环境需求添加适当的语句来输出错误消息,或者修改该函数来进行适当的错误处理。
1.STM32F10xD。LIB是调试模式的库文件。
2.STM32F10xR。LIB是发布模式的库文件。
3.要选择调试和发布模式,需要修改stm32f10x_conf.h的内容
#定义调试意味着调试模式。如果语句被注释掉,它就是释放模式。
4.要选择调试和发布模式,您还可以填写预定义的调试选项C /C和Define。
这样就不需要修改stm32f10x_conf.h的内容了
5.如果将库添加到项目中,则不需要将ST库源文件添加到项目中,这样更方便。
但是,库的选择应该与预定义的调试相对应。