关于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*的源码包也不起作用 今天终于解决了这个问题,搜 ...
随机推荐
- 350道面试题分享,拿下京东offer工资double
350道面试题分享,拿下京东offer工资double 前言: 面试,其实是一个双向选择的过程,在这个过程里,我们不应该抱着畏惧的心态去对待,这样反而会影响自己的发挥.同时看中的应该不止薪资,还要看你 ...
- Linux 配置程序包源 Nuget
编辑文件NuGet.Config vi ~/.nuget/NuGet/NuGet.Config 新增源 <add key="fz" value="http://19 ...
- Mysql EF Core 快速构建 Web Api
(1)首先创建一个.net core web api web项目; (2)因为我们使用的是ef连接mysql数据库,通过NuGet安装MySql.Data.EntityFrameworkCore,以来 ...
- IntelliJ IDEA 中使用 Lambok (注解无效问题的解决)
一,概述 Lambok可以说一个能很大提高开发效率的插件,只要在使用注解的方式就能实现很多常用的功能.如常用的@Data能在编译阶段自动生成toString方法,getter方法setter方法等. ...
- 英语LIGNALOO沉香lignaloo单词
沉香lignaloo,是瑞香科.沉香属的一种乔木,高5-15米.树皮暗灰色,几平滑,纤维坚韧:小枝圆柱形,具绉纹,幼时被疏柔毛,后逐渐脱落,无毛或近无毛.产于中国广东.海南.广西.福建等地.喜生于低海 ...
- Linux 和 Windows多线程函数对应表
Linux Pthread API Windows SDK 库对应 API 创建 pthread_create CreateThread 退出 pthread_exit ThreadExit 等待 p ...
- 素数、杨辉三角、封装结构和集合操作(15)——IPython使用和封装解构
IPython使用 帮助 ? ##Ipython的概述和简介 help(name) ##查询指定名称和帮助 obj? ##列出obj对象的详细信息 obj?? ##列出更详细的信息 特殊变量 _表示前 ...
- 上云测试,这些关键点你get 到没有
导读,先从云化说起,再谈谈云化形态下,除了常规的功能测试,云化的测试,还需要有几个必须要get到的硬核指标,最后在分别详解这些关键点硬核指标是什么,和如何测试呢.这是个值得深思的问题,希望所有测试人都 ...
- Rust中的字符串处理
一路看过来,怕是我知道的所有语言当,处理最复杂吧. 当然,如果能正确处理,也是能理解最到位的. 这,就是我为什么要学Rust的原因. 暂无用武之地,但逻辑体系和知识点够复杂,才能应对更多事务~ fn ...
- 文件上传-pubsec-文件上传大小限制
文件上传-pubsec-文件上传大小限制 Caused by: java.lang.IllegalArgumentException: ContextPath must start with '/' ...