STM32神器之库浅谈

笔者初次使用STM32缘于一个使用一个控制芯片通过4G网络远程控制两套步进电机协同工作的项目,跟所有的工程师一样,在考虑成本、性能、方案选择等多种因素后才选择了STM32进行项目开发。很多玩过51单片机的朋友会问STM32相比51单片机是不是单纯的IO引脚多了?或者时钟频率快了?或者跑的程序更大了?或者功能上更强大了?个人觉得STM32的精髓和灵魂之一在于其拥有自己的神器—库。

那么会有这样一个思考,作为一个库,必然有很多文件,那么这些文件是如何而来的呢?它们之间又是怎样的关系?笔者觉得真正想认识神器,必须通过实际开发才能深刻理解,但是任何事物的认知都是从美好或平淡或糟糕的开始的,所以笔者想尽力给读者呈现出一个比较美好的神器之美,那么就让笔者先浅谈一下使用神器开发与大家玩过的51单片机开发的区别吧。

在51单片机的程序开发中,我们可以直接配置寄存器来实现控制芯片的工作方式,比如中断,定时器等。那么问题在于我们如何去知道具体功能需要怎样的寄存器配置呢?我们很容易联想到使用查找表的方式,通过查阅来操作相关寄存器的配置1或者0,这种方式的弊端在于一旦资源较多,使用频繁,那这样看似琐屑机械的工作将会对工程师造成巨大的时间消耗威胁,更别说是别的工程师接手项目后进行二次开发带来的巨大压力,有人说只要有良好的说明文档和程序写作风格就可以了,那么问题来了,谁愿意花费时间代价和精力去统一一个公司的所有记录细节呢?最有效的解决方式就是不制造麻烦,或者让麻烦呈现出来,而不是隐藏于我们看不到的地方。此时此刻我们就会想怎样才能使得工程师脱离最底层的寄存器操作呢?怎样才能更容易阅读和方便进行二次开发?想一想我们以前学习C语言的时候,当时我们使用prinft()函数时,无非是学习它的使用格式,并没有去研究它的源码实现,如非必要,可以说是老死不相往来。那么我们怎样可以通过类似的方法来实现我们的上述愿望呢?来吧,用STM32库,其实可以理解为STM32提供的许多函数接口,工程师直接调用这些函数接口就可以配置STM32的寄存器,不用挖空心思去了解库底层的寄存器操作,而且对于寄存器的操作根据函数接口和调用参数一目了然。说到这里,如果读者觉得有点晕,那我正式总结一下库开发方式与直接配置寄存器方式的区别吧。库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为工程师提供配置寄存器的接口,简单说,工程师关心的就是如何使用库了。

“为什么STM32非得用库开发呢?我用51那一套来编程不行吗?”对于这个问题,我是这么看的,因为STM32外设资源非常丰富,由此带来的必然是寄存器的数量猛增和复杂度的增加,这个时候再使用直接配置寄存器方式就显出两大黑暗:第一,开发速度慢(相信现在的大多数工程师没有精力和时间花费在查找寄存器的操作表上面);第二,程序可读性差(相信很多工程师跟我一样,在看别人代码的时候容易一脸蒙尘,更别说没有注释的了)。此时如果说直接操作寄存器更直观或者程序运行占用资源少的优势时,我相信这点优势不谈也罢。那么直接配置寄存器在STM32这里就真的一点用武之地都没有了吗?也不是,笔者喜欢对频繁调用的中断服务函数中直接配置寄存器,也就是说,对于代码运行时间要求极为苛刻的地方直接配置寄存器是有更大价值的。站在哲学的角度来看,库归于分层思想。

那么还有一个至关重要的问题,STM32库基于怎样的标准来建立的呢?答案很简单(CMSIS标准),过程较迷离。谈到这里,笔者不得不讲讲其中的商业情节。我们大部分工程师使用的是ST公司生产的STM32,但是STM32采用的是cortex-M3内核,该内核是ARM公司设计的一个处理器体系架构,实际上ST公司只是负责设计内核之外的部件,然而像ST公司这样的合作厂商还有很多,于是为了避免片上外设差异带来的移植困难和软件兼容的问题,ARM建立了CMSIS标准,有一点商业模式影响行业标准的味道。谈到这里也就不难理解下面这样的事实:

CMSIS标准中最主要的为CMSIS核心层,它包括了:
内核函数层(ARM公司提供):包含用于访问内核寄存器的名称、地址定义;
设备外设函数层(芯片生产商提供):提供了片上的核外外设的地址和中断定义;
总结一下,CMSIS层位于硬件层与操作系统或者用户层之间,提供了与芯片生产商无关的硬件抽象层,为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异,这样对于软件的移植非常有利。

笔者推荐大家使用3.5版本的库进行开发,该版本可以通过登录官网获得。笔者觉得初学STM32库可以好好看看库帮助文档,该HTML文件的价值简单的来说,就是:ST公司已经为工程师写好了每一个外设的驱动了,想知道如何运用这些例子可以从这个文件中获得。大家有兴趣可以翻译一下3.5版本,网上流传的2.x版本的较多。

接下来笔者谈一下比较重要的库文件。进入Libraries文件夹可以看到,关于内核与外设的库文件分别存放在CMSIS和STM32F10X_STDPERIPH_DRIVER文件夹中。还有一个比较重要的是在core_cm3.c文件中包含的stdin.h这个头文件,这是一个ANSI C文件,提供了一些新类型定义,这个是独立于处理器之外的,就像我们熟知的C语言头文件stdio.h文件一样。

那么我们在哪里进行时钟配置呢?我们通过system_stm32f10x.c文件进行配置,该文件的功能在于设置系统时钟和总线时钟,M3比51单片机复杂,不是说外部给一个8M的晶振整个系统都会以8M晶振作为系统时钟,而是通过M3核的核内寄存器来对8M的时钟进行倍频,分频,或者使用芯片内部的时钟。所有的外设都与时钟的频率有关,所以这个文件的时钟配置非常关键。此外还有一个misc.c文件比较重要,这个文件提供了外设对内核中的NVIC(中断向量控制器)的访问函数,在配置中断时,必须把这个文件添加到工程中。最后还有一个配置使用了什么外设的头文件stm32f10x_conf.h。

最后,笔者提供一些资源链接供读者查阅,同时感谢读者耐心读完。

1. 《stm32f10x_stdperiph_lib_um.chm》
这是帮助文档,在使用库函数时,我们最好通过查阅此文件来了解库函数原型,或库函数的调用的方法,也可以直接阅读源码里面函数的函数说明。
2. 《STM32参考手册.pdf 》
这个文件相当于STM32的datasheet,它把STM32的时钟、存储器架构、及各种外设、寄存器都描述得清清楚楚。当我们对STM32的库函数的实现方式感到困惑时,可查阅这个文件。
3. 《Cortex-M3权威指南》 宋岩译。
该手册详细讲解了Cortex内核的架构和特性,要深入了解Cortex-M3内核,这是首选经典中的经典。