关于stm32f10x_conf.h文件
简介
stm32f10x_conf.h文件有2个作用:①提供对assert_param运行时参数检查宏函数的定义。②将开发者用到的标准外设头文件集中在这个文件里面,而stm32f10x_conf.h又被包含到stm32f10x.h中去了,因此方便开发者在写自己的库时,只需一股脑的包含stm32f10x.h就行了。
我本人是强烈不推荐第②功能。一个合格的C开发者应该知道它在写一个模块时,需要包含什么头文件,不需要包含什么头文件。而第②功能的做法就是,不管你用不用,我都全部包含进去。包含不会用到的头文件一般不是什么错误,但是它会影响代码的编译速度,代码的整洁和可读性。而他的第①功能又可有可无,因此我很早就打算将这个文件从工程中删除了。
本文主要介绍,在使用ST提供的标准外设驱动库V3.5.0开发stm32项目时,如何从工程中删除这个头文件,而又不影响正常开发。
关于assert_param
ST提供的标准外设库V3.5.0在实现时,为了防止用户传递的参数不合法,大量使用了运行时断言。这个断言函数名为assert_param。
例如库中的GPIO_ReadInputData函数:
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); //如果参数GPIOx不是一个合法的GPIO,则运行时会调用assert_failed来处理错误 return ((uint16_t)GPIOx->IDR);
}
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 */
解释:当我们在stm32f10x_conf.h文件定义了 USE_FULL_ASSERT(代表开发者需要启用标准库的运行时参数检查机制),那么assert_param作用为:即当参数为false时,调用assert_failed函数,否则当参数为true时,等于(void)0,也就是什么都不做。而assert_failed是一个留给开发者自己去实现的函数,他通常实现在main.c中,主体通常是一个死循环,其参数是错误发生的文件名和代码行号。也就是说当你在调用一个标准库的函数时,如果参数传递不合法,那么就会陷入死循环,因为程序没有继续允许下去的意义了。如果合法,则什么也不会发生。
当我们在stm32f10x_conf.h文件中不定义 USE_FULL_ASSERT(代表开发者不要启用标准库的运行时参数检查机制),assert_param总是等价于 :((void)0),即总是不起任何作用。这样就无法检测调用标准库时参数是否传递错误。
//------------文件:main.c------------------
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while ()
{
}
}
#endif
所以,USE_FULL_ASSERT是一个功能裁剪宏,定义后,标准库会启用参数检查机制;取消它的定义, 标准库会禁用参数检查机制。
第一个问题
为什么我们要使用V3.5.0标准库,就必须将stm32f10x_conf.h包含到工程中去(具体说是将stm32f10x_conf.h包含到stm32f10x.h中去)?
答:因为标准库V3.5.0为了实现运行时参数检查,使用了assert_param宏函数,而这个宏函数定义在stm32f10x_conf.h文件中。如果不包含这个文件到项目中去,编译器在编译标准库时,就会找不到这个函数的定义而报错。
第二个问题
我们如何将stm32f10x_conf.h包含到工程中去?
答:
在stm32f10x.h中,有如下代码片段:
//-----------文件: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
也就是说我们需要在stm32f10x.h中定义 USE_STDPERIPH_DRIVER 这个宏,才能将stm32f10x_conf.h包含到stm32f10x.h中去。而定义USE_STDPERIPH_DRIVER这个宏有2种方法:①修改stm32f10x.h,开启对USE_STDPERIPH_DRIVER的宏定义。②在编译器的宏定义选项中添加USE_STDPERIPH_DRIVER的定义。
然而为了防止开发者误修改stm32f10x.h文件,ST将这个文件的属性设置为只读的,因此第一种方法是不建议的。
第三个问题
为什么我们使用标准外设库V3.5.0,就必须提供对USE_STDPERIPH_DRIVER宏的定义?
答:结合上面的问题一和问题二就明白了。
最后一个问题
我们到底要不要启用标准库的运行时参数检查机制?
答:如果启用,则标准库的代码会在运行时执行参数检查,影响库函数的执行效率,生成的hex文件的也会膨胀。所以建议在开发时启用标准库的运行时参数检查机制,项目稳定后,发布时可以关闭。
移除stm32f10x_conf.h文件
最开始我已经表达了对stm32f10x_conf.h的态度,我不打算使用这个头文件,甚至以后得工程都不再使用它。但我又需要使用标准库,那就必须在stm32f10x.h中直接提供对assert_param的定义,而不是放在stm32f10x_conf.h中。
第一步:【右键】stm32f10x.h,将其只读属性取消,这样就可以修改它了。
第二步:
删除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
按如下操作继续修改stm32f10x.h
/*************************************************************************************
如果开发者需要启用标准库的运行时参数检查机制,则在编译器的宏定义选项中定义STDPERIPH_DRIVER_USE_ASSERT
如果开发者不想启用标准库的运行时参数检查机制,则不定义STDPERIPH_DRIVER_USE_ASSERT 提示:启用标准库的运行时参数检查机制,导致运行时执行参数检查代码,影响库函数的执行效率和生成的hex文件的体积。
建议在开发时启用标准库的运行时参数检查机制,发布时可以不启用。
*/
#ifdef STDPERIPH_DRIVER_USE_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 //====================用上面的代码替换stm32f10x.h中的下面的代码===================== #ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
#endif
第三步:
把stm32f10x.h文件的属性改回为只读,防止开发时错误的修改。
最后对main.c的修改:
如果开启了标准库的运行时参数检查机制,则还要在main.c中提供对assert_failed函数的实现,用于在参数检查错误时处理这个错误。
因此替换原先的assert_failed的定义如下:
#ifdef STDPERIPH_DRIVER_USE_ASSERT
//当标准外设库函数进行参数合法性检查发现不通过时,调用的回调处理函数
//file为错误发生的文件名,line为错误行号
void assert_failed(uint8_t* file, uint32_t line)
{
while ()
{
}
}
#endif
如何使用
通过上面的修改,我们已经不再需要stm32f10x_conf.h头文件(和里面的USE_FULL_ASSERT宏),也不再需要USE_STDPERIPH_DRIVER宏。取而代之的是一个新的宏:STDPERIPH_DRIVER_USE_ASSERT。
建议通过上面的步骤,构建一个自己的开发模板,以便后续继续使用。
这样做的好处
1、工程少了一个头文件,管理起来更加方便
2、在工程中使用标准外设库时,不再被强迫定义USE_STDPERIPH_DRIVER宏了
关于stm32f10x_conf.h文件的更多相关文章
- stm32f10x_it.c、stm32f10x_it.h和stm32f10x_conf.h文件作用
如上图,在STM32的Keil工程文件(Project)中一般都包含stm32f10x_it.c.stm32f10x_it.h和stm32f10x_conf.h这三个文件,但是在ST官方提供的标准库“ ...
- stm32f10x.h文件分析理解
今天再看过半年前自己写的这篇发现自己当时理解有误,stm32f10x.h与库开发并未存在太大关系,只是一个最为重要的寄存器地址到寄存器结构体变量的映射. stm32f10x.h 这个头文件是STM32 ...
- .lib文件 .h文件 .dll文件
.lib代表的是静态数据连接库,在windows系统中起到链接程序和函数的作用,存放的是函数的是函数调用的信息,是obj文件的集合.相当于linux中的.a或.0. .so文件.lib文件是不对外公开 ...
- 对于.h文件和.c文件
C语言中.h文件和.c文件详细解析_云止水_新浪博客http://blog.sina.com.cn/s/blog_73006d600102wcx5.html
- 有关stdint.h 文件
有关stdint.h 文件 Google C++编程规范的P25页有如下叙述: <stdint.h> 定义了 int16_t . uint32_t . int64_t 等整型,在需要确定大 ...
- 下位机多个".c, .h"文件的相互包含及排版
一.背景: 自从接触单片机编程以来,由于工作上的需要,不可避免的时常会接手别人的代码,但常常由于上一位同事的编码随意性有点大,导致可读性非常的差,有时候不得不完全舍弃原有代码,推倒重来,无形中增加了工 ...
- C语言中 *.c和*.h文件的区别!
C语言中 *.c和*.h文件的区别! http://blog.163.com/jiaoruijun07@126/blog/static/68943278201042064246409/ ...
- delegate 集成在类中,还是单独写在.h文件中?
转:http://stackoverflow.com/questions/11382057/declaring-a-delegate-protocol There definitely are sub ...
- 编译过程中,termcap.h 文件找不到路径 licli.a终于生成
编译过程中,termcap.h 文件找不到路径 查看是linux 源码下找不到termcap.h文件 安装了所有关于*cap*的源码包也不起作用 今天终于解决了这个问题,搜 ...
随机推荐
- Linux目录和文件——目录格式
Linux目录和文件——目录格式 摘要:本文主要了解了Linux系统的目录格式. 一切皆文件 Linux下“一切皆文件”是Unix/Linux的基本哲学之一. Linux中所有内容都是以文件的形式保存 ...
- Java生鲜电商平台-物流配送的设计与架构
Java生鲜电商平台-物流配送的设计与架构 说明:由于Java开源生鲜电商平台是属于自建物流系统,也就是买家下的单,需要公司派物流团队进行派送. 业务需求中买家的下单时间控制在: ...
- “金九银十”已过,总结我的天猫、蚂蚁、头条面试经历(Java岗)
跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽.切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的 ...
- Java获取客户端真实IP地址
Java代码 import javax.servlet.http.HttpServletRequest; /** * 获取对象的IP地址等信息 */ public class IPUtil { /** ...
- vuePress自动部署到Github Page脚本踩坑
背景 照着官网的教程来就行了,踩了个小坑,记录一下,希望对你有帮助 这是部署后的效果 小坑1 如图所示,官网推荐部署命令 然而windows 没有bash 指令, 直接运行报错 两个解决方法: 项目根 ...
- php 除10取整,取十位数前面一个数字,百位前两个数字
需求:php 除10取整,取十位数前面一个数字,百位前两个数字,并把大于2的加红显示 例:0-9,10-19,20-29,30-39,110-119对应为:0 1 2 3 11 实现主要方法:$num ...
- OPC 集成的五大要素,你都掌握了吗?
相信在处理工业项目集成问题的时候,自动化集成供应商真正需要的不是那些华丽的宣传语,而是提供真正的通信数据集成实力. 任何自动化集成的供应商都希望能够消除中间的层层障碍,从而实现真正的信息集成互通.那么 ...
- APS系统生产流转方式和批量算法研究
01.前言 在经济领域,生产型企业是经济的根基,有了生产型企业生产出的各种产品,才有物流.网上购物和金融融资等活动.对于生产型企业,其制造能力是其核心竞争力.如何提升制造能力一直是生产型企业面临的课题 ...
- maven 学习---Maven项目模板
Maven提供用户,使用原型的概念,不同类型的项目模板(以数字614)是一个非常大的列表. Maven帮助用户快速开始使用以下命令创建新的Java项目 mvn archetype:generate 什 ...
- A dependency may only have one source
在使用Flutter的时候添加依赖报错了 Error on line 21, column 5 of pubspec.yaml: A dependency may only have one sour ...