目录
[一、STM32 寄存器概述](#一、STM32 寄存器概述)
[1.GPIO 相关寄存器](#1.GPIO 相关寄存器)
[4.RCC 相关寄存器](#4.RCC 相关寄存器)
在嵌入式系统开发中,STM32 微控制器以其强大的性能和丰富的功能而备受青睐。而理解和掌握 STM32 的寄存器是深入学习和开发 STM32 的关键。本文将详细介绍 STM32 的寄存器,帮助读者更好地理解和应用 STM32。
一、STM32 寄存器概述
寄存器是 CPU 内部用来存放数据的小型存储区域,具有高速存储的特点。在 STM32 中,寄存器可以暂存指令、数据和地址,为微控制器的高效运行提供了关键支持。例如,通过对特定寄存器的操作,可以实现对 GPIO(通用输入输出)端口的配置,控制外设的输入输出状态。在实际的嵌入式开发中,了解和掌握 STM32 寄存器的使用方法至关重要。它不仅可以帮助开发者实现对硬件的精确控制,还能提高程序的性能和可移植性。无论是直接操作寄存器,还是使用高级的库函数,都需要对寄存器的原理有深入的理解。
二、寄存器的定义与作用
寄存器是一种有限存贮容量的高速存贮部件,在 STM32 微控制器中,它作为 CPU 内部的小型存储区域,起着至关重要的作用。寄存器可以暂存指令、数据和地址,就像一个特殊的地址存放数据的地方。例如,存放数据的寄存器可以直接存储某个引脚的高低电平数据,当需要读取这个数据时,就可以直接到这个寄存器所在的地方询问数据是多少。不同的数据会存放在不同的寄存器中,通过地址来区分这些寄存器,就像不同的行李寄存处在不同的店铺号一样。
指令、地址寄存器与数据寄存器类似,里面存放的都是 0 和 1,在特定的规定下,数据寄存器里面存放的 0 和 1 表示数据,指令寄存器里存放的表示指令。可以把寄存器类比为有特殊功能的地方,既然是个地方当然就有地址了,所以,可以把寄存器想象为特殊的地址。比如厨房可以类比为寄存器,负责做饭这个特殊功能;仓库也是个寄存器,负责存东西这个特殊功能。需要某些功能的时候,就要操作某个寄存器。
三、寄存器分类
1.内核寄存器
- 通用目的寄存器:用于存储数据和地址,参与算术逻辑运算等操作。在 STM32 中,通用目的寄存器包括 R0-R15 等。其中 R0-R7 是低组寄存器,所有指令都能访问;R8-R12 是高组寄存器,16 位指令不能访问,32 位指令不受限制。
- 堆栈指针寄存器(R13):每一种异常模式(如中断等)都有其自己独立的 R13,通常指向异常模式所专用的堆栈。不同的模式下都有各自独立的堆栈,用于在程序执行过程中保存临时数据、局部变量等,保证各种模式下程序的状态的完整性。
- 连接寄存器(R14):保存子程序返回地址。当使用 BL 或 BLX 指令进行跳转时,跳转指令自动把返回地址放入 R14 中,子程序通过把 R14 复制到程序计数器 PC 来实现返回。当异常发生时,异常模式的 R14 用来保存异常返回地址。
- 程序计数器(R15):存放正在执行的指令的地址。在读取时,返回的值是当前指令的地址加上一定的偏移量(这与处理器的架构和流水线设计有关);向 PC 中写数据,会引起一次程序的分支。
2.外设寄存器
- 控制寄存器(xxx_CR):用来控制、配置外设的工作方式,例如 GPIO 端口模式寄存器(GPIOx_MODER),可以配置 GPIO 引脚为输入、输出、模拟等不同的工作模式。
- 状态寄存器(xxx_SR):存储了当前外设的工作状态,例如串口的状态寄存器(USART_SR),可以通过读取该寄存器的某些位来判断串口是否发送完成、是否接收到数据等。
- 数据寄存器(xxx_DR):用于存储外设进行输入输出的数据。比如 GPIO 端口的输入数据寄存器(GPIOx_IDR)用于读取 GPIO 引脚的输入状态,输出数据寄存器(GPIOx_ODR)用于设置 GPIO 引脚的输出状态。
- 位操作寄存器:针对某些需要对单个位进行操作的场景,STM32 提供了位操作寄存器。例如 GPIOx_BSRR(设置 / 清除寄存器),可以对 GPIO 引脚的单个位进行置位和复位操作,方便了对特定引脚位的控制,而不必对整个寄存器进行操作。
- 锁定寄存器:用于锁定某些寄存器的配置,防止意外的修改。比如 GPIO 端口配置锁定寄存器(GPIOx_LCKR),可以在配置完成后锁定 GPIO 的配置,避免误操作改变引脚的配置。
四、重要寄存器详解
1.GPIO 相关寄存器
- GPIO 端口模式寄存器(GPIOx_MODER) :
- 功能:用于配置 GPIO 引脚的工作模式,如输入、输出、模拟、复用等模式。
- 位定义:每两位控制一个引脚的模式,比如 00 表示输入模式,01 表示输出模式,10 表示模拟模式,11 表示复用功能模式。
- 举例 :若要将 GPIOA 的引脚 5 配置为输出模式,需要将
GPIOA_MODER
寄存器的第 10、11 位设置为 01。- GPIO 端口输出类型寄存器(GPIOx_OTYPER) :
- 功能:配置 GPIO 引脚的输出类型是推挽输出还是开漏输出。
- 位定义:每一位对应一个引脚,0 表示输出推挽(复位状态),1 表示输出开漏。
- 举例 :将
GPIOA_OTYPER
的第 5 位设置为 1,可将 GPIOA 的引脚 5 配置为开漏输出。- GPIO 端口输出速度寄存器(GPIOx_OSPEEDR) :
- 功能:设定 GPIO 引脚的输出速度,速度越快,功耗越高,但信号传输速度也越快。
- 位定义:每两位控制一个引脚的输出速度,00 表示 2MHz(低速),01 表示 25MHz(中速),10 表示 50MHz(快速),11 表示 30pF 时为 100MHz(高速,15pF 时为 80MHz 输出最大速度)。
- 举例 :若要将 GPIOA 的引脚 3 的输出速度设置为快速,需将
GPIOA_OSPEEDR
寄存器的第 6、7 位设置为 10。- GPIO 端口上拉 / 下拉寄存器(GPIOx_PUPDR) :
- 功能:配置 GPIO 引脚的上拉或下拉状态,用于在输入模式下确保引脚的默认电平状态。
- 位定义:每两位控制一个引脚,00 表示无上拉或下拉(浮空),01 表示上拉,10 表示下拉,11 为保留。
- 举例 :将
GPIOA_PUPDR
的第 4 位设置为 01,可将 GPIOA 的引脚 4 配置为上拉输入。- GPIO 端口输入数据寄存器(GPIOx_IDR) :
- 功能:该寄存器为只读寄存器,用于读取 GPIO 引脚的输入电平状态。
- 位定义:每一位对应一个引脚,读取该位的值为 0 或 1,分别表示对应引脚的低电平或高电平。
- 举例 :读取
GPIOA_IDR
寄存器的值,可以获取 GPIOA 所有引脚的输入电平状态。- GPIO 端口输出数据寄存器(GPIOx_ODR) :
- 功能:可通过软件读写该寄存器来设置 GPIO 引脚的输出电平,写入 0 为低电平,写入 1 为高电平。
- 位定义:每一位对应一个引脚的输出状态。
- 举例 :向
GPIOA_ODR
寄存器的某一位写入 1,可将对应引脚设置为高电平输出。- GPIO 端口置位 / 复位寄存器(GPIOx_BSRR) :
- 功能 :用于对 GPIO 引脚进行置位或复位操作,操作方式简单快速,无需通过修改
GPIOx_ODR
寄存器来实现。- 位定义:寄存器的高 16 位为复位位,低 16 位为置位位。写入 1 到相应的位可对引脚进行操作,写入 0 则无操作。
- 举例 :要将 GPIOA 的引脚 2 置位,可向
GPIOA_BSRR
寄存器的第 2 位(低 16 位中的第 2 位)写入 1;要将引脚 7 复位,可向GPIOA_BSRR
寄存器的第 7 位(高 16 位中的第 7 位)写入 1。- GPIO 端口配置锁定寄存器(GPIOx_LCKR) :
- 功能:用于锁定 GPIO 的配置,防止意外的修改。
- 位定义:第 16 位为锁定键,写入特定的序列可激活锁定功能;第 0 - 15 位为锁定位,用于指定哪些引脚的配置被锁定。
- 举例 :按照锁定键写序列操作
GPIOx_LCKR
寄存器,可锁定 GPIO 引脚的配置。
2.定时器相关寄存器
- 自动装载寄存器(TIMx_ARR) :
- 功能 :决定了定时器的计数周期。当定时器的计数器达到
ARR
的值时,会产生更新事件,可用于触发中断或 DMA 请求等操作。- 工作模式 :分为自动装载寄存器缓冲寄存器和自动装载寄存器影子寄存器。通过
ARPE
位控制缓冲寄存器的数据何时更新到影子寄存器。当ARPE = 0
时,写ARR
时数据直接写入影子寄存器;当ARPE = 1
时,只有更新事件发生时,缓冲寄存器的数据才更新到影子寄存器。- 举例 :若要设置定时器的周期为 1000 个计数单位,可将
TIMx_ARR
的值设置为 999(从 0 开始计数到 999 为 1000 个计数单位)。- 预分频器控制寄存器(TIMx_PSC) :
- 功能:对定时器的时钟源进行分频,以降低定时器的计数频率。
- 工作模式:也分为预分频器缓冲寄存器和预分频器影子寄存器。更新事件发生时,缓冲寄存器的内容更新到影子寄存器中。
- 举例 :如果将
TIMx_PSC
的值设置为 999,且定时器的时钟源频率为 72MHz,那么经过预分频器后,定时器的计数频率为 72MHz / (999 + 1) = 72kHz。- 控制寄存器(TIMx_CR1 等) :
- 功能:包含定时器的各种控制位,如定时器的使能位、计数模式(向上计数、向下计数、中心对齐计数等)选择位、更新中断使能位等。
- 位定义:不同的位具有不同的功能,通过对这些位的设置来控制定时器的工作状态。
- 举例 :设置
TIMx_CR1
寄存器的CEN
位为 1,可使能定时器开始计数。
3.中断相关寄存器
- 中断使能寄存器(NVIC_ISER 等) :
- 功能:用于使能相应的中断。STM32 有多个中断源,每个中断源都有对应的使能位在中断使能寄存器中。
- 位定义 :例如在
NVIC_ISER[0]
寄存器中,每一位对应一个中断号,写入 1 使能该中断,写入 0 禁止该中断。- 举例 :要使能外部中断线 0 的中断,需要将
NVIC_ISER[0]
的第 0 位设置为 1。- 中断优先级寄存器(NVIC_IPR 等) :
- 功能:设置中断的优先级。STM32 支持多个中断优先级,通过对这些寄存器的设置可以确定不同中断的优先级顺序,高优先级的中断可以打断低优先级的中断执行。
- 位定义:每个中断号都有对应的 4 位用于设置优先级,数值越小优先级越高。
- 举例 :将某个中断的优先级设置为较高优先级,可将其在
NVIC_IPR
寄存器中对应的 4 位设置为较小的值。
4.RCC 相关寄存器
- 时钟控制寄存器(RCC_CR) :
- 功能:用于开启或关闭 STM32 的各种时钟源,如高速外部时钟(HSE)、高速内部时钟(HSI)、低速外部时钟(LSE)、低速内部时钟(LSI)等,以及配置时钟的相关参数,如时钟的分频系数等。
- 位定义:不同的位对应不同的时钟源和参数设置,通过对这些位的操作来控制时钟的状态。
- 举例 :要开启 HSE 时钟,需要将
RCC_CR
寄存器的HSEON
位设置为 1。- 时钟配置寄存器(RCC_CFGR) :
- 功能:用于配置系统时钟的来源以及各种分频系数,如 AHB、APB1、APB2 等总线的分频系数,以确定不同外设的时钟频率。
- 位定义:通过设置寄存器中的不同位来选择系统时钟源(如 HSE、HSI 等)以及设置分频系数。
- 举例 :若要将系统时钟设置为 HSE 经过分频后作为系统时钟,需要在
RCC_CFGR
寄存器中进行相应的设置。
五、寄存器操作方法
1.直接操作寄存器
- 通过指针直接访问寄存器地址,进行读写操作。这种方法需要对寄存器地址有准确的了解,并且需要注意数据类型的匹配。
- 例如:
cpp
#define GPIOA_BASE (0x40020000UL)
#define GPIOA_MODER (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
void setup_gpio()
{
GPIOA_MODER |= (1 << 10); // 设置 GPIOA 引脚 5 为输出模式
}
2.使用库函数操作寄存器
- STM32 提供了丰富的库函数,可以方便地对寄存器进行操作。使用库函数可以提高开发效率,并且减少错误的发生。
- 例如:
cpp
#include "stm32f4xx.h"
void setup_gpio()
{
GPIO_InitTypeDef GPIO_InitStruct;
// 使能 GPIOA 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// 配置 GPIOA 引脚 5 为输出模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
六、总结
STM32 的寄存器是控制微控制器功能的关键。通过对寄存器的深入理解和掌握,可以实现对 STM32 的精确控制,提高开发效率和系统性能。在实际开发中,可以根据具体需求选择直接操作寄存器或使用库函数操作寄存器。同时,需要注意寄存器的地址和数据类型的匹配,以及操作的安全性和稳定性。希望本文对读者理解和应用 STM32 的寄存器有所帮助。