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-11 17:27

stm32外扩外部sram学习笔记
在一般情况下stm32内部sram是足够使用的 MDK配置如下 但是有些时候内存是不够用的,比如用到ucgui的时候或者做大项目时就需要外扩sram,倘若你要把外部sram作为运行内存则可以做如下配置: 另外一种方法就是自己写malloc函数,正点原子的内存管理函数可以借鉴一下: __align(32) u8 mem2base __attribute__((at(0X68000000))); //外部SRAM内存池 这段代码中的_attribute_ 是定位的具体位置的意思,本例中是定位到0x68000000地址;查看一下数据手册地址映射图看一下外扩地址范围,起始地址确实是0x6800
[单片机]
<font color='red'>stm32</font>外扩外部sram学习笔记
基于STM32时钟系统的开发及配置
一、背景 最近做个项目,需要使用STM32,还是以前一样的观点,时钟就是MCU心脏,供血即时钟频率输出,想要弄明白一个MCU,时钟是一个非常好的切入点。言归正传,网上已经有太多大神详述过STM32的详细配置方法了,在此就简单介绍下STM32时钟系统,以及如何配置做个简单记录,方便以后的快速开发。 二、正文 废话不多说,上一张STM32F10xx的时钟树图: 由图可知,STM32F10XX有两级时钟 第一级时钟 * 高速内部时钟(HSI) * 锁相环时钟(PLLCLK) * 高速外部时钟(HSE) 第二级时钟 * 低速内部时钟(LSI) * 低速外部时钟(LSE) 又由图可知, * HSE由外部晶振从“OSC_OUT”,“
[单片机]
基于<font color='red'>STM32</font>时钟系统的开发及配置
STM32之can 实例+代码解析
#include sysdef.h #define MAX_MAIL_NUM 3 //CAN总线调试:0=运行 1=自环调试 #define CAN_DEBUG 0 //CAN总线波特率:0=250kbps,1=500kbps,2=1Mbps #define CAN1_BPS 0 unsigned char can1_addr = 0; unsigned short Can1_Tx_Count =0; unsigned short Can1_Rx_Count =0; unsigned short Can1_Send_Delay =0; unsigned char Can1_Send_Buf ={0xe
[单片机]
STM32 printf函数打印到串口
学习STM32过程中,经常打交道的莫过于串口,你可以将任何信息,当然重要的是调试信息打印到串口中输出,总是用一个字节发送函数或者字符串发送函数总是有些不放便,之前编程中熟悉的莫过于printf了,下面就给出了用printf打印到串口的方案,当然方案不止一个,仅供参考。 1、 添加printf的头文件 #include int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; } 3、修改一下选中Us
[单片机]
stm32之堆栈
stm32中的堆栈设置 keil编译完成时存储情况 当编译成功时,会出现: BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632 Code:程序代码部分 RO-data: 程序定义的常量const temp RW-data:已初始化的全局变量 ZI-data:未初始化的全局变量 片中的: flash=Code+RO-data+RW-data RAM=RW-data+ZI-data 通过上面的BUILD可以看出,这个程序已经用了1600多的RAM,为什么会出用到这么多的RAM呢? 在startup_stm32f10x_md.s文件中存在:
[单片机]
STM32学习笔记8——串口输出数据丢失问题
项目中采用STM32F103和AD7260进行数据采集。采集后想将数据通过串口逐点输出到上位机,然后查看数据是否正确。AD7260是采用外部中断进行采集的,当AD7260的BUSY输出下降沿后,触发外部中断,这时CPU去采集数据。 串口输出部分,我先是这么做的:在中断中采集数据的后面添加printf(串口已经重定向到printf函数)语句,每采集得到一个点后直接printf输出。上位机用软件SerialChart测试,发现数据经常丢失,或者出现一个很大的数(明显超出ADC的输出范围)。可初步断定,是串口输出部分出了问题。调试得出的结果很简单,但一开始走了很多弯路,如下: 1、先是感觉串口输出被外部中断打断,在网上查串口输出
[单片机]
stm32 无初值指针变量导致程序跑飞
//定时器3中断服务程序 void TIM3_IRQHandler(void) { if(TIM3- SR&0X0001)//溢出中断 { char str ; //LED1=!LED1; //TIM3- CR1 &= 0xfe; //关闭定时器3 rx_all += rx_count; tx_all += tx_count; sprintf(str, %4d ,rx_all); show_str(25,0,str); sprintf(str, %4d ,tx_all); show_str(15,0,str); sprintf(str, %4d ,(rx_count 2)); show
[单片机]
STM32的三种延时方法的代码实现_纯软件延时, 系统定时器延时, 定时器延时
/* 外部调用: delay_init(72); //系统主频, 单位为MHZ, 仅对 SYSTICK_DELAY 有效 delay_ms(1000); */ #include stm32f10x.h //#define SOFT_DELAY //纯软件延时 //#define SYSTICK_DELAY //系统定时器延时 #define TIMER_DELAY //定时器延时 #ifdef TIMER_DELAY #define TIMER_DELAY TIM4 #define TIMER_DELAY_PERIOD 1000 #de
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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