assert_param()函数

2023-11-05

我们在学STM32的时候函数assert_param出现的几率非常大,上网搜索一下,网上一般解释断言机制,做为程序开发调试阶段时使用。下面我就谈一下我对这些应用的看法,学习东西抱着知其然也要知其所以然。
4 断言机制函数assert_param
我们在分析库函数的时候,几乎每一个函数的原型有这个函数assert_param();下面以assert_param(IS_GPIO_ALL_PERIPH(GPIOx));为例说一下我的理解,函数的参数IS_GPIO_ALL_PERIPH(GPIOx),我们可以寻找到原型
#define IS_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, u32 line) 
{ /* User can add his own implementation to report the file name and linenumber, 
ex: printf("Wrong parameters value: file %s on line %d\r\n", 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 below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will 
be based on direct access to peripherals registers 
*/
#define USE_STDPERIPH_DRIVER
#endif

#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
#endif
可以很容易看出来,我们不在那里添加,这个头文件中也给我们设置了开关,只要把第一个的注释去掉,就不用在配置中添加USE_STDPERIPH_DRIVER了,在第二个文件中我们可以知道怎样包含这个控制开关文件了,呵呵。我们也明白为什么我们在写程序的时候只要包含stm32f10x.h就能很容易的包含所有的文件文件了吧,我们只要在stm32f10x_conf.h配置一下就能包含所需要的库文件了。
通过以上可以看出,通过头文件的相互包含,来控制外设以及调试文件的调用,这样我们理清思路,理解起来就好多了。当然在学习中可能有些C语言问题还没有理解透彻,多上网搜一下,或者多看书,很快就搞明白的。

 

 

PS 2:

       

STM32中assert_param的使用

在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义;
在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。
所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参数大于3,
则这个assert_param()可以在运行的程序调用到这个函数时报告错误,使程序员可以及时发现错误,而不必等到程序运行结果的错误而大费周折。

 

这是一种常见的软件技术,可以在调试阶段帮助程序员快速地排除那些明显的错误。

它确实在程序的运行上牺牲了效率(但只是在调试阶段),但在项目的开发上却帮助你提高了效率。

当你的项目开发成功,使用release模式编译之后,或在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_PERIPH(ADCx));
。。。

在执行assert_param()的检验时,如果发现参数出错,它会调用函数assert_failed()向程序员报告错误,在任何一个例程中的main.c中都有这个函数的模板,如下:

void assert_failed(uint8_t* file, uint32_t line)
{


while (1)
{}
}

你可以按照自己使用的环境需求,添加适当的语句输出错误的信息提示,或修改这个函数做出适当的错误处理。

1、STM32F10xD.LIB是DEBUG模式的库库文件。
2、STM32F10xR.LIB是Release模式的库库文件。
3、要选择DEBUG和RELEASE模式,需要修改stm32f10x_conf.h的内容。
    #define DEBUG 表示DEBUG模式,把该语句注释掉,则为RELEASE模式。
4、要选择DEBUG和RELEASE模式,也可以在Options,C/C++,Define里填入DEBUG的预定义。
    这样,就不需要修改stm32f10x_conf.h的内容。
5、如果把库加入项目,则不需要将ST的库源文件加入项目,比较方便。
    但是,库的选择要和DEBUG预定义对应。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

assert_param()函数 的相关文章

随机推荐

  • Spring Cloud的断路器模式是什么?如何使用断路器?Spring Cloud的配置管理是怎样实现的?

    1 Spring Cloud的断路器模式是什么 如何使用断路器 Spring Cloud的断路器模式是一种应对微服务架构中潜在故障的解决方案 在微服务架构中 不同的服务相互依赖 当某个服务出现故障或响应缓慢时 可能会导致级联故障 影响整个系
  • ELK技术栈实践(一)

    通常 日志被分散的储存不同的设备上 如果你管理数十上百台服务器 你还在使用依次登录每台机器的传统方法查阅日志 这样是不是感觉很繁琐和效率低下 当务之急我们使用集中化的日志管理 例如 开源的syslog 将所有服务器上的日志收集汇总 集中化管
  • C语言中低位存放,C语言 大端小端存储解析以及判断方法

    当我们在C语言中查看数据在内存中的存储时 我们经常会发现一个很奇怪的现象 什么现象呢 例如下面这段代码 int main int i 1 return 0 数据在内存中的存放方式似乎和我们想象的顺序不太一样 在我们的常规认知不一样 在我们的
  • [UPC] 2021秋组队17

    目录 A Quality Adjusted Life Year B Gwen s Gift C Forest for the Trees D H Index E Driving Lanes F Treasure Spotting G Nei
  • 测试第一年

    2018年 无心插柳柳成荫 终于进入了软件测试这一行 经过各种磕磕绊绊 进入了一家不足五十人的小私企 工资待遇和工作环境都不算好甚至可以说是略差 但在合肥这座对应届生极其不友好的城市 能找到一家公司做自己想做的事情已实属不易 作为一名初出茅
  • VS_VS2015或者VS2017出现跳过:1或者Skiped:1

    问题如下 解决办法 把绿色的部分全部勾上即可解决问题
  • 事务回滚,同时记录异常信息

    事务回滚 同时记录异常信息 需求 实现原理 实现 1 依赖HTTP重新发送请求 2 开启新事务 插入异常信息 需求 在发生异常时 回滚对数据库的操作 同时在数据库中插入一条异常信息 实现原理 开启新的事务 进行异常信息的数据库操作 实现 1
  • Linux中重要的目录有哪些?分别有何作用?

    当我们学习Linux知识时 除了要学习各种各样的命令之外 我们还需要了解Linux各个目录的功能 那么Linux中重要的目录有哪些 在Linux系统中 有两个非常重要的目录 bin与sbin 接下来我们详细的介绍一下 Linux重要的目录分
  • [C++]访问者模式

    在访问者模式 Visitor Pattern 中 我们使用了一个访问者类 它改变了元素类的执行算法 通过这种方式 元素的执行算法可以随着访问者改变而改变 这种类型的设计模式属于行为型模式 根据模式 元素对象已接受访问者对象 这样访问者对象就
  • 计算机视觉领域不同的方向:目标识别、目标检测、语义分割等

    计算机视觉任务 图像分类 image classification 图像分类 根据图像的主要内容进行分类 数据集 MNIST CIFAR ImageNet 目标检测 object detection 给定一幅图像 只需要找到一类目标所在的矩
  • 计算机网络知识点总结——第五章传输层

    目录 一 传输层概述 二 UDP协议 三 TCP协议 TCP报文段首部格式 重点 TCP连接管理 TCP可靠传输 TCP流量控制 重点 TCP拥塞控制 重点 拥塞控制四种算法 一 传输层概述 只有主机之间才会有的层次 传输层的功能 传输层提
  • “惊群”,看看nginx是怎么解决它的

    在说nginx前 先来看看什么是 惊群 简单说来 多线程 多进程 linux下线程进程也没多大区别 等待同一个socket事件 当这个事件发生时 这些线程 进程被同时唤醒 就是惊群 可以想见 效率很低下 许多进程被内核重新调度唤醒 同时去响
  • eclipse 导出maven 项目关联jar 文件

    一 默认导出maven 项目所在的文件夹target dependency 1 打开控制台指令窗口cmd 2 切换到maven 项目所在pom xml 文件所在目录 我的项目目录所在地址 D j2ee Morning 3 执行mvn 项目指
  • Qt多线程的创建详解

    文章目录 一 摘要 1 线程基础 2 为什么要创建多线程 3 创建多线程的方法 二 继承于QObject线程的创建 1 项目创建 2 代码编写与实现 三 线程间数据的传递 1 通过外部变量 2 通过信号与槽机制 四 总结 一 摘要 1 线程
  • Mysql 事务锁

    一 InnoDB锁的类型 S行级共享锁 S锁简单理解就是 运行 select from l where id 1 innoDB就会对id 1的这行数据进行加S锁 X行级排它锁 对数据进行修改时 就会对修改的行加X锁 排它的意思就是 在同一时
  • 【路径规划】基于哈里斯鹰优化算法的栅格法路径规划 机器人路径规划【Matlab代码#20】

    文章目录 可更换其他算法 获取资源 请见文章第6节 资源获取 1 原始HHO算法 2 机器人路径规划环境创建 3 路径规划模型建立 4 部分代码展示 5 仿真结果展示 6 资源获取 可更换其他算法 获取资源请见文章第6节 资源获取 1 原始
  • 白盒测试 代码检查

    6 2 1 代码检查法 代码检查包括桌面检查 代码审查和走查等 主要检查代码和设计的一致性 代码对标准的遵循 可读性 代码逻辑表达的正确性 代码结构的合理性等方面 发现违背程序编写标准的问题 程序中不安全 不明确和模糊的部分 找出程序中不可
  • SpringMvc学习-5-Spring MVC 文件上传

    文件上传 需要加入commons fileupload包 maven项目加入依赖
  • 1.SCT15单片机(建keil C51工程)

    1 文件管理 与新建文件 在其中创建3个文件 user obj app user 存放主函数和公共文件 obj keil软件生成的文件 app 存放各种外设文件 2 新建工程 a 打开Keil软件 点击如下进入新建工程界面 b 点击开始新建
  • assert_param()函数

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