嘿!我是目录
一、STM32F103系列芯片
1. 简介
STM32F系列属于中低端的32位ARM微控制器,该系列芯片是意法半导体(ST)公司出品,其内核是Cortex-M3[^1]。
该系列芯片按片内Flash的大小可分为三大类:小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。
芯片集成定时器Timer,CAN,ADC,SPI,I2C,USB,UART等多种外设功能。
详解STM32T103C8T6:
STM32代表STM32家族,32位MCU;
F代表产品类型为基础型;
103代表特定功能为STM32基础型;
C代表引脚数为48&49引脚;
8代表内存容量为64KB;
T代表封装为QFP;
6代表温度范围为-40到+85℃。
2. 存储器映射
-
存储器空间
Cortex‐M3 支持4GB 存储空间。整块4G存储器开始地址标为0x0000_0000,结束地址为0xFFFF_FFFF,地址的位数是32位,那么2^32=4,294,967,296。
由于一个基本的存储单元是8bits即1Byte(每个地址对应一个存储单元,这样如果只是访问某一bit就要使用位操作,或者使用位带操作),因此4,294,967,296/1024=4,194,304KB,4,194,304/1024=4096MB,4094/1024=4GB。 -
存储器映射
这4GB的存储空间被划分成8个块,每一块用来与特定功能完成映射。映射关系如图所示。
(某博主的个人理解:这4GB的空间指的是地址空间,每个地址对应一个具体的设备。CPU并不知道每个设备是什么,它所关心的只有地址,获取相应的地址,然后找到地址对应的存储单元或者寄存器,进行读取或者写入数据即可。4GB是它最大支持的地址数目,但是实际可能没有使用那么多。)
- 存储器功能分类
序号 | 用途 | 地址范围 |
---|---|---|
Block0 | Code | 0x0000 0000 ~ 0x1FFF FFFF(512MB) |
Block1 | SRAM | 0x2000 0000 ~ 0x3FFF FFFF(512MB) |
Block2 | 片上外设 | 0x4000 0000 ~ 0x5FFF FFFF(512MB) |
Block3 | FSMC的bank1~bank2 | 0x6000 0000 ~ 0x7FFF FFFF(512MB) |
Block4 | FSMC的bank3~bank4 | 0x8000 0000 ~ 0x9FFF FFFF(512MB) |
Block5 | FSMC寄存器 | 0xA000 0000 ~ 0xCFFF FFFF(512MB) |
Block6 | 没有使用 | 0xD000 0000 ~ 0xDFFF FFFF(512MB) |
Block7 | Cortex-M3内部外设 | 0xE000 0000 ~ 0xFFFF FFFF(512MB) |
在这 8个 Block里面,有 3个块非常重要,也是我们最关心的三个块。Block0用来设计 成内部 FLASH,Block1 用来设计成内部 RAM,Block2 用来设计成片上的外设,下面我们 简单的介绍下这三个 Block 里面的具体区域的功能划分。
- 存储器 Block0 内部区域功能划分
Block0 主要用于设计片内的 FLASH,我们使用的 STM32F103ZET6(霸道)和 STM32F103VET6(指南者)的 FLASH 都是 512KB,属于大容量。要在芯片内部集成更大 的 FLASH 或者 SRAM 都意味着芯片成本的增加,往往片内集成的 FLASH 都不会太大,ST 能在追求性价比的同时做到512KB,实乃良心之举。Block内部区域的功能划分具体见下表。
块 | 用途说明 | 地址范围 |
---|---|---|
Block0 | 预留 | 0x1FFE C008 ~ 0x1FFF FFFF |
Block0 | 选项字节:用于配置读写保护、 BOR 级别、软件/硬件看门狗以及器 件处于待机或停止模式下的复位。当 芯片不小心被锁住之后,我们可以从 RAM 里面启动来修改这部分相应的 寄存器位。 | |
Block0 | 系统存储器:里面存的是ST出厂时 烧 写 好 的 isp 自 举 程 序 ( 即 Bootloader),用户无法改动。串口 下载的时候需要用到这部分程序。 | 0x1FFF F000- 0x1FFF F7FF |
Block0 | 预留 | 0x0808 0000 ~ 0x1FFF EFFF |
Block0 | FLASH:我们的程序就放在这里。 | 0x0800 0000 ~ 0x0807 FFFF (512KB) |
Block0 | 预留 | 0x0008 0000 ~ 0x07FF FFFF |
Block0 | 取决于 BOOT引脚,为 FLASH、系 统存储器、SRAM 的别名。 | 0x0000 0000 ~ 0x0007 FFFF |
存储器Block1内部区域功能划分
Block1 用 于 设 计 片 内 的 SRAM 。 我 们 使 用 的 STM32F103ZET6 ( 霸 道 ) 和 STM32F103VET6(指南者)的 SRAM 都是 64KB,Block 内部区域的功能划分具体下表。
块 | 用途说明 | 地址范围 |
---|---|---|
Block1 | 预留 | 0x2001 0000 ~ 0x3FFF FFFF |
Block1 | SRAM 64KB | 0x2000 0000 ~0x2000 FFFF |
Block2 用于设计片内的外设,根据外设的总线速度不同,Block 被分成了 APB 和 AHB 两部分,其中 APB 又被分为 APB1 和 APB2,具体见下表。
块 | 用途说明 | 地址范围 |
---|---|---|
Block2 | APB1总线外设 | 0x4000 0000 ~ 0x4000 77FF |
Block2 | APB2总线外设 | 0x4001 0000 ~ 0x4001 3FFF |
Block2 | AHB总线外设 | 0x4001 8000 ~ 0x5003 FFFF |
3. 寄存器映射
每个寄存器都是32bit,占用4个Byte即4个存储单元。可以把寄存器看作一个特殊的单元,一个这样的单元占32bit,只要找到这个单元的起始地址就可以对其进行操作。
其映射地址 = 外设总基地址(块基地址)+ 总线相对于外设总基地址的偏移 + 具体外设基地址相对于总线基地址的偏移 + 寄存器相对于具体外设基地址的偏移。
- 寄存器操作
直接地址操作访问
以GPIOB_ODR寄存器为例:
我们找到 GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C(至于这个地址如何找到可以参考–怎么找到某个寄存器的地址?查看数据手册),ODR 寄存器是 32bit,低 16bit 有效,对应着 16 个外部 IO,写 0/1 对应的的 IO 则输出低/高电平。现在我们通过 C 语言指 针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平。
通过绝对地址访问内存单元
// GPIOB 端口全部输出 高电平
*(unsigned int*)(0x4001 0C0C) = 0xFFFF;
0x4001 0C0C在我们看来是 GPIOB端口 ODR的地址,但是在编译器看来,这只是一个 普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把 它转换成指针,即(unsigned int *)0x4001 0C0C,然后再对这个指针进行 * 操作。 刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存 器的方式来操作。
通过寄存器别名方式访问内存单元
// GPIOB 端口全部输出 高电平
#define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)
* GPIOB_ODR = 0xFF;
为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面.
// GPIOB 端口全部输出 高电平
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)
GPIOB_ODR = 0xFF;
其实以上所讲并不是很清晰明了,笔主在这里推荐一个写得很好的博客 STM32寄存器的简介、地址查找,与直接操作寄存器。
二、流水灯
1. 流水灯实验详悉
板子供电有两种方式: 通过U3 USB-micro接口提供5V供电,然后经过板载的LDO芯片转为VCC3V3;通过P2 接口,即SWD下载接口中的VCC3V3给核心板供电。
核心板上有两个LED,其中一个为电源指示灯PWR,另外一个LED与PC13引脚相连,当PC13置高时,LED灭;当PC13置低时,LED亮;
核心板上的跳线是为了选择启动模式使用。我们为了让程序以主闪存存储器作为启动区域,需要将BOOT0置低,BOOT1随意,此种启动模式是最常用的用户FLASH启动,为默认启动模式;
核心板上的按键为RESET复位按键;
P2接口为SWD下载模式对应的引脚接口。
2. Keil新建项目
3. 用C语言和汇编语言分别做流水灯
3.1 C语言
- 新建项目。
- 写入
.c
文件
注:使用的引脚是PA7,PB9,PC15。如果是不一样的请改为自己相应的引脚。
//--------------APB2使能时钟寄存器------------------------
#define RCC_AP2ENR *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRL *((unsigned volatile int*