本文是Sandeepin学习《STM32库开发实战指南》所做的笔记,主要方便自己以后上手STM32方便,因此很多东西点到为止,如果想正式学STM32,还是推荐直接买书看,看本笔记难免有知识漏洞。本文适合临时上手用STM32的新手,或者对STM32想做大致了解的朋友。部分资料参考了《STM32自学笔记》及网上诸多文章,这里不一一列举了。顺便说说,我用的板子是STM32F103ZET6,因此文中提到的文件配置及以后笔记中的例程均在此平台下跑通。

1 STM32基础

编程语言:C、C++、Java

嵌入式平台:ARM、MIPS、DSP

协议:USB、TCP/IP、SPI、I2C

操作系统:实时μC/OS、非实时Linux

STM32:Cortex-M3内核,有外设ADC、串口UART、定时器TIM等。

CMSIS标准(Cortex Microcontroller Software Interface Standard),实际是新建了一个软件抽象层。

STM32库编程:Libraries文件夹下是驱动库的源代码及启动文件。

2 主要文件简介

  1. core_cm3.c文件:作用是为采用Cortex-M3核设计SoC的芯片商设计的芯片外设提供一个进入CM3内核的接口。

  2. system_stm32f10x.c文件:该文件的功能是设置系统时钟和总线时钟。我们还要通过CM3核的核内寄存器来对8M的时钟进行倍频、分频,或者使用芯片内部的时钟。所有的外设都与时钟的频率有关。

  3. stm32f10x.h文件:它包含了STM32中寄存器地址和结构体类型定义,在使用到STM32固件库的地方都要包含这个头文件。

  4. 启动文件:Libraries\CMSIS\Core\CM3\startup\arm文件夹下是由汇编语言编写的系统启动文件,不同的文件对应不同的芯片型号。文件名的英文缩写的意义如下: xl:超高密度(容量)产品,stm32f101/103系列。 hd:高密度产品,Flash大于128KB。 启动文件的作用:启动文件是任何处理器在上电复位之后最先运行的一段汇编程序。初始化堆栈指针SP。初始化程序计数器指针PC。设置堆、栈的大小。设置异常向量表的入口地址。配置外部SRAM作为数据存储器(这个由用户配置,一般的开发板没有外部SRAM)。设置C库的分支入口__main。

  5. STM32F10x_StdPeriph_Driver文件夹:Libraries\STM32F10x_StdPeriph_Driver文件夹下有inc(include的缩写)和src(source的缩写)这两个文件夹,这都属于CMSIS的设备外设函数部分。如针对模数转换(ADC)外设,在src文件夹下有一个stm32f10x_adc.c源文件,在inc文件夹下有一个stm32f10x_adc.h头文件,若我们开发的工程中用到了STM32内部的ADC,则至少要把这两个文件包含到工程里。这两个文件夹中还有一个很特别的misc.c文件,这个文件提供了外设对内核中的NVIC(中断向量控制器)的访问函数,在配置中断时,我们必须把这个文件添加到工程中。

  6. stm32f10x_it.c和stm32f10x_conf.h文件:在库目录的Project\STM32F10x_StdPeriph_Template目录下,存放了官方的一个库工程模板,我们在用库建立一个完整的工程时,还需要添加这个目录下的stm32f10x_it.c、stm32f10x_it.h和stm32f10x_conf.h这三个文件。stm32f10x_it. c是专门用来编写中断服务函数的。stm32f10x_conf. h文件被包含进stm32f10x.h文件,是用来配置使用了什么外设的头文件,用这个头文件我们可以很方便地增加或删除上面Driver目录下的外设驱动函数库。

3 MDK入门:

新建工程教程:

MDK这里用的版本是V4.12,在新建工程文件夹中,新建5个文件夹,分别为USER、FWlib、CMSIS、Output、Listing。

USER用来存放工程文件和用户层代码,包括主函数main.c。

FWlib用来存放STM32库里面的inc和src这两个文件夹,这两个文件包含了芯片上的所有驱动,这两个文件夹下的文件我们不需要修改。

CMSIS用来存放库为我们自带的启动文件和一些位于CMSIS层的文件。

Output文件夹用来保存软件编译后输出的文件。

Listing用来保存编译后生成的链接文件。

把库\Libraries\STM32F10x_StdPeriph_Driver文件夹下的inc跟src这两个文件夹复制到FWlib文件夹中。

把库文件夹Project\STM32F10x_StdPeriph_Template下的main.c、stm32f10x_conf.h、stm32f10x_it.h和stm32f10x_it.c复制到USER目录下。

将库文件\Libraries\CMSIS\CM3文件夹下的全部文件复制到CMSIS文件夹中。Startup\arm里面把startup_stm32f10x_hd.s启动文件添加到我们的工程中。system.stm32f10x.h、system.stm32f10x.c、stm32f10x.h这几个位于CMSIS层的文件也是放到CMSIS文件夹中。

回到我们的工程中,选中Target右键选中Add Group选项新建4个组,分别命名为STARTCODE、USER、FWlib、CMSIS。

在STARTCODE组里面添加startup_stm32f10x_hd.s启动文件。

在USER组里面添加main.c和stm32f10x_it.c这两个文件。

【待补充】

在Define文本框里面添加两个宏定义:USE_STDPERIPH_DRIVER, STM32F10X_HD,

在建立工程时需要注意的是:

1)因为我们用的是ST官方的新版本库,与编译器自带的库会存在不兼容性,所以我们需要修改库的搜索路径。

2)这个工程我们是设置成软件仿真,如果是用开发板加J-LINK调试的话,还需要在开发环境中做修改。

编译按钮说明:

Translate按钮:就是编译当下修改过的文件,即检查一下有没有语法错误,既不链接库文件,也不会生成可执行文件。

Build按钮:就是编译当下修改过的工程,它包含了语法检查、链接动态库文件、生成可执行文件。

Rebuild按钮:即重新编译整个工程,与Build这个按钮实现的功能是一样的,但有所不同的是它是重新编译整个工程的所有文件,耗时巨大。

下载方式:

1.J-LINK下载:MDK工具栏中的Load按钮就可将编译好的程序下载到开发板的Flash。

2.串口下载:1)给开发板供电(DC5V),拔掉J-LINK,插上串口线(注意是两头都是母的交叉线),接的是串口1,串口2是下载不了程序的,再将BOOT0接到VCC。

串口下载软件是mcuisp。

设置波特率为115200。可执行文件(hex文件)都在工程目录下Output这个文件下。

4 流水灯例程分析

想要控制LED灯,当然是通过控制STM32芯片的I/O引脚电平的高低来实现。

在STM32芯片上,I/O引脚可以被软件设置成各种不同的功能,如输入或输出,所以又被称为GPIO(General-Purpose I/O)。

而GPIO引脚又被分为GPIOA、GPIOB、……、GPIOG不同的组,每组端口分为0~15共16个不同的引脚,对于不同型号的芯片,端口的组和引脚的数量不同。

控制LED的步骤就自然整理出来了:

1)GPIO端口引脚多——就要选定需要控制的特定引脚。

2)GPIO功能如此丰富——配置需要的特定功能。

3)控制LED的亮和灭——设置GPIO输出电压的高低。

要控制GPIO端口,就要涉及控制相关的寄存器。

寄存器可以分为以下4类,其功能简要概括如下:

1)配置寄存器:选定GPIO的特定功能,最基本的如选择作为输入还是输出端口。

2)数据寄存器:保存了GPIO的输入电平或将要输出的电平。

3)位控制寄存器:设置某引脚的数据为1或0,控制输出的电平。

4)锁定寄存器:设置某锁定引脚后,就不能修改其配置。

关于寄存器名称如GPIOx_CRL、GPIOx_CRH上的标号x,其取值可以为图中括号内的值(A……E),表示这些寄存器也跟GPIO一样,是分组的。

端口配置高寄存器(GPIOx_CRH):其中x=A~E

CNFy[1:0]位,其中 y=8~15:在输入模式时MODE=00:

00 模拟输入

01 浮空输入模式(复位后的状态)

10 上拉、下拉输入模式

11 保留

MODE>00时:

00 通用推挽输出模式

01 通用开漏输出模式

10 服用功能推挽输出模式

11 服用开漏输出模式

MODEy[1:0]位,其中y=8~15: 00 输入模式(复位后的状态) 01 输出模式,最大10MHz 10 输出模式,最大2MHz 11 输出模式,最大50MHz

举例说明对CRH寄存器的配置:当将GPIOx_CRH寄存器的第28至29位设置为参数“11”,并将第30至31位设置为参数“00”时,则把x端口第15个引脚的模式配置成了“输出的最大速度为50MHz的通用推挽输出模式”,

端口位设置、清除寄存器(GPIOx_BSRR),其中x=A~E:

位数31~16:清除端口x的位,0表示对应位不产生影响。1表示清除对应位为0。

位数15~0:设置端口x的位,0表示对应位不产生影响。1表示设置对应位为1。

同时设置了清除、设置,设置优先。

例如:对x端口的寄存器GPIOx_BSRR的第0位(BS0)进行写1,则x端口的第0引脚被设置为1,输出高电平,若要令第0引脚再输出低电平,则需要向GPIOx_BSRR的第16位(BR0)写1。

地址映射:

Cortex-M3有32根地址线,所以它的寻址空间大小为2^32 bit=4 GB。ARM公司设计时,预先把这4 GB的寻址空间大致地分配好了。它把从0x40000000至0x5FFFFFFF(512 MB)的地址分配给片上外设。

以后我们写代码的时候,如果要修改GPIO的寄存器,就可以用如下的方式来实现。

GPIO_TypeDef*GPIOx;//定义一个GPIO_TypeDef型结构体指针GPIOx

GPIOx=GPIOA;//把指针地址设置为宏GPIOA地址

GPIOx->CRL=0xffffffff;//通过指针访问并修改GPIOA_CRL寄存器

但这只是库开发的皮毛,而且实际上我们并不是这样使用库的,库为我们提供了更简单的开发方式。

5 STM32的时钟系统

STM32芯片为了实现低功耗,设计了一个功能完善但却非常复杂的时钟系统。普通的MCU一般只要配置好GPIO的寄存器就可以使用了,但STM32还有一个步骤,就是开启外设时钟。

从时钟频率来说,又分为高速时钟和低速时钟,高速时钟是提供给芯片主体的主时钟,而低速时钟只是提供给芯片中的RTC(实时时钟)及独立看门狗使用。从芯片角度来说,时钟源分为内部时钟与外部时钟源,内部时钟是由芯片内部RC振荡器产生的,起振较快,所以时钟在芯片刚上电的时候,默认使用内部高速时钟。而外部时钟信号是由外部的晶振输入的,在精度和稳定性上都有很大优势,所以上电之后我们再通过软件配置,转而采用外部时钟信号。

STM32有以下4个时钟源:

1)高速外部时钟(HSE):以外部晶振作为时钟源,晶振频率可取范围为4~16 MHz,我们一般采用8 MHz的晶振。

2)高速内部时钟(HSI):由内部RC振荡器产生,频率为8 MHz,但不稳定。

3)低速外部时钟(LSE):以外部晶振作为时钟源,主要提供给实时时钟模块,所以一般采用32.768 kHz。配套STM32实验板上用的是32.768 kHz、6p负载规格的晶振。

4)低速内部时钟(LSI):由内部RC振荡器产生,也主要提供给实时时钟模块,频率大约为40 kHz。

GPIO外设是挂载在APB2总线上的,APB2的时钟是APB2预分频器的输出,我们就可以得到GPIO外设的时钟也等于HCLK,即72 MHz。

与我们开发密切相关的时钟:

1)SYSCLK:系统时钟,是STM32大部分器件的时钟来源。

2)HCLK:提供给用于 ARM920T,存储器控制器,中断控制器,LCD 控制器,DMA 和 USB 主机模块的 AHB总线的时钟。

未完待续……