STM32中assert_param的分析(转)

发布者:qin199099最新更新时间:2019-11-23 来源: eefocus关键字:STM32  assert_param 手机看文章 扫描二维码
随时随地手机看文章

我们在学STM32的时候函数assert_param出现的几率非常大,上网搜索一下,网上一般解释断言机制,做为程序开发调试阶段时使用。下面我就谈一下我对这些应用的看法,学习东西抱着知其然也要知其所以然。


断言机制函数assert_param


我们在分析库函数的时候,几乎每一个函数的原型有这个函数assert_param();下面以assert_param(IS_GPIO_ALL_PERIPH(GPIOx));为例说一下我的理解,函数的参数IS_GPIO_ALL_PERIPH(GPIOx),我们可以寻找到原型


#defineIS_GPIO_ALL_PERIPH(PERIPH) (((*(uint32_t*)&(PERIPH)) == GPIOA_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOB_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOC_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOD_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOE_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOF_BASE) ||

((*(uint32_t*)&(PERIPH)) ==GPIOG_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((uint8_t *)__FILE__, __LINE__))

void assert_failed(uint8_t* file,uint32_t line);

#else

#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((uint8_t *)__FILE__, __LINE__),函数的作用在库函数中有解释,用来指示出错的行数和文件。注意:__FILE__, __LINE__是标准库函数中的宏定义!切记


void assert_failed(uint8_t* file,uint32_t line);刚开始没看明白为什么加在这里,仔细一想是在头文件的函数声明。至于函数实体呢?我们从官方文件的模板中main.c中可以找到。如下:


void assert_failed(u8* file, u32line) 

    /* User can add his ownimplementation to report the file name and line number, 

       ex: printf("Wrong parametersvalue: file %s on line %drn", file, line) */ 

    /* Infinite loop */ 

    while (1) { } 


英文注释也说明了怎么应用,通过输入参数来确定位置,最简单的方法就是串口打印了,这个函数的主要思想是在输入参数有问题的时候,但是有编译不出来,它可以帮你检查参数的有效性,好处不必多言,自己领悟就行。


继续说明如下: assert_param是怎样包含进去的呢?我们在stm32f10x_conf.h这个头文件中定义的函数声明还是宏定义,怎么在其它文件中都能应用呢?也很多网上朋友在刚开始学习的时候都遇到编译不过去的问题出现,最后通过在文件中添加USE_STDPERIPH_DRIVER来解决的:

我们可以在整个工程中进行搜索USE_STDPERIPH_DRIVER,通过头文件可以看出,是使用标准外设文件。在stm32f10x.h文件中我们可以搜索到如下情况:


#if !defined USE_STDPERIPH_DRIVER

/**

* @brief Comment the line belowif you will not use the peripherals drivers.

In this case, these drivers willnot be included and the application code will 

be based on direct access toperipherals registers 

*/

#define USE_STDPERIPH_DRIVER

#endif

 

#ifdef USE_STDPERIPH_DRIVER

#include "stm32f10x_conf.h"

#endif


可以很容易看出来,我们不在那里添加,这个头文件中也给我们设置了开关,只要把第一个的注释去掉,就不用在配置中添加USE_STDPERIPH_DRIVER了,在第二个文件中我们可以知道怎样包含这个控制开关文件了,呵呵。我们也明白为什么我们在写程序的时候只要包含stm32f10x.h就能很容易的包含所有的文件文件了吧,我们只要在stm32f10x_conf.h配置一下就能包含所需要的库文件了。


通过以上可以看出,通过头文件的相互包含,来控制外设以及调试文件的调用,这样我们理清思路,理解起来就好多了。当然在学习中可能有些C语言问题还没有理解透彻,多上网搜一下,或者多看书,很快就搞明白的。

 


关键字:STM32  assert_param 引用地址:STM32中assert_param的分析(转)

上一篇:STM32 stdint.h简略翻译
下一篇:初识stm32-----串口1的字符串与字符的发送

推荐阅读最新更新时间:2024-11-16 21:36

STM32程序添加printf函数后无法运行的解决方法(串口实验)
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数. 例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下: #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { USART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(
[单片机]
基于STM32、FreeRTOS实现硬件看门狗+软件看门狗监测多任务的思路
我们都知道硬件看门狗的目的:是用来监测系统,防止系统死机,并在死机的情况下使其系统复位重启。 嵌入式专栏 1 在RTOS操作系统中,如果任务(线程)较多,出现高优先级任务长时间占用CPU资源,低优先级任务长时间得不到执行这种想象,那么我们的系统就是具有“Bug”的系统。 如上描述,假如我们的线程没有死机,只是长时间得不到执行。在这种异常情况下,我们又不希望系统复位,只希望执行特定代码,那我们该如何来避免这种问题呢? 关于看门狗硬件看门狗:利用一个 定时器 计数电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时“喂狗”。 因此程序正常工作时,定时器总不能溢出,也就不能产生复位信号。如果程序出现故障,不在定时周期内喂
[单片机]
STM32 学习过程中 printf 函数 突然不能执行的简单提示问题
一段时间没有使用KEIL建立MDK工程了,今天新建一个工程,测试串口输出,发现突然不能打印输出了,反复观察,程序确实没有问题,以为硬件问题,就将原来可以执行的程序烧写,结果居然可以,那么这就是程序问题了。 经过仔细观察,发现是这里的原因,实在好久不用就不好发现,记之! 使用自带的迷你库,才能包含printf函数!
[单片机]
<font color='red'>STM32</font> 学习过程中 printf 函数 突然不能执行的简单提示问题
STM32单片机半主机模式的应用
在keil中编程时常会遇到__use_no_semihosting_swi的警告,这时你就是进入了半主机模式。 在嵌入式的编程中你是避免不了使用printf、fopen、fclose等函数的但是因为嵌入式的程序中并没有对这些函数的底层实现,使得设备运行时会进入软件中断BAEB处,这时就需要__use_no_semihosting_swi这 个声明,使程序遇到这些文件操作函数时不停在此中断处,具体操作如下,将下列程序加入你的工程中: #pragmaimport(__use_no_semihosting_swi)#pragmaimport(_main_redirection)constchar__stdin_name[150]
[单片机]
STM32 PWM波驱动模拟舵机(库函数版)
数字舵机 vs 模拟舵机 “数字舵机区别于传统的模拟舵机,模拟舵机需要给它不停的发送PWM信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次PWM信号就能保持在规定的某个位置。” 到底模拟舵机与数码舵机在实际使用中有什么区别呢?我自己总结大致有以下几点: 1 数码舵机在位置准确度方面要高于模拟舵机。 2 在同样标称1.6公斤的舵机面前数码舵机在实际表现中会感觉更加“力气大”而模拟舵机就会“肉”点。 3 模拟舵机由于控制芯片是模拟电路,所以即便是相同型号的舵机会存在小小的性能差异,而数码舵机在一致性方面就非常好。 4 数码舵机一般均采用PID优化算法,所以,线性要好过模拟舵机。 5 对于高灵敏度
[单片机]
stm32-学习经验总结 ———UCOSIII-软件定时器
一、软件定时器简介 UC/OS-III提供了软件定时器服务,定时器的本质就是一个递减的计数器,当计数器减到0的时候可以触发某种动作的执行,这个动作通过回调函数来实现,回调函数是用户自己定义的,可以是简单的打开一个LED灯,或者开启电机等。当定时器计时完成时,定义的回调函数就会被立即调用,应用程序可以有任意数量的定时器。 注意!一定不要在回调函数中使用阻塞调用或者可以阻塞或删除定时器任务的函数,比如:OSTimeDly() OSTimeDlyHMSM() 等等一些函数。 UCOSIII的软件定时器服务的相关代码是在OS_TIMR.c文件中,当设置OS_CFG.H中的OS_CFG_TMR_EN置为1的时候软件定时器服务被使能。 UCO
[单片机]
STM32之点灯仪式
【1】寄存器信息确认 (1)STM32 PortB的起始地址是0x40010C00 (2)有可能涉及到的GPIO的地址: 寄存器名 偏移量 寄存器地址 GPIOB_CRL 0x00 0x40010C00 GPIOB_CRH 0x04 0x40010C04 GPIOB_IDR 0x08 0x40010C08 GPIOB_ODR 0x0C 0x40010C0C GPIOB_BSRR 0x10 0x40010C10 GPIOB_BRR 0x14 0x40010C14 【2】C语言操作寄存器 (1)ARM是内存与IO统一编址的,所以ARM中的所有外设都是通过寄存器的方式来操作的 (2)每个寄存器都有地址,C语言通过这些地址来操作这些寄
[单片机]
基于STM32的远程温控系统设计
温度控制是工业控制的主要对象之一,常用的温控数学模型是一阶惯性加上纯滞后环节,但其随着加热对象和环境条件的不同,会存在着较大的差异。因为温控对象这种较为普遍的含有纯滞后环节的特点,容易引起系统超调和持续的振荡,温度控制对象的参数会发生幅度较大的变化。因此无法采用传统的控制方法(如常规的PID控制)对温度进行有效的控制,而智能控制不需要对象的精确数学模型就可以对系统实施控制 。温度控制多采用由单片机系统来实现温度控制,其缺点是远程控制系统复杂,可靠性差,特别是当控制点较多、距离较远时,采取总线方式的通讯出错概率较高,影响到温度的控制精度 。   目前,多家厂商(如日本导电、岛通)均推出精度可达0.1级的基于PID算法的智能型温控仪
[工业控制]
基于<font color='red'>STM32</font>的远程温控系统设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved