STM32外设库文件分析(V3.5)

标准库文件3.5版本 
1._htmresc 里面有两个logo,没用,删除。
2.Release_Notes.html 发行版本,可以看到各个版本的发行时间,修改内容。
3.Utilities 里面是一些测试C文件,评估使用。
4. stm32f10x_stdperiph_lib_um.chm 帮助文件。
5.Project 文件夹有个模版和一个例程。以工程模式提供。
6.Libraries 文件夹下面包括两个文件夹:

CMSIS Cortex Microcontroller Software Interface Standard 
CM3
     CoreSupport:core_cm3.c core_cm3.h

     DeviceSupport
ST
    STM32F10x: stm32f10x.h,system_ stm32f10x.c,system_ stm32f10x.h   startup
arm:启动文件
Documentation:Cortex Microcontroller Software Interface Standard 发行版本记录

STM32F10x_StdPeriph_Driver

根据需要和开发环境对文件进行了一些精简,精简后的内容:
CMSIS Cortex Microcontroller Software Interface Standard
  CoreSupport
        Core_cm3.c:
STM32从3.0库开始引入了CMSIS,CMSIS是Cortex微控制器软件接口标准(Cortex MicroController Software Interface Standard)的缩写,
这个是ARM定制的一个用于Cortex-M系列的一个标准,主要是为了提供通用api接口来访问内核和一些片上外设,提高代码的可移植性。
CMSIS有三个层:
核内外设访问层 Core Peripheral Access Layer(CPAL),
中间件访问层    Middleware Access Layer(MWAL),
设备访问层       Device Peripheral Access Layer(DPAL)。
CPAL用于访问内核的寄存器和组件,如NVIC,调试系统等。该层是由ARM实现的。
MWAL用于对中间件的访问,现在该层还未实现。(也不知道所谓的中间层是什么东西)。
DPAL用于定义一些硬件寄存器的地址和一些外设访问函数,由芯片制造商实现。
 
CPAL层的实现就是Core_cm3.c文件,DPAL层的实现就是system_ stm32f10x.c文件(似乎还应该加上外设的函数库)。
 
接下来就来了解一下Core_cm3.c里面有什么东东:
首先是汇编关键字__ASM和__INLINE的宏定义,支持不同的编译器。由于使用的是Keil,所以就只看第一种,__CC_ARM。
这里面的函数调用都只符合ARM过程调用标准的,如R0到R3用作参数和返回值传递,这也是这里面唯一用到的。
此外,在Keil中使用了__asm关键字后,编译器不会为函数增加返回指令,所以需要自己编写返回命令,也就是每个函数后面的   bx lr。
1.       __ASM uint32_t  __get_PSP(void):获取进程堆栈指针PSP。
2.       __ASM void __set_PSP(uint32_t topOfProcStack):设置PSP。
3.       __ASM uint32_t __get_MSP(void):获取主堆栈指针MSP。
4.       __ASM void __set_MSP(uint32_t mainStackPointer):设置MSP。
5.       __ASM uint32_t __REV16(uint16_t value):反转半字中字节顺序,如0xABCD反转后得到0xCDAB。
6.       __ASM int32_t __REVSH(int16_t value):反转字节顺序,并做符号拓展。
就是在__REV16函数得到的结果上再进行一次符号拓展。这两个函数主要是方便进行大小端的切换。
7.       __ASM void __CLREX(void):清除由LDREX指令造成的互斥锁。LDREX和STREX是Cortex用来实现互斥访问,
保护临界资源的指令,LDREX执行后,只有离它最近的一条存储指令(STR,STREX)才能执行,其他的存储指令都会被驳回,
而CLREX就是用于清除互斥访问状态的标记。
8.       __ASM uint32_t   __get_BASEPRI(void):获取BASEPRI寄存器的值,
优先级号高于该寄存器的中断都会被屏蔽(优先级号越大,优先级越低),为零时不屏蔽任何中断。
9.       __ASM void __set_BASEPRI(uint32_t basePri):设置BASEPRI的值。
10.   __ASM uint32_t __get_PRIMASK(void):PRIMASK是一个只有一位的寄存器,置位时屏蔽绝大部分的异常中断,
只剩下NMI和HardFault可以响应。
11.   __ASM void __set_PRIMASK(uint32_t priMask):设置PRIMASK的值。
12.   __ASM uint32_t   __get_FAULTMASK(void):FAULTMASK也是一个只有一位的寄存器,为1时只有NMI才能响应,
其他异常与中断全部被屏蔽。
13.   __ASM void __set_FAULTMASK(uint32_t faultMask):设置FAULTMASK的值。
14.   __ASM uint32_t __get_CONTROL(void):获取CONTROL的值。寄存器CONTROL只有两位。
CONTROL[0]选择特权级别,0为特权级,1为敌用户级。CONTROL[1]用于选择堆栈指针,0为MSP,1为PSP。
15.   __ASM void __set_CONTROL(uint32_t control):设置CONTROL寄存器的值。
BASEPRI,PRIMASK,FAULTMASK,CONTROL都只能在特权模式下被修改。
C++的关键字 asm

微软详述:
__asm关键字启动内联汇编并且能写在任何c/c++合法语句之处.它不能单独出现.
它必须接汇编指令、一组被大括号包含的指令或一对空括号.术语“__asm 块”在这里是任意一个指令或一组指令无论是否在括号内。
以下代码片段是在括号内的一个简单的__asm块。
__asm
{
           mov al, 2
         mov dx, 0xD007
         out al, dx
}

另一种方法是,你可以在每个汇编指令前放置__asm
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx
因为__asm关键字是一个语句分隔符,你也可以将汇编指令放在同一行:
__asm mov al, 2   __asm mov dx, 0xD007   __asm out al, dx
以上三个的例子产生相同的代码,但是第一种风格(把__asm块用括号括起来)有一些优势。
括号可以清晰的将C或C++代码和汇编代码分开,并且避免了不必要的重复__asm关键字。括号也能避免模糊性。
如果你想在__asm块的同一行放置一个C或C++语句,你必须将块用括号括起来。
没有括号,编译器不能告诉汇编代码在哪里停止而C或C++代码在哪里开始。
最后,因为在括号的文字有和原始MASM一样的格式,你能轻松的从一个已有的MASM源文件里剪切和黏贴文字到文件来。
不同于C和C++的括号,包含__asm块的括号对变量的作用域并没有效果。你也能嵌套__asm块,嵌套对变量作用域也没有效果。

core_cm3.h:里面包含了一些内联函数,数据结构,这些数据结构都是核心的外设数据结构,大概包括:NVIC,SCB,ITM,CoreDebug,SysTick.
       对以上设备进行设置的函数也在这个头文件里,以静态内联函数的形式出现,例如 static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn),
       其中,__INLINE   是__inline 的替代。 静态函数 static 声明。
       Core_cm3.c 文件中定义的函数声明也在这个文件中。
       invlude包含指令不仅仅限于.h头文件,可以包含任何编译器能识别的C/C++代码文件,包括.c,.hpp,.cpp,.hxx,.cxx等,甚至.txt,.abc等等都可以。
          预处理器发现 #include 指令后,就会寻找后跟的文件名并把这个文件的内容包含到当前文件中。
                               被包含文件中的文本将替换源代码文件中的#include 指令, 
       就像你把被包含文件中的全部内容键入到源文件中的这个位置一样。
DeviceSupport
stm32f10x.h:
       新版的固件库V3.0以上 main等源文件中不再直接包含 stm32f10x_conf.h,
       而是 stm32f10x.h, stm32f10x.h则定义了启动设置,以及所有寄存器宏定义,
       此文件中需要注意的有:

     1、device选择
     #if !defined ( STM32F10X_LD)    && !defined ( STM32F10X_LD_VL) && !defined ( STM32F10X_MD) 
     &&   !defined ( STM32F10X_MD_VL)&& !defined ( STM32F10X_HD)      && !defined ( STM32F10X_HD_VL) 
     &&   !defined ( STM32F10X_XL)    && !defined ( STM32F10X_CL) 
   
     #endif
     #if !defined ( STM32F10X_LD) && !defined ( STM32F10X_LD_VL) 
     && !defined ( STM32F10X_MD) && !defined ( STM32F10X_MD_VL) 
     && !defined ( STM32F10X_HD) && !defined ( STM32F10X_HD_VL) 
     && !defined ( STM32F10X_XL) && !defined ( STM32F10X_CL)
        #error "Please select first the target  STM32F10x device used in your application (in stm32f10x.h file)"
     #endif
如果都没有定义,编译器会报错。

2、外设宏定义USE_STDPERIPH_DRIVER
#if !defined   USE_STDPERIPH_DRIVER
#endif
注意 stm32f10x.h文件的后面有这样的代码,大概8300行左右:
#ifdef USE_STDPERIPH_DRIVER
#include " stm32f10x_conf.h"
#endif
stm32f10x_conf.h中包含了所有外设的头文件,因此任意源文件只要包含了 stm32f10x.h,就可以在源文件调用任意外设的函数。
3、外部时钟频率选择
#if !defined HSE_VALUE
#ifdef  STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000)
#else
#define HSE_VALUE ((uint32_t)8000000)
#endif
#endif
注意 STM32F10X_CL, STM32F10X_CL是 stm32f105 和 stm32f107 互联型的device,
用到此器件外部要选用25MHz的晶体,此处默认的外部8MHz的晶体
4. stm32f10x.h包含了这些头文件,include" stm32f10x.h",就不用包含下面这些了。
    #include "core_cm3.h"
    #include "system_ stm32f10x.h"
    #include

system_ stm32f10x.c:
这个文件中包含系统上电复位之后时钟设置要调用的函数:
SystemInit()系统初始化,系统上电复位,main()在启动其它分支程序以前调用的函数。
SetSysClock(),被SystemInit()函数调用,设置系统时钟频率,根据宏定义选择系统运行的时钟频率。
SetSysClockTo24
SetSysClockTo36
SetSysClockTo48
SetSysClockTo56
SetSysClockTo72
SetSysClockToHSE
system_ stm32f10x.h 源文件函数声明的头文件。

startup文件夹包含各个系列的启动代码,用户应该根据自己的芯片类型来选择启动代码。

    STM32F10x_StdPeriph_Driver
inc:头文件没什么好说的了,一个头文件对用一个源文件,包括函数,数据结构的的一些声明
src:这一层就是Device Peripheral Access Layer(DPAL)了,看看名字就知道是关于哪个设备的,没什么
        说的。唯一有一个例外就是misc.c文件, STM32 V3.5版本的库函数中没有原来版本中单独对于NVIC(中断向量嵌套)的外设驱动,
        把NVIC的外设驱动放在了misc.c中,实际上是代替原来的 stm32f10x_nvic.c.
3.5 版本的库文件中少了stm32f10x_it.c文件,需要自己添加。

15:54 2012-09-03

1.没有加入 stm32f10x_it.c 初始化文件找不到中断向量。
2.没有加入CM3文件夹的的头文件,编译器自动将类型定义链接到MDK的库中,
C:\Program Files\MDK380a\ARM\INC\ST\ STM32F10x\ stm32f10x_type.h(23): error:   #256: invalid redeclaration of type name "s32" (declared at line 312 of "C:\Program Files\MDK380a\ARM\INC\ST\ STM32F10x\ stm32f10x.h")
这个error是因为在程序中用到了s32这个类型,但是程序中没有包含这个 stm32f10x_type.h
这个时候编译器提示你,这个类型是在上面这个路径的文件中定义的,要你包含这个
头文件。
在编译器路径中加入了CM3文件夹路径,这个问题可以得到解决。
原因是  stm32f10x.h文件中定义了这些类型。

#include " stm32f10x.h" 包含下面的两个头文件。它们都位于CM3文件夹中。
#include "core_cm3.h"
#include "system_ stm32f10x.h"
stm32f10x.h文件的8184行,有这样一句
#ifdef USE_STDPERIPH_DRIVER
    #include " stm32f10x_conf.h"
#endif

其中这个 stm32f10x.conf.h 文件中包含的以下的头文件
#include " stm32f10x_adc.h" 
#include " stm32f10x_bkp.h" 
#include " stm32f10x_can.h" 
#include " stm32f10x_crc.h" 
#include " stm32f10x_dac.h" 
#include " stm32f10x_dbgmcu.h" 
#include " stm32f10x_dma.h"
#include " stm32f10x_exti.h" 
#include " stm32f10x_flash.h" 
#include " stm32f10x_fsmc.h" 
#include " stm32f10x_gpio.h"
#include " stm32f10x_i2c.h" 
#include " stm32f10x_iwdg.h" 
#include " stm32f10x_pwr.h" 
#include " stm32f10x_rcc.h"
#include " stm32f10x_rtc.h" 
#include " stm32f10x_sdio.h"
#include " stm32f10x_spi.h" 
#include " stm32f10x_tim.h" 
#include " stm32f10x_usart.h" 
#include " stm32f10x_wwdg.h" 
#include "misc.h"
在文件包含路径中加入了CM3文件夹,在C文件中加入 stm32f10x.h文件,同时在MDK中
设置USE_STDPERIPH_DRIVER ,这个C文件中的函数就可以调用所有标准库外设。



8:55 2012-09-04

1. stm32启动文件
STM32启动文件简单分析( STM32F10x.s适用范围)定时器, 型号, 名字在<< STM32不完全手册里面>>,
我们所有的例程都采用了一个叫 STM32F10x.s的启动文件,
里面定义了 STM32的堆栈大小以及各种中断的名字及入口函数名称,还有启动相关的汇编代码。
STM32F10x.s是MDK提供的启动代码,从其里面的内容看来,它只定义了3个串口,4个定时器。
实际上 STM32的系列产品有5个串口的型号,也只有有2个串口的型号,定时器也是,做多的有8个定时器。
比如,如果你用的 STM32F103ZET6,而启动文件用的是 STM32F10x.s的话,
你可以正常使用串口1~3的中断,而串口4和5的中断,则无法使用。
又比如,你TIM1~4的中断可以正常使用,而5~8的,则无法使用。
       所以 STM32F10x.s并不能适用所有的 STM32型号,这样,我们就得对不同型号的 STM32,选择不同的启动文件

其中,ld.s适用于小容量 产品;md.s适用于中等容量产品;hd适用于大容量产品;
这里的容量是指FLASH的大小.判断方法如下:
小容量:FLASH≤32K
中容量:64K≤FLASH≤128K
大容量:256K≤FLASH
cl:互联型产品, stm32f105/107系列 
vl:超值型产品, stm32f100系列 
xl:超高密度产品, stm32f101/103系列 超大容量 512-1024K 
ld:低密度产品,FLASH小于64K 
md:中等密度产品,FLASH=64 or 128 
hd:高密度产品,FLASH大于128-512

2、 typedef与结构结合使用
typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
这语句实际上完成两个操作:
  1) 定义一个新的结构类型
 struct tagMyStruct
 {
 int iNum;
 long lLength;
 };
 分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,
    struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,
    这个结构都存在。
 我们可以用struct tagMyStruct varName来定义变量,但要注意,
    使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct
    合在一起才能表示一个结构类型。
 2) typedef为这个新的结构起了一个名字,叫MyStruct。
 typedef struct tagMyStruct MyStruct;
 因此,MyStruct实际上相当于struct tagMyStruct,
    我们可以使用MyStruct varName来定义变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值