STM32
安装下载调试
keil5安装包下载:www.aflasdkasda;lsdaksa;d;alskda;sd;alk
芯片支持包下载:https://www.keil.com/dd2/pack/
1、烧写器方式:
#JTAG
1 3 5 7 9 11 13 15 17 19
VREF NC TDI TMS/SWDIO TCK/SWCLK NC TDO/SWDIO RESET NC NC
NC GND GND GND GND GND GND GND GND GND
2 4 6 8 10 12 14 16 18 20
2、串口方式
ISP(In-System Programming)在系统可编程,指电路板上的空白器件可以编程写入用户代码,而不需要取下器件。ISP通过芯片内部的自举程序(Bootloader,由芯片厂家烧写好,不得更改)来选定一种串行的外设,对芯片内部的FLASH进行编程。常用的ISP方式就是通过串口下载,最主要的优点就是成本低,缺点是只能用于下载程序,不能硬件仿真。普通ISP在下载程序的时候需要手动配置BOOT的启动方式
BOOT0 BOOT1 启动方式
0 x 内部FLASH
1 0 系统存储器
1 1 内部SRAM
注释:Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装在到内存中然后跳转到操作系统所在的空间,启动操作系统运行 [2] 。
对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader
-> RXD PA9
USB -> CH340(USB转串口) <-> 单片机
-> TXD PA10
1、USB转串口模块在开发板上是一个独立的模块
2、只有USART1才具有串口下载的功能
什么是STM32
stm32:
- ST——意法半导体,是一个公司名,即SOC厂商
- M——Microeconomics的缩写,表示
微控制器
,并不是微处理器。 - 32——表示其是一个32bit的也是现今最高的微控制器,处理器现今出现64bit。
注释:STM32 = ARM内核(Cortex-M) + SOC增加各种外设(GPIO、I2C、SPI等)
自带常用的通信接口:
串口USART
:用于跟串口接口的设备通信,比如:USB转串口模块、ESP8266、WIFI、GSP模块、GSM模块、串口屏、指纹识别模块、语音识别模块。- 内部集成电路
I2C
:用于跟I2C接口的设备通信,比如:EEPROM、电容屏、陀螺仪MPU6050、0.96寸OLED模块。 - 串口通信接口
SPI
:用于跟SPI接口的设备通信,比如:串行FLASH、以太网W5500、音频模块VS1052. - SDIO、FSMC、I2S、ADC、GPIO
内核分类:
Cortex-M0 STM32-F0 入门级
STM32-L0 低功耗
Cortex-M3 STM32-F1 基础型,主频72MHZ
STM32-F2 高性能
STM32-L1 低功耗
Cortex-M4 STM32-F3 混合信号
STM32-F4 高性能,主频180MHZ
STM32-L4 低功耗
Cortex-M7 STM32-F7 高性能
命名方法:
基础:STM32F103
引脚数:C:48,R:64,V:100,Z:144,B:208,N:216
FLASH:C:256KB,E:512KB,I:2048KB
封装:T:QFP封装
温度:6:-48°~+85°
如何寻找引脚的功能
参考手册:
- 片上外设的功能说明和寄存器没描述:对片上的每个外设的功能和使用做了详细的说明,包含寄存器的详细描述。编程的时候需要反复查询这个手册。
数据手册:
- 功能概览:主要讲这个芯片有哪些功能
- 引脚说明:详细描述每个引脚的功能
- 内存映射:列举总线的地址和包含哪些外设
- 封装特性:
什么是寄存器
内核(驱动单元)和外设(被动单元)之间通过总线传输数据,其中:
- ICode总线: I表示
Instruction
,即指令。我们写好的程序编译之后都是一条条指令,存放在FLASH中,内核要读取这些指令来执行程序就必须通过ICode总线,它几乎每时每刻都需要被使用,它是专门用来取指的。 - DCode总线: D表示
Data
,及数据,数据又分常量和变量两种,常量用关键字const修饰放到内部的FLASH中,变量不管是全局变量或局部变量都是放在SRAM中。因为数据可以被Dcode总线和DMA总线访问,所以为了避免访问冲突,在取数据的时候需要经过一个总线矩阵来总裁
,来决定哪个总线在取数据。 - DMA总线: 和Dcode作用相同,主要作用是搬数据,它省去了CPU中的通用寄存器作为数据中转,从而CPU只需要向DMA发送一条指令之后就可以处理其它事情。
- System总线: 主要读取
寄存器
,而寄存器就是存在于外设中。
1、什么是存储器映射? |
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程称为存储器映射。
翻阅数据手册如下图示例。

2、什么是寄存器映射? |
给有特定功能的内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
以操作GPIOB为例:
在参考手册中找到GPIO的ODR寄存器,偏移地址为0x0c,在寄存器映像表中也可以清楚的找到GPIOB的起始地址为0x4001,那么GPIOB端口输出寄存器地址就为0x40010C0C。
全部输出高就为:*( unsigned int * )(0x40010C0C) = 0xFFFF;
unsigned int *
: 是强制转换为地址,不然编译器不知道。*
:是做指针操作
之后可以通过寄存器别名方式访问内存单元:
#define GPIOB_ODR (unsigned int*)(0x40010C0C)
* GPIO_ODR = 0xFF;
#define GPIOB_ODR *(unsigned int*)(0x40010C0C)
GPIO_ODR = 0xFF;
由参考手册中的寄存器映射表可以看出:
#总线基地址
名称 基地址 相对外设基地址的偏移
APB1 0x4000 0000 0x0
APB2 0x4001 0000 0x0001 0000
AHB 0x4001 8000 0x0001 8000
#GPIO基地址
名称 基地址 相对APB2总线的地址偏移
GPIOA 0x4001 0800 0x0000 0800
GPIOB 0x4001 0C00 0x0000 0C00
GPIOC 0x4001 1000 0x0000 1000
GPIOD 0x4001 1400 0x0000 1400
GPIOE 0x4001 1800 0x0000 1800
GPIOF 0x4001 1C00 0x0000 1C00
GPIOG 0x4001 2000 0x0000 2000
#GPIO端口寄存器地址
名称 基地址 相对APB2基地址的偏移
GPIOB_CRL 0x4001 0C00 0x00
GPIOB_CRH 0x4001 0C00 0x04
GPIOB_IDR 0x4001 0C00 0x08
GPIOB_ODR 0x4001 0C00 0x0C
GPIOH_BSRR 0x4001 0C00 0x10
GPIOH_BRR 0x4001 0C00 0x14
GPIOH_LCKR 0x4001 0C00 0x18
用C语言封装寄存器 |
1、define封装
/*外设基地址*/
#define PERIPH_BASE ((unsigned int)0x40000000)
/*总线基地址*/
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define AHBPERIPH_BASE ((unsigned int)0x00020000)
/*GPIO外设基地址*/
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
/*寄存器基地址*/
#define GPIOB_CRL (GPIOB_BASE + 0x00)
#define GPIOB_BASE (GPIOB_BASE + 0x04)
#define GPIOB_IDR (GPIOB_BASE + 0x08)
#define GPIOB_ODR (GPIOB_BASE + 0x0C)
#define GPIOB_BSRR (GPIOB_BASE + 0x10)
#define GPIOB_BRR (GPIOB_BASE + 0x14)
#define GPIOB_LCKR (GPIOB_BASE + 0x18)
操作PB0输出:
// PB0输出低电平
GPIOB_ODR &= ~(1<<0);
//PB0输出高电平
GPIOB_ODR |= (1<<0);
2、结构体封装
typedef unsigned int uint32_t; /* 无符号32位变量 */
typedef unsigned short int uint16_t; /* 无符号16位变量 */
/* GPIO寄存器列表 */
typedef struct{
uint32_t CRL; /*GPIO端口配置低寄存器 地址偏移:0x00 */
uint32_t ORH; /*GPIO端口配置高寄存器 地址偏移:0x04 */
uint32_t IDR; /*GPIO数据输入寄存器 地址偏移:0x08 */
uint32_t ODR; /*GPIO数据输出寄存器 地址偏移:0x0C */
uint32_t BSRR; /*GPIO位设置/清除寄存器 地址偏移:0x10 */
uint32_t BRR; /*GPIO端口位清除寄存器 地址偏移:0x14 */
uint32_t LCKR; /*GPIO配置锁定寄存器 地址偏移:0x18 */
}GPIO_TypeDef;
GPIO TypeDef * GPIOx; //定义一个GPIO_TypeDef型结构体指针GPIOx
GPIOx = GPIO_BASE; //把指针地址设置为宏GPIOH_BASE地址
GPIOx->IDR = 0xFFFF;
GPIOx->ODR = 0xFFFF;
uint32_t temp;
temp = GPIOx->IDR; //读取GPIOB_IDR寄存器的值到变量temp中
或者
/* 使用GPIO_TypeDef把地址强制转换成指针 */
#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)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
/*使用定义好的宏直接访问*/
/*访问GPIOB端口的寄存器*/
GPIOB->BSRR = 0xFFFF;
GPIO->CRL = 0xFFFF;
GPIOB->ODR = 0xFFFF;
uint32_t temp;
temp = GPIOB->IDR;