简介

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。

如果我们需要启用运行时参数检查,则在编译器的宏定义选项中提供STDPERIPH_DRIVER_USE_ASSERT的定义,否则不提供STDPERIPH_DRIVER_USE_ASSERT的定义。

建议通过上面的步骤,构建一个自己的开发模板,以便后续继续使用。

这样做的好处

1、工程少了一个头文件,管理起来更加方便

2、在工程中使用标准外设库时,不再被强迫定义USE_STDPERIPH_DRIVER宏了

关于stm32f10x_conf.h文件的更多相关文章

  1. stm32f10x_it.c、stm32f10x_it.h和stm32f10x_conf.h文件作用

    如上图,在STM32的Keil工程文件(Project)中一般都包含stm32f10x_it.c.stm32f10x_it.h和stm32f10x_conf.h这三个文件,但是在ST官方提供的标准库“ ...

  2. stm32f10x.h文件分析理解

    今天再看过半年前自己写的这篇发现自己当时理解有误,stm32f10x.h与库开发并未存在太大关系,只是一个最为重要的寄存器地址到寄存器结构体变量的映射. stm32f10x.h 这个头文件是STM32 ...

  3. .lib文件 .h文件 .dll文件

    .lib代表的是静态数据连接库,在windows系统中起到链接程序和函数的作用,存放的是函数的是函数调用的信息,是obj文件的集合.相当于linux中的.a或.0. .so文件.lib文件是不对外公开 ...

  4. 对于.h文件和.c文件

    C语言中.h文件和.c文件详细解析_云止水_新浪博客http://blog.sina.com.cn/s/blog_73006d600102wcx5.html

  5. 有关stdint.h 文件

    有关stdint.h 文件 Google C++编程规范的P25页有如下叙述: <stdint.h> 定义了 int16_t . uint32_t . int64_t 等整型,在需要确定大 ...

  6. 下位机多个".c, .h"文件的相互包含及排版

    一.背景: 自从接触单片机编程以来,由于工作上的需要,不可避免的时常会接手别人的代码,但常常由于上一位同事的编码随意性有点大,导致可读性非常的差,有时候不得不完全舍弃原有代码,推倒重来,无形中增加了工 ...

  7. C语言中 *.c和*.h文件的区别!

    C语言中 *.c和*.h文件的区别!  http://blog.163.com/jiaoruijun07@126/blog/static/68943278201042064246409/        ...

  8. delegate 集成在类中,还是单独写在.h文件中?

    转:http://stackoverflow.com/questions/11382057/declaring-a-delegate-protocol There definitely are sub ...

  9. 编译过程中,termcap.h 文件找不到路径 licli.a终于生成

    编译过程中,termcap.h      文件找不到路径   查看是linux  源码下找不到termcap.h文件   安装了所有关于*cap*的源码包也不起作用     今天终于解决了这个问题,搜 ...

随机推荐

  1. Docker(一) - CentOS7中安装Docker - (视频教程)

    Docker的使用越来越多,安装也相对简单.本文使用视频的方式展示在CentOS7系统中安装Docker,本文更适合于准备入门学习Docker的童靴. 以下视频,请带上耳机开始聆听 (双击全屏播放) ...

  2. 章节十五、2-PageObjectModel

    一.在实现自动化过程中,会有很多重复的代码,我们在维护代码时会很困难,如果想解决这个问题,我们就需要使用PageObjectModel(页面对象模型)的方式来进行自动化代码的书写. 二.案例演示 以该 ...

  3. https://support.microsoft.com/zh-cn/help/2290714/error-message-when-you-install-office-2010-on-a-windows-7-based-comput

    Error message when you install Office 2010 on a Windows 7-based computer "The installation of M ...

  4. torchline:让Pytorch使用的更加顺滑

    torchline地址:https://github.com/marsggbo/torchline 相信大家平时在使用Pytorch搭建网络时,多少还是会觉得繁琐,因为我们需要搭建数据读取,模型,训练 ...

  5. springboot整合OSS实现文件上传

    OSS 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量.安全.低成本.高可靠的云存储服务.OSS可用于图片.音视频.日志等海量文件的存储.各种终端 ...

  6. Urllib 库使用

    什么是Urllib Urllib是python内置的HTTP请求库包括以下模块urllib.request 请求模块   -->用来模拟发送请求  类似于输入网址敲击回车的过程urllib.er ...

  7. Mysql 视图&事务&触发器

    参考资料 一.视图 视图的含义: 视图是一个虚拟表,是从数据库中一个或者多个表中导出来的表. 1.创建视图 #语法:CREATE VIEW 视图名称 AS SQL语句 create view teac ...

  8. kubectl-trace 基于bpftrace 的kubernetes 集群性能分析工具

    kubectl-trace 是一个kubectl 的插件,我们可以使用基于bpftrace 的编程能力,来分析系统的性能问题, 强大,灵活,后边安装试用下 参考架构 参考资料 https://gith ...

  9. 原生js-input框全选

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Windows下找到JVM占用资源高的线程

    与linux下top命令直接显示进程下线程资源占用不同,Windows下默认任务管理器只能显示出进程的资源占用,jconsle等工具也只能显示出java进程资源占用,无法显示出进程能具体线程的资源占用 ...