【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器

1 初识STM32

1.1 STM32的字面意思

  • 1.ST:意法半导体,是一个公司的名字。
  • 2.M: Microelectronics的缩写,表示微控制器。
  • 3.32:32bit,表示这是一个32bit的微控制器。

1.2 STM32有什么

STM32微控制器上集成了多种硬件设备和外设,这些设备和外设可用于各种不同的应用。以下是一些常见的STM32微控制器上可能集成的设备和外设:

  • 通用输入/输出引脚(GPIO):用于连接和控制外部设备,如开关、LED等。
  • 定时器:用于生成精确的时间延迟、频率和脉冲宽度调制(PWM)信号。
  • 串行通信接口(USART、SPI、I2C等):用于与其他设备进行串行通信,如传感器、外部存储器、显示屏等。
  • 模数转换器(ADC):用于将模拟信号转换为数字信号,通常用于读取传感器数据。
  • 数字模数转换器(DAC):用于将数字信号转换为模拟信号,常用于音频和模拟控制应用。
  • 脉冲宽度调制(PWM)输出:用于生成可调节脉冲宽度的信号,通常用于电机控制、LED调光等。
  • 计数器:用于计数外部事件的发生次数,通常用于测量频率或脉冲数。
  • 比较器:用于比较两个输入信号,判断它们的关系。
  • 看门狗定时器:用于监控系统运行状态,防止系统死锁。
  • 以太网控制器:用于实现以太网通信功能,常用于连接到局域网或互联网。
  • USB控制器:用于实现USB通信功能,支持各种USB设备模式。
  • 加速度计和陀螺仪:用于测量物体的加速度和角速度,常用于惯性测量和导航应用。
  • CAN控制器:用于控制CAN总线通信,适用于汽车和工业领域。
  • 触摸屏控制器:用于检测和处理触摸屏输入。
  • 加密硬件模块:一些型号集成了硬件加密模块,用于保护存储在微控制器内部的数据。
  • 片上存储器:包括闪存和RAM,用于存储程序代码和数据。
  • 时钟和时钟源:用于提供微控制器内部各个模块的时钟信号。

1.3. STM32命名方法

【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第1张图片
以STM32F103VET6举例:

  • 家族:STM32表示32bit的MCU。
  • 产品类型:F表示基础型。
  • 具体特性:基础型。
  • 引脚数目:V表示100pin(引脚),其他常用的为C(48)、R(64)、Z(144)、B(208)、N(216)。
  • FLASH大小:E表示512KB,其他常用的为C(256)、I(2048)。
  • 封装:T表示QFP封装,这是最常用的封装。
  • 温度:6表示温度等级为A(-40~85°)。

1.4 STM32引脚

1.4.1 引脚分类

  • 电源:VBAT、VDD、VSS、VDDA、VSSA、VREF+、VREF-等。
  • 晶振IO:主晶振IO、RTC晶振IO。
  • 下载IO:用于JATG下载的JTMS、JTCK、JTDI、JTDO、NJTRST;用于SWD下载的SWDIO、SWCLK等。
  • BOOT IO:BOOT0、BOOT1,用于设置系统的启动方式。
  • 复位IO:NRST,用于外部复位。
  • GPIO:专用器件接到专用的总线,比如I2C、SPI、SDIO、FSMC、DCMI这些总线的器件需要用到专用的IO。普通的元器件(如蜂鸣器、LED等)接到普通的GPIO口即可。剩下的IO口可根据项目需要引出或不引出。

1.4.2 引脚的功能定义说明

【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第2张图片

  • ①引脚序号:阿拉伯数字表示LQFP封装,英文字母开头表示BGA封装。引脚序号这里列出了8种封装型号,具体使用哪一种根据实际情况来选择。
  • ②引脚名称:指复位状态下的引脚名称。
  • ③引脚类型:S(电源引脚)、I(输入引脚)、I/O(输入/输出引脚)。
  • ④ I/O结构:FT(兼容5V)、TTa(只支持3.3V,且直接到ADC)、B(BOOT引脚)、RST(复位引脚,内部带弱上拉)。
  • ⑤注意事项:对某些IO要注意的事项的特别说明。
  • ⑥复用功能:IO的复用功能,通过GPIOx_AFR寄存器来配置选择。一个IO口可以复用为多个功能,即一脚多用。
  • ⑦额外功能:IO的额外功能,通过直连的外设寄存器配置来选择。

2 什么是寄存器

2.1 寄存器定义

在STM32微控制器中,寄存器是一种特殊的内存单元,用于控制和配置微控制器的各种硬件功能和外设。这些寄存器的值直接影响微控制器的行为和性能。在编程中,开发人员可以通过读取和写入这些寄存器来配置和控制微控制器的各种功能。寄存器定义通常在STM32的设备头文件中,这些头文件由厂家提供,包含了各种寄存器的地址和位字段定义。

2.2 如何辨别芯片的正方向

  • 方法1:找到芯片上的小圆点,在这个小点的基础上逆时针旋转(从1引脚开始,到最后一个引脚)。
  • 方法2:正看丝印,丝印的逆时针开始。

2.3 芯片里面有什么

STM32芯片从宏观上看主要包括内核(Cortex-M3,ARM公司设计)和总线矩阵(FLASH、SRAM、外设,ST公司设计)两部分。

系统框图可以在《STM32参考手册》 - 《2存储器和总线架构 》- 《2.1 系统架构》中查看。
以下为STM32F10XX系统框图。
【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第3张图片

  • ICode 中的 I 表示 Instruction,即指令。我们写好的程序编译之后都是一条条指令,存放在 FLASH中,内核要读取这些指令来执行程序就必须通过 ICode 总线,它几乎每时每刻都需要被使用,它是专门用来取指的。
  • 常量放在FLASH中,变量(全局变量、局部变量)放在SRAM中。数据可以被Dcode(D表示Data)总线和DMA总线访问(Dcode访问的是内核中的数据)。为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
  • System,系统总线主要是访问外设的寄存器,我们通常说的寄存器编程,即读写寄存器都是通过这根系统总线来完成的。
  • DMA总线用来搬数据。

假设我们CPU要读取一个变量(在SRAM中),传输到一个内部的外设:
情况1:如果不使用DMA总线,CPU首先要通过Dcode总线把数据从SRAM读取到CPU的通用寄存器中,CPU再把数据传到内部的外设。
情况2:如果使用DMA总线,CPU只需要发送一个命令,将SRAM中的数据通过DMA总线搬到内部的外设。这样CPU就空闲了,可以进行其他的操作。

2.4 存储器映射

存储器映射:存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射。

存储器映射图可以在《STM32F103xCDE_数据手册-英文》 - 《4-memory mapping》中查看。
【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第4张图片

// 现在我们要让GPIOB端口的16个引脚输出高电平

// 方法1:通过决定地址访问内存单元
* (unsigned int*)(0X40010C0C) = 0XFFFF;

// 方法2:通过寄存器别名方式访问内存单元
#define GPIOB_ODR *(unsigned int*)(0X40010C0C)
GPIOB_ODR = 0XFFFF;
  • 0X40010C0C是GPIOB输出数据寄存器ODR的地址。

1.在《STM32F10X 参考手册》中 找到GPIOB的初始地址0X40010C00(可以在2.3存储器映像中找,也可以在8.2GPIO寄存器描述中找)。
2.寻找ODR的地址偏移量0Ch(8.2.4 端口配置高寄存器(GPIOx_ODR)中找到地址偏移)。

  • (unsigned int*)将(0X40010C0C)强制转换为地址。(编译器并不知道0X40010C0C是一个地址)

2.5 STM32寄存器映射

寄存器映射:给已经分配好地址的有特定功能的内存单元取别名的过程。

  • 总线基地址(可在《STM32F10X 参考手册》- 《2.3存储器映像》中查看)
    【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第5张图片
  • GPIO基地址(可在《STM32F10X 参考手册》- 《2.3存储器映像》中查看)【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第6张图片
  • GPIOB端口的寄存器列表(GPIOB中的其他寄存器地址:GPIOB的基地址+寄存器相对GPIOB基地址的偏移量)【STM32-野火】---学习笔记---一.初识STM32、什么是寄存器_第7张图片

2.6 C语言对寄存器的封装

2.6.1 宏定义

/* 外设基地址 */
#define PERIPH_BASE      ((unsigned int)0x40000000)

/* 总线基地址 */
#define APB1PERIPH_BASE  PERIPH_BASE
#define APB2PERIPH_BASE  (PERIPH_BASE + 0x00010000)
#define AHBPERIPH_BASE  (PERIPH_BASE + 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)

/* 寄存器基地址,以GPIO为例 */
#define GPIOB_CRL        (GPIOB_BASE+0x00)
#define GPIOB_CRH        (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)

2.6.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 = GPIOB_BASE; // 将指针地址设置为宏GPIO_BASE地址
GPIOx->IDR = 0XFFFF;

uint32_t temp = GPIOx->IDR; // 读取GPIOB_IDR寄存器的值到变量temp中

2.6.3 定义GPIO端口基地址指针

/* 使用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)

/* 使用定义好的宏直接访问 */
GPIOB->BSRR = 0XFFFF;

uint32_t temp = GPIOB->IDR;

让PB0输出高/低电平

#define PERIPH_BASE      ((unsigned int)0x40000000)
#define APB2PERIPH_BASE  (PERIPH_BASE + 0x00010000)
#define GPIOB_BASE       (APB2PERIPH_BASE + 0x0C00)
#define GPIOB_ODR        *(unsignedint*)(GPIOB_BASE+0x0C)

// PB0输出低电平
GPIOB_ODR &= ~(1<<0); // ~:取反;先 << ,再 ~ ,再 &= 。

// PB0输出高电平
GPIOB_ODR |= (1<<0);

// PB0取反
GPIOB_ODR ^= (1<<0);

你可能感兴趣的:(stm32,学习,笔记)