STM32学习笔记(一):简介、软件安装及新建工程

STM32学习笔记(一):简介、软件安装及新建工程

本文内容参考自以下内容:

一、初识STM32

1. STM32的基本概念

STM32是指ST公司开发的32位微控制器

2. STM32的分类

STM32 针对于不同的市场需求,推出很多不同的系列。
从内核上面分为Cortex-M0、Cortex-M3、Cortex-M4、Cortex-M7,根据不同内核大概分为主流、高性能、低功耗等类型。

3. STM32命名规则

FLASH闪存是一种非易失性内存,在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘。

4. STM32系统结构

芯片(这里指内核,或者叫 CPU)和外设之间通过各种总线连接,其中驱动单元有 4个,被动单元也有 4 个,为了方便理解,我们都可以把驱动单元理解成是CPU 部分,被动单元都理解成外设。

4.1驱动单元
4.1.1 ICode 总线

指令总线。我们写好的程序编译之后都是一条条指令,存放在 FLASH 中,内核要读取这些指令来执行程序就必须通过 ICode 总线。

4.1.2 DCode 总线

数据总线。我们在写程序的时候,数据有常量和变量两种,常量就是固定不变的,用 C 语言中的 const关键字修饰,是放到内部的 FLASH 当中的,变量是可变的,不管是全局变量还是局部变量都放在内部的SRAM。因为数据可以被 Dcode 总线和 DMA 总线访问,所以为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。

4.1.3 System总线

系统总线。系统总线主要是访问外设的寄存器,我们通常说的寄存器编程,即读写寄存器都是通过这根系统总线来完成的。

4.1.4 DMA总线

DMA 总线也主要是用来传输数据,这个数据可以是在某个外设的数据寄存器,可以在SRAM,可以在内部的 FLASH。因为数据可以被 Dcode 总线和 DMA 总线访问,所以为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。

DMA可以理解为CPU的小助手,DMA的出现就是为了解决批量数据的输入/输出问题。DMA是指外部设备不通过CPU而直接与系统内存交换数据的接口技术。这样数据的传送速度就取决于存储器和外设的工作速度。

4.2 被动单元
4.2.1 FLASH

内部的闪存存储器 , 我们编写好的程序就放在这个地方。内核通过 ICode 总线来取里面的指令。

4.2.2 SRAM

内部的 SRAM,即我们通常说的 RAM,程序的变量,堆栈等的开销都是基于内部的SRAM。内核通过 DCode 总线来访问它。

4.2.3 FSMC

灵活的静态的存储器控制器,通过 FSMC,我们可以扩展内存,如外部的SRAM,NANDFLASH 和 NORFLASH。

(NORFLASH的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是其很低的写入和擦除速度大大影响了它的性能。NANDFLASH存储器具有容量较大,改写速度快等优点,适用于大量数据的存储,因而在业界得到了越来越广泛的应用,如嵌入式产品中包括数码相机、MP3随身听记忆卡、体积小巧的U盘等)

但有一点我们要注意的是,FSMC 只能扩展静态的内存,即名称里面的 S:static,不能是动态的内存,比如 SDRAM 就不能扩展。

(RAM可分为静态存储器SRAM(Static Random Access Memory,SRAM)和动态存储器DRAM(Dynamic Random Access Memory)。SRAM:读写速度快,生产成本高,多用于容量较小的高速缓冲存储器。SRAM中的存储单元相当于一个锁存器,只有0,1两个稳态;DRAM:读写速度较慢,集成度高,生产成本低,多用于容量较大的主存储器。DRAM则是利用电容存储电荷来保存0和1两种状态,因此需要定时对其进行刷新,否则随着时间的推移,电容其中存储的电荷将逐渐消失。

4.2.4 AHB 到 APB 的桥

从 AHB 总线延伸出来的两条 APB2 和 APB1 总线,上面挂载着 STM32 各种各样的特色外设。

5. 引脚定义

在这里插入图片描述
以STM32F103C8T6为例

左上角小黑点代表第一个引脚,然后从1脚起按照逆时针的顺序排列(所有芯片的引脚顺序都是逆时针排列的)。

标红色的是电源相关的引脚,标蓝色的是最小系统相关的引脚,标绿色的是IO口、功能口相关的引脚

I = 输入,O = 输出,S = 电源,FT:容忍5V ,没有FT的只能容忍3.3V的电压

IO口有主功能、默认复用功能和重定义功能。
主功能就是STM32基本IO口,与外设没有连接的,我们可以直接输出或读入高低电平。
默认复用功能是与外设连接的IO口,单片机通过控制IO口控制外设。
比如:STM32的串口1的引脚对应的I/O位PA9、PA10。而PA9、PA10默认的功能都是GPIO,所以说当PA9、PA10引脚作为串口1使用的时候就是端口复用。
端口复用初始化步骤:
1、GPIO端口时钟使能。要使用到端口复用,首先是要使能端口的时钟了;
2、复用的外设时钟使能。比如要将PA9、PA10引脚复用成串口,必须也要使能串口时钟;
3、端口模式配置。在I/O复用位内置外设功能引脚的时候,必须设置GPIO端口的模式。这里拿USART1为例,进行配置,要配置全双工的串口1,TX引脚需要推挽复用输出,RX引脚需要浮空输入或者上拉输入。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 PA.10 浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); 

总而言之,使用复用功能的时候至少要使能2时钟:GPIO时钟使能、复用的外设时钟使能。同时还要初始化GPIO以及复用外设功能(端口模式配置)。
重定义功能: 如果有两个功能同时复用在了一个IO口上,确实需要用到这两个功能时,可以把其中一个复用功能重映射到其他端口上。
例如,从引脚定义图上看出可以将串口1重映射到PB6、PB7引脚上。
端口重映射初始化步骤:
以串口1为例,除了之前使能复用功能的2个时钟之外,还需要使能AFIO功能时钟,然后调用重映射函数:
1、GPIO端口时钟使能。要使用到端口复用,首先是要使能端口的时钟了;
2、复用的外设时钟使能。比如要将PB6、PB7引脚复用成串口,必须也要使能串口时钟;
3、使能AFIO时钟。重映射必须使能AFIO时钟;
4、开启重映射;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);

然后跟端口复用一样配置端口模式,这样,就将串口1的TX和RX引脚映射到PB6、PB7引脚上面了。

引脚1VBAT : 备用电池供电的引脚,在这个引脚可以接一个3V的电池,当系统电源断电时,备用电池可以给内部的RTC时钟和备份寄存器供电

引脚2PC13-TAMPER-RTC: IO口/侵入检测/RTC引脚,RTC引脚可以用来输出RTC校准时钟、RTC闹钟脉冲或秒脉冲

引脚3、4 是IO口或者接32.768KHz的RTC晶振

引脚5、6 接系统的主晶振,一般是8MHz的,然后芯片内有锁相环电路,可以对这个8MHz的频率进行倍频,最终产生72MHz的频率,作为系统的主时钟

引脚7NRST是系统复位引脚,N代表它是低电平复位的

引脚8、9是内部模拟部分的电源,比如ADC、RC震荡器等,VSS接地,VCC接3.3V

引脚10-19是IO口,其中PA0还兼具了WKUP的功能,这个可以用来唤醒处于待机模式的STM32

引脚20是IO口或者BOOT1引脚,BOOT引脚是用来配置启动模式的

引脚21、22是IO口

引脚23、24、35、36、47、48是系统的主电源口

引脚25-33是IO口

引脚34、37-40是IO口或者调试端口,调试端口是用来调试程序和下载程序的,STM32支持SWD和JTAG两种调试方式,SWD需要两根线,JTAG需要5根线,STLINK用的是SWD方式,JLINK用的是JTAG方式

引脚41-43、45、46是IO口

引脚44是BOOT0引脚

6. 启动配置

在这里插入图片描述

启动配置,指定程序开始运行的位置,程序一般在FLASH程序存储器开始执行,也可以让程序在别的地方开始执行以完成特殊功能

启动模式2:系统存储器。这个模式是用来做串口下载用的,系统存储器存的是STM32中的一段BootLoader程序,该程序的作用是接收串口的数据,然后刷新到主闪存中,这样就可以使用串口下载程序了,如果没有STLINK和JLINK或者引脚34、37-40都配置成了IO口就可以用串口下载程序

启动模式2:内置SRAM,进行程序调试

BOOT引脚的值是在上电复位后的一瞬间有效,BOOT1和PB2在同一个引脚上,上电的瞬间是BOOT1功能,当第四个时钟过后就是就是PB2的功能了

7. 最小系统电路

要想让STM32正常工作,就需要把电源部分和最小系统部分的电路连接好

在这里插入图片描述

二、软件安装

链接:https://pan.baidu.com/s/17RIzmQsR-WWTUbb8WmKlhg 提取码:1234

1. 安装Keil5 MDK

可以更换安装路径,一路next就OK

2. 安装器件支持包

2.1 离线安装

上面的百度网盘链接:Keil5 MDK——支持包

在这里插入图片描述

然后选择需要用到的型号,双击,一路next就好

2.2 在线安装

打开Keil5 MDK

在这里插入图片描述

点击更新按钮,加载器件列表

在这里插入图片描述

假如要用STM32F2系列,选择想要安装的型号,install即可,软件自动安装

3. 软件注册

右键 管理员身份打开 Keil5

在这里插入图片描述

复制CID

在这里插入图片描述

上面的百度网盘链接:Keil5 MDK——keygen——打开破解软件(注意解压keygen时要关闭杀毒软件)

在这里插入图片描述

复制CID,Target选择ARM

在这里插入图片描述

点击Generate生成序列码,复制下来

在这里插入图片描述

返回keil软件,将序列码粘贴到1的位置,点击2

在这里插入图片描述

如下图,表示成功

在这里插入图片描述

4. 安装STLINK/JLINK驱动

首先将STLINK插到电脑上
此电脑右键属性打开设备管理器
显示STLINK在其他设备上,并且带有感叹号,表示没有安装驱动,需要安装

在这里插入图片描述

打开Keil5安装目录,按照下图安装驱动

在这里插入图片描述

完成后的状态

在这里插入图片描述

同样的方法也可以安装JLINK的驱动

在这里插入图片描述

5. 安装USB转串口的驱动

同样将USB转串口的芯片(CH340)插到电脑上,上面的百度网盘链接,双击
在这里插入图片描述
在这里插入图片描述

三、存储器与寄存器基础知识

这一节分析这个封装过程只是想更加清楚理解如何使用 C 来封装寄存器的,实际上ST 公司提供的固件库把 STM32 所有外设都已经封装好了,我们只需要调用即可。后续的开发也是基于固件库的。

1、存储器

程序存储器、数据存储器、寄存器和 I/O 端口排列在同一个顺序的 4 GB 地址空间内。ARM 将这 4GB 的存储器空间平均分成了 8 块区域,每块区域的大小是 512MB,这个容量是非常大的,因此芯片厂商就在每块容量范围内设计各自特色的外设,要注意一点每块区域容量占用越大,芯片成本就越高,所以说我们使用的 STM32 芯片都是只用了其中一部分。ARM 在对这 4GB 容量分块的时候是按照其功能划分,每块都有它特殊的用途。存储器分块图如下图所示。
在这里插入图片描述
在这 8 个 Block 里面,Block0、Block1 和 Block2 这 3 个块是我们最为关心的。因为它包含了 STM32 芯片的内部 Flash、RAM 和片上外设。
(1byte、1KB、4KB,1MB、1GB用16进制表示的范围:
1KB = 1024byte= 2的10次方 byte,转化为16进制为0x400,表示地址的范围是0x00~0x3FF。
1MB = 1024KB = 2的20次方byte,转化为16进制为0x100000。表示的地址范围为0x00000~0xFFFFF。
1GB=2的30次方byte,转化为16进制为0x40000000。表示的地址范围为0x00000~0x3FFFFFFF。)
Block0 :主要用于设计片内的 FLASH,STM32F103 系列芯片内部 FLASH 最大是 512KB。
0x0000 0000-0x0007 FFFF:取决于 BOOT 引脚,为 FLASH、系统存储器、SRAM 的别名。
0x0008 0000-0x07FF FFFF:预留。
0x0800 0000-0x0807 FFFF:片内 FLASH,我们编写的程序就放在这一区域(512KB)。
0x0808 0000-0x1FFF EFFF:预留。
0x1FFF F000-0x1FFF F7FF:系统存储器,里面存放的是 ST 出厂时烧写好的isp 自举程序,用户无法改动。使用串口下载的时候需要用到这部分程序。
0x1FFF F800-0x1FFF F80F:选 项 字 节 ,用 于 配 置 读 写 保 护 、BOR 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。当芯片不小心被锁住之后,我们可以从 RAM 里面启动来修改这部分相应的寄存器位。
0x1FFF F810-0x1FFF FFFF:预留。
Block1:用于设计片内的SRAM
0x2000 0000-0x2000 FFFF:SRAM,容量为 64KB。
0x2001 0000-0x3FFF FFFF:预留。
Block2 :用于设计片内外设,根据外设总线速度的不同,Block2 被划分为 AHB和 APB 两部分,APB 又被分成 APB1 和 APB2 总线。
0x4000 0000-0x4000 77FF:APB1 总线外设。
0x4000 7800-0x4000 FFFF:预留。
0x4001 0000-0x4001 3FFF:APB2 总线外设。
0x4001 4000-0x4001 7FFF:预留。
0x4001 8000-0x4002 33FF:AHB 总线外设。
0x4002 4400-0x5FFF FFFF:预留。
Block3/4/5 中还包含了 FSMC 扩展区域,这 3 个块可用于扩展外部存储器,比如 SRAM,NORFLASH 和 NANDFLASH 等。

2、寄存器

由于 Cortex-M3 内核是 32 位的,所以存储器内部是以四个字节为一个单元,每一个单元对应不同的功能,当我们控制这些单元时也就可以控制外设。
每一个单元还对应一个地址,我们要操作这些单元,也就是通过对应的地址来访问。
把每个单元的功能作为名,给这个内存取一个别名,这个别名就是我们经常说的寄存器。给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射

3、访问 STM32 寄存器内容

寄存器就是一些有特定功能的内存单元,所以要访问 STM32寄存器也就是操作 STM32 的内存单元,根据 C 语言指针的特点,可以使用指针来操作STM32 的内存单元。

3.1 STM32 外设地址映射

相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。APB1 总线的地址最低,因此片上外设就从这这个地址开始,也称外设基地址。
(1)总线基地址
在这里插入图片描述
从上图可以看到 APB1 总线基地址是 0x4000 0000,相对外设基地址的偏移量是 0,所以此总线也是外设 Block2 的基地址。
(2)外设基地址
在这里插入图片描述
(3)外设寄存器地址
GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器为 32bit,占四个字节,这些寄存器都是按顺序依次排列在外设的基地址上。寄存器的位置都以相对该外设基地址的偏移地址来描述。这里我们以 GPIOC 端口为例,来说明 GPIO都有哪些寄存器。
在这里插入图片描述
以 GPIOC_BSRR 寄存器为例:
在这里插入图片描述
A.红色框 4 表示的我们所查找寄存器的名称,寄存器 GPIOx_BSRR 内的 x 表示的是 STM32GPIO 端口,范围是 A-E,也就是说在 GPIOA、GPIOB 等端口中都有这个寄存器。
B.红色框 5 表示的是相对 GPIOx 地址的偏移值,比如现在我们使用的是GPIOC 外设,其基地址是 0x4001 1000,那么本寄存器 GPIOx_BSRR 地址=0x40011000+0x10=0x4001 1010。对于其他的 GPIO 外设也是一个原理。
C.红色框 6 和 7 表示的是寄存器的位表。其中 6 表示寄存器编号,因为一个寄存器是 32bit,所以范围是 0-31。7 表示的是相应位的权限,w:只写,r:只读,rw:可读可写。
D.红色框 8 是寄存器位功能说明。这个也是寄存器说明中最重要的部分,它详细介绍了寄存器每一个位的功能。例如本寄存器中有两种寄存器位,分别为BRy 及 BSy,其中的 y 数值表示的是管脚号,可以是 0-15。如 BR0、BS0 用于控制 GPIOx 的第 0 个引脚。
其中 BRy 引脚的说明是“ 0:不会对相应的 ODRx 位执行任何操作; 1:对相应 ODRx 位进行复位”。这里的“复位”是将该位设置为 0 的意思,而“置位”表示将该位设置为 1;说明中的 ODRx 是另一个寄存器的寄存器位,我们只需要知道 ODRx 位为 1 的时候,对应的引脚 x 输出高电平,为 0 的时候对应的引脚输出低电平即可。
所以,如果对 BR0 写入“ 1”的话,那么 GPIOx 的第 0 个引脚就会输出“低电平”,但是对 BR0 写入“ 0”的话,却不会影响 ODR0 位,所以引脚电平不会改变。要想该引脚输出“高电平”,就需要对“ BS0”位写入“ 1”,寄存器位 BSy 与 BRy 是相反的操作。

3.2 使用 C 语言封装寄存器

(1)总线和外设基地址封装:
根据寄存器的概念,我们可以使用 C 语言中的宏定义对寄存器进行定义。具体代码如下:

//定义外设基地址
#define PERIPH_BASE ((unsigned int)0x40000000) 
//定义 APB2 总线基地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 
//定义 GPIOC 外设基地址
#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
//定义寄存器基地址 这里以 GPIOC 为例
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00) 
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)

我们知道 GPIOC_BSRR 的值是这个寄存器的地址,但是编译器不知道它是地址,而是把它当做立即数,所以我们必须要强制转换为(unsigned int *)指针类型才可以对其操作,然后再在前面加上一个*作取指针操作,表示对该地址内内容进行读写。
我们得到了寄存器具体的地址,那么就可以使用 C 语言指针来操作读写。例如我们需要 GPIOC0 输出一个低电平或者高电平,可以使用下面语句来操作。

//控制 GPIOC 第 0 管脚输出一个低电平
GPIOC_BSRR = (0x01<<(16+0));
//控制 GPIOC 第 0 管脚输出一个高电平
GPIOC_BSRR = (0x01<<0);

(2)寄存器封装:
根据 GPIO 寄存器的特点,我们知道不论 GPIOA 还是 GPIOB 等都拥有一组功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR 等等,它们只是地址不一样。为了更方便地访问寄存器,我们引入 C 语言中的结构体对寄存器进行封装,具体代码如下:

typedef unsigned int uint32_t; /*无符号 32 位变量*/
typedef unsigned short int uint16_t; /*无符号 16 位变量*/
/* GPIO 寄存器列表 */
typedef struct
{
	uint32_t CRL; /*GPIO 端口配置低寄存器 地址偏移: 0x00 */
	uint32_t CRH; /*GPIO 端口配置高寄存器 地址偏移: 0x04 */
	uint32_t IDR; /*GPIO 数据输入寄存器 地址偏移: 0x08 */
	uint32_t ODR; /*GPIO 数据输出寄存器 地址偏移: 0x0C */
	uint32_t BSRR; /*GPIO 位设置/清除寄存器 地址偏移: 0x10 */
	uint32_t BRR; /*GPIO 端口位清除寄存器 地址偏移: 0x14 */
	uint16_t LCKR; /*GPIO 端口配置锁定寄存器 地址偏移: 0x18 */
}GPIO_TypeDef;

假如这个结构体的首地址为0x4001 1000(这也是第一个成员变量 CRL 的地址),那么结构体中第二个成员变量 CRH 的地址即为 0x4001 1000 +0x04 ,加上的这个 0x04 ,正是代表 CRH所占用的 4 个字节地址的偏移量,其它成员变量相对于结构体首地址的偏移,在上述代码右侧注释已给出。
比如我们还是将 GPIOC0 输出低电平,具体代码如下:

GPIO_TypeDef * GPIOx; //定义一个 GPIO_TypeDef 型结构体指针 GPIOx
GPIOx = GPIOC_BASE; //把指针地址设置为宏 GPIOC_BASE 地址
GPIOx->BSRR =(1<<(16+0)); //通过指针访问并修改 GPIOC_BSRR 寄存器

为了操作更简便灵活,我们直接使用宏定义好GPIO_TypeDef 类型的指针,而且指针指向各个 GPIO 端口的首地址,使用时我们直接用该宏访问寄存器即可。具体代码如下:

#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
GPIOC->BSRR = (1<<(16+0));

四、基于库函数新建工程

1. STM32 标准库

上面的百度网盘链接:“STM32F10x_StdPeriph_Lib_V3.5.0\”

在这里插入图片描述

进入 Libraries 文件夹看到,关于内核与外设的库文件分别存放在 CMSIS 和STM32F10x_StdPeriph_Driver 文件夹中。

1.1 CMSIS 文件夹

STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\文件夹展开内容见下图

在这里插入图片描述

1.1.1 内核相关文件

在 CoreSupport 文件夹中有 core_cm3.c 和 core_cm3.h 两个文件。Core_cm3.h 头文件里面实现了内核的寄存器映射,对应外设头文件 stm32f10x.h,区别就是一个针对内核的外设,一个针对片上(内核之外)的外设。

core_cm3.h 头文件中包含了“stdint.h” 这个头文件,主要作用是提供一些类型定义,如下图
在这里插入图片描述

1.1.2 启动文件

启动文件放在 startup/arm 这个文件夹下面,这里面启动文件有很多个,不同型号的单片机用的启动文件不一样,有关每个启动文件的详细说明如下

在这里插入图片描述

1.1.3 Stm32f10x.h

这个头文件实现了片上外设的有寄存器的映射,描述STM32有哪些寄存器和它对应的地址,是一个非常重要的头文件,在内核中与之相对应的头文件是 core_cm3.h。

1.1.4 system_stm32f10x.c

system_stm32f10x.c 文件实现了 STM32 的时钟配置,操作的是片上的 RCC 这个外设。系统在上电之后,首选会执行由汇编编写的启动文件,启动文件中的复位函数中调用的SystemInit函数就在这个文件里面定义。调用完之后,系统的时钟就被初始化成 72M。

1.2 STM32F10x_StdPeriph_Driver 文件夹

在这里插入图片描述

这两个文件夹中,还有一个很特别的 misc.c 文件,这个文件提供了外设对内核中的NVIC(中断向量控制器)的访问函数,在配置中断时,我们必须把这个文件添加到工程中。

1.3 stm32f10x_it.c、 stm32f10x_conf.h 文件

文件目录:STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template

我们在用库建立一个完整的工程时 , 还 需 要 添 加 这 个 目 录 下 的 stm32f10x_it.c 、 stm32f10x_it.h 、 stm32f10x_conf.h 和system_stm32f10x.c 这四个文件。

1.3.1 stm32f10x_it.c

这个文件是专门用来编写中断服务函数的

1.3.2 system_stm32f10x.c

在CMSIS下有介绍

1.3.3 stm32f10x_conf.h

这个文件被包含进 stm32f10x.h 文件。当我们使用固件库编程的时候,如果需要某个外设的驱动库,就需要包含该外设的头文件,用一个头文件 stm32f10x_conf.h 把这些外设的头文件都包含在里面,让这个配置头文件统一管理这些外设的头文件,我们在应用程序中只需要包含这个配置头文件即可,我们又知道这个头文件在stm32f10x.h 的最后被包含,所以最终我们只需要包含 stm32f10x.h这个头文件即可,非常方便。

库各文件关系:

在这里插入图片描述

2. 新建库函数工程模板

因为用库新建工程的步骤较多,我们一般是使用库建立一个空的工程,作为工程模板。以后直接复制一份工程模板,在它之上进行开发。

2.1 新建本地工程文件夹

为了工程目录更加清晰,我们在本地电脑上新建一个“工程模板”文件夹,在它之下再新建7 个文件夹,具体如下:

在这里插入图片描述

名称作用
Doc用来存放程序说明的文件,由写程序的人添加
Hardware控制子程序
Libraries固件库文件
Listings存放编译器编译时产生的C/汇编、链接的列表清单
Objects存放编译产生的调试信息、hex文件等
System延时函数、LCD屏、串口等习惯性的放在这个文件夹
User用 于 存 放用 户 编 写的 main.c、stm32f10x_conf.h、stm32f10x_it.c和stm32f10x_it.h中断函数文件。

文件夹没有固定的要求,根据自己习惯建就好。
在本地新建好文件夹后,把准备好的库文件添加到相应的文件夹下:

Libraries:

在这里插入图片描述
在这里插入图片描述

User:

在这里插入图片描述

2.2 Keil5新建工程

保存在 Project文件夹下,项目名为Project,不同的项目可以通过改所在的文件夹名称加以区分,例如该项目所在的总文件夹的名称为:Template

2.2.1 选择 CPU 型号

以STM32F103C8T6为例,选择STM32F103C8

在这里插入图片描述

2.2.2 在线添加库文件

我们手动添加库文件,这里我们点击关掉。

2.2.3 添加组文件夹

添加三个组文件夹

FWlib:固件库,即本地文件夹Template\Libraries\STM32F10x_StdPeriph_Driver内的内容

CMSIS:本地文件夹Template\Libraries\CMSIS内的内容

User:本地文件夹Template\User内的内容

2.2.4 添加文件

选中文件夹,右键,添加已经存在的文件到文件夹

将FWlib、CMSIS、User对应的本地文件夹中的文件添加进来

在CMSIS中添加启动文件时只能添加一个,以STM32F103C8T6为例,STM32F103C8T6的DFLASH为128k,属于中容量,选择startup_stm32f10x_md.s

在这里插入图片描述

每个芯片对应的启动文件怎么选参考:三、新建工程——1.1.2 启动文件

在User中添加main.c函数

在这里插入图片描述

2.2.5 配置魔术棒选项卡

在这里插入图片描述

(1) Target 中选中微库“ Use MicroLib”,为的是在日后编写串口驱动的时候可以使用printf 函数。

(2)在 Output 选项卡中把输出文件夹定位到我们工程目录下的“Object”文件夹,如果想在编译的过程中生成 hex 文件,那么那 Create HEX File 选项勾上。

(3) 在 Listing 选项卡中把输出文件夹定位到我们工程目录下的“Listing”文件夹。

(4) 在 C/C++选项卡中添加处理宏及编译器编译的时候查找的头文件路径。如果头文件路径添加有误,则编译的时候会报错找不到头文件。

在这里插入图片描述

USE_STDPERIPH_DRIVER 宏:为了让 stm32f10x.h 包含 stm32f10x_conf.h 这个头文件。

“Include Paths ”这里添加的是头文件的路径,如果编译的时候提示说找不到头文件,一般就是这里配置出了问题。你把头文件放到了哪个文件夹,就把该文件夹添加到这里即可。

(5)Debug下拉列表选择对应调试器并在Setting——Flash Download里勾选Reset and Run,则下载完程序会自动运行,不需要手动复位

在这里插入图片描述

  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值