你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 中的 assert_param 函数  

[复制链接]
yceast 发布时间:2015-11-7 20:51
本帖最后由 yceast 于 2015-11-8 21:23 编辑
& h+ r: Z& T+ y$ P: P
, q& J* N4 q. F( I8 V3 X& t
        我们在学STM32的时候函数assert_param出现的几率非常大,上网搜索一下,网上一般解释断言机制,做为程序开发调试阶段时使用。下面我就谈一下我对这些应用的看法,学习东西抱着知其然也要知其所以然。
* y7 r( L1 E  O6 l5 ]# i& k4 断言机制函数assert_param% x$ ^7 H1 T& d, ^+ d: x9 G
我们在分析库函数的时候,几乎每一个函数的原型有这个函数assert_param();下面以assert_param(IS_GPIO_ALL_PERIPH(GPIOx));为例说一下我的理解,函数的参数IS_GPIO_ALL_PERIPH(GPIOx),我们可以寻找到原型3 H) {. h. W7 ]0 E7 J: z
#define IS_GPIO_ALL_PERIPH(PERIPH) (((*(uint32_t*)&(PERIPH)) == GPIOA_BASE)||
" N' g5 c9 J3 r((*(uint32_t*)&(PERIPH)) == GPIOB_BASE) || 6 F4 d' K, e9 {9 T( r1 a% J9 h
((*(uint32_t*)&(PERIPH)) == GPIOC_BASE) ||
+ x- w0 z% Q3 e  m3 _; Y((*(uint32_t*)&(PERIPH)) == GPIOD_BASE) || 4 f; m( W2 }# B, e
((*(uint32_t*)&(PERIPH)) == GPIOE_BASE) || % `  L; z6 T7 @
((*(uint32_t*)&(PERIPH)) == GPIOF_BASE) || % q" }! T2 F8 ?0 y  ]0 G
((*(uint32_t*)&(PERIPH)) == GPIOG_BASE))
5 \; O/ Q% o9 @0 v这个宏定义的作用就是检查参数PERIPH,判断参数PERIPH是否为GPIOX(A...G)基址中的一个,只要有一个为真则其值为真,否则为假,不用多说,这是C语言中基本的逻辑运算。当然这个库函数也用的很有意思,看:首先对PERIPH进行取址,也就是求地址,&PERIPH,然后对这个地址强制转化为32位的指针,即前面加(uint32_t *),然后通过*进行访问这个地址(指针)中的内容。不多说了,看几遍就能明白。
8 n8 _) h5 s0 _+ O% T: b7 d5 l下面我们再回到assert_param这个函数,这个函数是哪里的呢?在stm32f10x_conf.h寻找到原型如下:$ h' Q2 f5 I) H! J" ]. n
#ifdef USE_FULL_ASSERT
        #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t*)__FILE__, __LINE__))
3 I% j  H( `7 A# cvoid assert_failed(uint8_t* file, uint32_t line);
! C5 D% o, S. r! T: V#else* c4 [. ]/ Y2 }3 U
#define assert_param(expr) ((void)0)
) n8 P: d# V+ d& d#endif 7 I/ Z  n$ k# K: v" U+ M
这是一个预编译文件,若是定义了USE_FULL_ASSERT这个文件,则执行后面的文件,我们在程序中一般都没什么定义,即执行后面这个语句((void)0),这个语句不用多想,没有定义USE_FULL_ASSERT就是什么也不执行。说的明白点,对上面的那个语句IS_GPIO_ALL_PERIPH(GPIOx)不执行任何操作。
+ Q# b' ]2 }& G1 n+ [5 o0 e若是定义了USE_FULL_ASSERT它,我们调用这个函数assert_param时,及对参数IS_GPIO_ALL_PERIPH(GPIOx)的正确性进行检查,通过一个C语言中的双目运算符来判断,若是返回1,执行语句(void)0,跟上面一样,若是返回0,则执行后面的函数assert_failed((uint8_t *)__FILE__,__LINE__),函数的作用在库函数中有解释,用来指示出错的行数和文件。注意:__FILE__,__LINE__是标准库函数中的宏定义!切记
* W, [2 @- n2 Q" vvoid assert_failed(uint8_t* file, uint32_t line);刚开始没看明白为什么加在这里,仔细一想是在头文件的函数声明。至于函数实体呢?我们从官方文件的模板中main.c中可以找到。如下:" j) o3 g% r& w  C: t2 N
void assert_failed(u8* file, u32 line)
7 M8 A& [# D; _6 n3 G) }+ @) e{ /* User can add his own implementation to report the file name and linenumber,
4 e2 N4 m6 C8 E; |$ j% Sex: printf("Wrong parameters value: file %s on line %drn", file,line) */ , M7 J4 o6 V( T9 d, B% l8 s# Z
/* Infinite loop */
: }. k  H) A3 N8 O' kwhile (1) { } + c  S) ?& `0 c/ v& V  J
} 英文注释也说明了怎么应用,通过输入参数来确定位置,最简单的方法就是串口打印了,这个函数的主要思想是在输入参数有问题的时候,但是有编译不出来,它可以帮你检查参数的有效性,好处不必多言,自己领悟就行。6 ~  u& P( _% {0 r4 M; }! B! d
继续说明如下: assert_param是怎样包含进去的呢?我们在stm32f10x_conf.h这个头文件中定义的函数声明还是宏定义,怎么在其它文件中都能应用呢?也很多网上朋友在刚开始学习的时候都遇到编译不过去的问题出现,最后通过在文件中添加USE_STDPERIPH_DRIVER来解决的:
        我们可以在整个工程中进行搜索USE_STDPERIPH_DRIVER,通过头文件可以看出,是使用标准外设文件。在stm32f10x.h文件中我们可以搜索到如下情况:; _7 e4 Z$ \  V1 E6 Y
#if !defined USE_STDPERIPH_DRIVER
; j# J- A+ N% D' `9 f/ h# T/**
" f" L$ V5 q; F5 E* @brief Comment the line below if you will not use the peripherals drivers.2 F" t3 [0 Q5 l% @2 L1 |! ?& x4 ~* ~
In this case, these drivers will not be included and the application code will 6 K5 N+ k# S: W
be based on direct access to peripherals registers 1 Y6 H; J+ X8 Q( h' F  v8 c/ {& w
*/
; p( C. @0 L0 x% |#define USE_STDPERIPH_DRIVER. [6 d, j$ d- s- {, U
#endif
. P9 d# y! ?4 s4 L  ?#ifdef USE_STDPERIPH_DRIVER$ L( }+ O# S, b0 S. B- @  }
#include "stm32f10x_conf.h"
4 W# L4 G! G' t  }6 C# M. T#endif
* l1 E! r! [7 [' V* }可以很容易看出来,我们不在那里添加,这个头文件中也给我们设置了开关,只要把第一个的注释去掉,就不用在配置中添加USE_STDPERIPH_DRIVER了,在第二个文件中我们可以知道怎样包含这个控制开关文件了,呵呵。我们也明白为什么我们在写程序的时候只要包含stm32f10x.h就能很容易的包含所有的文件文件了吧,我们只要在stm32f10x_conf.h配置一下就能包含所需要的库文件了。5 F' y! U4 h4 c% o: d8 o
通过以上可以看出,通过头文件的相互包含,来控制外设以及调试文件的调用,这样我们理清思路,理解起来就好多了。当然在学习中可能有些C语言问题还没有理解透彻,多上网搜一下,或者多看书,很快就搞明白的。

1 J/ B) Q7 q4 w! i, r* X$ _) Q5 e2 [* w+ C5 T9 v5 G* U- M1 W
        PS 2:
8 C4 R/ z! N! |; x2 R% [. N
        STM32中assert_param的使用* A' K8 E$ Q$ Z* ]
在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义;
0 r6 H$ V5 y' R2 _! v: z3 k& e& z在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。) L* [' C8 G5 i& U$ w) z, B3 A
所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参数大于3,) j' N: }2 g: g: o# m
则这个assert_param()可以在运行的程序调用到这个函数时报告错误,使程序员可以及时发现错误,而不必等到程序运行结果的错误而大费周折。
        这是一种常见的软件技术,可以在调试阶段帮助程序员快速地排除那些明显的错误。
        它确实在程序的运行上牺牲了效率(但只是在调试阶段),但在项目的开发上却帮助你提高了效率。
        当你的项目开发成功,使用release模式编译之后,或在stm32f10x_conf.h文件中注释掉对USE_FULL_ASSERT的宏定义,所有的assert_param()检验都消失了,不会影响最终程序的运行效率。- D3 T) R" c& q7 E' U
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((u8 *)__FILE__, __LINE__))
$ @- K4 \) T: v7 D。。。) m6 V. Y0 R- ]0 g* A& |  n
assert_param(IS_ADC_ALL_PERIPH(ADCx));5 f# g$ [+ E% f5 k- k' R% }+ G
。。。
8 H* ^" {# H5 J3 p8 _2 [
        在执行assert_param()的检验时,如果发现参数出错,它会调用函数assert_failed()向程序员报告错误,在任何一个例程中的main.c中都有这个函数的模板,如下:
        void assert_failed(uint8_t* file, uint32_t line)
, {& F/ Q2 y# Z1 }; i{
        
$ w6 v; Y8 C2 U: K6 d1 A* E0 Rwhile (1)
* v3 t* y; X6 U, v$ b{}% R( S  z! d# L# I/ o# O  q" E& I# [
}
        你可以按照自己使用的环境需求,添加适当的语句输出错误的信息提示,或修改这个函数做出适当的错误处理。
        1、STM32F10xD.LIB是DEBUG模式的库库文件。
8 Z. S) P- D- F% ~& [2、STM32F10xR.LIB是Release模式的库库文件。
& s- ?$ @3 [- n. Q1 ~3、要选择DEBUG和RELEASE模式,需要修改stm32f10x_conf.h的内容。0 h: R2 g, B; w7 j% U* p. d9 F
    #define DEBUG 表示DEBUG模式,把该语句注释掉,则为RELEASE模式。
* v  V9 w7 M8 q' U. Z0 e9 D9 W4、要选择DEBUG和RELEASE模式,也可以在Options,C/C++,Define里填入DEBUG的预定义。
/ o& J! G, H; M' V6 s# R    这样,就不需要修改stm32f10x_conf.h的内容。) @% p6 s1 @1 D) v3 I  {! r
5、如果把库加入项目,则不需要将ST的库源文件加入项目,比较方便。
9 A  D! N9 q. @! I9 h- R* `$ b& @    但是,库的选择要和DEBUG预定义对应。
赞 收藏 2 评论39 发布时间:2015-11-7 20:51

举报

39个回答
orima 回答时间:2015-11-8 11:00:39

/ _6 [2 C- |9 t! p这个看STM板卡商了,有没有零售版的,如果只有活动才有,那就是抢的。如果是人家自己花钱买的,人家爱怎么折腾是人家的事。。。。
feiante 回答时间:2015-11-8 18:10:23
可以看看获奖的名单,如果没有他,那他就是买的,他想转让那是他的事。( p% r( L7 V; a7 c- @
不过既然楼主发了这个帖子了,也同时反映了一个问题,就是论坛中的板子靠抢,确实存在不合理的一面。如果板子靠积分换购,并且积分不会太低,那么换板子时可能大家会仔细考虑是否需要这块板子。
党国特派员 回答时间:2015-11-9 09:36:00
学习了。 blank.png blank1.png blank2.png blank3.png blank4.png
moyanming2013 回答时间:2015-11-7 21:16:13
三次都没有抢到的来顶
cq_hello 回答时间:2015-11-7 22:18:25
让我静静的赚积分,下次我也要抢
?[Wait...]?& 回答时间:2015-11-7 22:24:08
没 人家那是买的 当时发票都在群里晒出来了% r! S9 Z9 A  H, s8 K1 Y
所以不能乱说的
埃斯提爱慕 回答时间:2015-11-7 22:36:32
提示: 作者被禁止或删除 内容自动屏蔽
kingsings 回答时间:2015-11-7 22:59:05
为何恰巧是三块呢
mark0668 回答时间:2015-11-7 23:28:00
人家那是买的
wang540 回答时间:2015-11-7 23:41:43
是买的  
peter001 回答时间:2015-11-8 00:10:00
恩,不要乱说
wu1169668869 回答时间:2015-11-8 00:53:14
。。。。。。。。。。
yanhaijian 回答时间:2015-11-8 08:15:09
太无耻。
肽宰1 回答时间:2015-11-8 08:23:35
一个人可以抢三次
suoma 回答时间:2015-11-8 08:35:59
还是希望留给有需要的人
chifen 回答时间:2015-11-8 09:08:05
可以连续 抢吗
wamcncn 回答时间:2015-11-8 09:16:26
淡定............
123下一页
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版