当前位置:首页 > stm32学习笔记
Libraries文件夹下是驱动库的源代码及启动文件。
Project 文件夹下是用驱动库写的例子跟一个工程模板。 在使用库开发时,我们需要把libraries目录下的库函数文件添加到工程中,并查阅库帮助文档来了解ST提供的库函数,这个文档说明了每一个库函数的使用方法。
进入Libraries文件夹看到,关于内核与外设的库文件分别存放在CMSIS和STM32F10x_StdPeriph_Driver文件夹中。
Libraries\\CMSIS\\CM3文件夹下又分为CoreSupport和DeviceSupport文件夹。
system_stm32f10x.c,是由ST公司提供的,遵守CMSIS标准。该文件的功能是设置系统时钟和总线时钟, M3比51单片机复杂得多,并不是说我们外部给一个8M的晶振,M3整个系统就以8M为时钟协调整个处理器的工作。我们还要通过M3核的核内寄存器来对8M的时钟进行倍频,分频,或者使用芯片内部的时钟。所有的外设都与时钟的频率有关,所以这个文件的时钟配置是很关键的。
system_stm32f10x.c在实现系统时钟的时候要用到PLL(锁相环),这就需要操作寄存器,寄存器都是以存储器映射的方式来访问的,所以该文件中包含了stm32f10x.h 这个头文件。
stm32f10x.h 这个文件非常重要,是一个非常底层的文件。 所有处理器厂商都会将对内存的操作封装成一个宏,即我们通常说的寄存器,并且把这些实现封装成一个系统文件,包含在相应的开发环境中。这样,我们在开发自己的应用程序的时候只要将这个文件包含进来就可以了。
各种STM32型号的启动文件
配置时钟频率相应的头文件
设备外设访问层,主要配置时钟频率 定义寄存器的地址及使用的结构体封装
Libraries\\CMSIS\\Core\\CM3\\startup\\arm文件夹下是由汇编编写的系统启动文件,不同的文件对应不同的芯片型号,在使用时要注意。见图 4-3 文件名的英文缩写的意义如下:
cl:互联型产品,stm32f105/107系列 vl:超值型产品,stm32f100系列
xl:超高密度(容量)产品,stm32f101/103系列 ld:低密度产品,FLASH小于64K md:中等密度产品,FLASH=64 or 128 hd:高密度产品,FLASH大于128 启动文件的作用是: 1. 初始化堆栈指针SP;
2. 初始化程序计数器指针PC; 3. 设置堆、栈的大小;
4. 设置异常向量表的入口地址;
5. 配置外部SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部SRAM);
6. 设置C库的分支入口__main(最终用来调用main函数);
7. 在3.5版的启动文件还调用了在system_stm32f10x.c文件中的SystemIni() 函数配置系统时钟,在旧版本的工程中要用户进入main函数自己调用SystemIni() 函数。
Libraries\\STM32F10x_StdPeriph_Driver文件夹下有inc(include的缩写)跟src(source的简写)这两个文件夹,这都属于CMSIS的设备外设函数 部分。
src里面是每个设备外设的驱动程序,这些外设是芯片制造商在Cortex-M3核外加进去的。如针对模数转换(ADC)外设,在src文件夹下有一个stm32f10x_adc.c源文件,在inc文件夹下有一个stm32f10x_adc.h头文件,若我们开发的工程中用到了STM32内部的ADC,则至少要把这两个文件包含到工程里。
在库目录的\\Project\\STM32F10x_StdPeriph_Template目录下,存放了官方的一个库工程模板,我们在用库建立一个完整的工程时,还需要添加这个目录下的stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h这三个文件。
stm32f10x_it.c,是专门用来编写中断服务函数的,在我们修改前,这个文件已经定义了一些系统异常 的接口,其它普通中断服务函数由我们自己添。但是我们怎么知道这些中断服务函数的接口如何写呢?是不是可以自定义呢?答案当然不是的,这些都有可以在汇编启动文件中找到,具体的大家自个看库的启动文件的源码去吧。
stm32f10x_conf.h,这个文件被包含进stm32f10x.h 文件。是用来配置使用了什么外设的头文件,用这个头文件我们可以很方便地增加或删除上面driver目录下的外设驱动函数库。如下面的代码配置表示使用了gpio、rcc、spi、usart的外设库函数,其它的注释掉的部分,表示没有用到。 1. /* Includes
------------------------------------------------------------------*/
2. /* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
3. //#include \4. //#include \ 5. //#include \ 6. //#include \7. //#include \8. //#include \9. //#include \10. //#include \11. //#include \12. //#include \ 13. //#include \ 14. #include \ 15. //#include \
16. //#include \17. //#include \ 18. #include \ 19. //#include \20. //#include \21. #include \ 22. //#include \ 23. #include \ 24. //#include \
25. //#include \CMSIS functions) */
stm32f10x_conf.h这个文件还可配置是否使用“断言”编译选项,在开发时使用断言可由编译器检查库函数传入的参数是否正确,软件编写成功后,去掉“断
言”编译选项可使程序全速运行。可通过定义USE_FULL_ASSERT或取消定义来配置是否使用断言。
其功能简要概括如下:
1. 配置寄存器:选定GPIO的特定功能,最基本的如:选择作为输入还是输出端口。
2. 数据寄存器:保存了GPIO的输入电平 或 将要输出的电平。 3. 位控制寄存器:设置某引脚的数据 为1或0,控制输出的电平。 4. 锁定寄存器:设置某锁定引脚后,就不能修改其配置。
5.4 STM32的时钟系统普通的MCU,一般只要配置好GPIO的寄存器,就可以使用了,但STM32还有一个步骤,就是开启外设时钟。
STM32有以下4个时钟源:
高速外部时钟(HSE):以外部晶振作时钟源,晶振频率可取范围为4~16MHz,我们一般采用8MHz的晶振。
高速内部时钟(HSI): 由内部RC振荡器产生,频率为8MHz,但不稳定。 低速外部时钟(LSE):以外部晶振作时钟源,主要提供给实时时钟模块,所以一般采用32.768KHz。
低速内部时钟(LSI):由内部RC振荡器产生,也主要提供给实时时钟模块,频率大约为40KHz。
当我们使用外设时,一定要记得开启外设的时钟啊,亲。
初始化结构体——GPIO_InitTypeDef类型
关键字typedef定义的新类型。追踪其定义原型如下,位于stm32f10x_gpio.h文件中:
1. typedef struct 2. {
3. uint16_t GPIO_Pin; /*指定将要进行配置的GPIO引脚*/
4. GPIOSpeed_TypeDef GPIO_Speed; /*指定GPIO引脚可输出的最高频率*/ 5. GPIOMode_TypeDef GPIO_Mode; /*指定GPIO引脚将要配置成的工作状态*/ 6. }GPIO_InitTypeDef;
uint16_t类型的GPIO_Pin为我们将要选择配置的引脚,在stm32f10x_gpio.h文件中有如下宏定义:
1. #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */ 2. #define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */ 3. #define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */ 4. #define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
这些宏的值,就是允许我们给结构体成员GPIO_Pin赋的值,如我们给GPIO_Pin赋值为宏GPIO_Pin_0,表示我们选择了GPIO端口的第0个引脚,在后面会通过一个函数把这些宏的值进行处理,设置相应的寄存器,实现我们对GPIO端口的配置
GPIOSpeed_TypeDef 和GPIOMode_TypeDef又是两个库定义的新类型,GPIOSpeed_TypeDef原型如下:
1. typedef enum 2. {
3. GPIO_Speed_10MHz = 1, //枚举常量,值为1,代表输出速率最高为10MHz 4. GPIO_Speed_2MHz, //对不赋值的枚举变量,自动加1,此常量值为2 5. GPIO_Speed_50MHz //常量值为3 6. }GPIOSpeed_TypeDef;
,GPIOMode_TypeDef也是一个枚举类型定义符,原型如下:
1. typedef enum
2. { GPIO_Mode_AIN = 0x0, //模拟输入模式
3. GPIO_Mode_IN_FLOATING = 0x04, //浮空输入模式 4. GPIO_Mode_IPD = 0x28, //下拉输入模式 5. GPIO_Mode_IPU = 0x48, //上拉输入模式 6. GPIO_Mode_Out_OD = 0x14, //开漏输出模式
7. GPIO_Mode_Out_PP = 0x10, //通用推挽输出模式 8. GPIO_Mode_AF_OD = 0x1C, //复用功能开漏输出 9. GPIO_Mode_AF_PP = 0x18 //复用功能推挽输出 10. }GPIOMode_TypeDef;
我们可以总结GPIO_InitTypeDef类型结构体的作用,整个结构体包含
GPIO_Pin 、GPIO_Speed、GPIO_Mode三个成员,我们对这三个成员赋予不同的数值可以对GPIO端口进行不同的配置,而这些可配置的数值,已经由ST的库文件封装成见名知义的枚举常量。这使我们编写代码变得非常简便。
开启外设时钟
开启和关闭外设时钟也有封装好的库函数 RCC_APB2PeriphClockCmd(),可输入参数为ENABLE(使能)和DISABLE(关闭),控制相应的外设时钟状态,调用的时候需要向它输入两个参数,一个参数为将要控制的,挂载在APB2总线上的外设时钟,第二个参数为选择要开启还是关闭该时钟。
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOF, ENABLE)32 就表示将要ENABLE(使能)GPIOC外设时钟。
在这里强调一点,如果我们用到了I/O的引脚复用功能,还要开启其复用功能时
钟。如GPIOC的Pin4还可以作为ADC1的输入引脚,现在我们把它作为ADC1来使用,除了开启GPIOC时钟外,还要开启ADC1的时钟:
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOF, ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE);
控制I/O输出高、低电平
要控制GPIO引脚的电平高低,只要在GPIOx_BSRR寄存器相应的位写入控制参数就可以了。ST库也为我们提供了具有这样功能的函数,可以分别是用
GPIO_SetBits()控制输出高电平,和用GPIO_ResetBits()控制输出低电平。
1、 将char型变量a的第七位(bit6)清0,其它位不变。 1、 a &= ~(1<<6); //括号内1左移6位,得二进制数:0100 0000
2、 //按位取反,得1011 1111 ,所得的数与a作”位与&”运算, 3、 // a的第7位(bit6)被置零,而其它位不变。
2、 同理,将变量a的第七位(bit6)置1,其它位不变的方法如下。 1、 a |= (1<<6); //把第七位(bit6)置1,其它为不变 3、 将变量a的第七位(bit6)取反,其它位不变。
1、 a ^=(1<<6); //把第七位(bit6)取反,其它位不变
共分享92篇相关文档