为什么Stm32初始化外设都需要先打开时钟?
首先,没有打开外部时钟的外设是无法响应的,可以有效避免一些意外造成的程序异常并且有效减少电量的消耗。其次,有了固定的时钟也可以更方便我们控制外设,并配合CPU进行一些编程操作。一下是开启外设的一些方法:
/*
AHB外设总线:
DMA1,DMA2,SRAM,FLITF,CRC,FSMC,SDIO
*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC,DISABLE);
/*
APB1外设总线:
TIM2,TIM3,TIM4,TIM5,TIM6,TIM7,TIM12,TIM13,TIM14,WWDG
SPI2,SPI3,USART2,USART3,UART4,UART5,I2C1,I2C2,USB,CAN1,CAN2,BKP,PWR,DAC,CEC,
*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,DISABLE);
/*
APB2外设总线:
AFIO,GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF,GPIOG,ADC1,ADC2
TIM1,SPI1,TIM8,USART1,ADC3,TIM15,TIM16,TIM17,TIM9,TIM10,TIM11
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
配置完成后,有些外设可能需要一段时间等待时钟稳定下来,一些需要使能。
GPIO的八种模式
GPIO(general propose input/output)指stm32中的通用输入输出端口,可以用于传输、接受数据,连接外设等,功能十分强大。
配置GPIO需要配置端口时钟、模式、数据传输速度、上下拉寄存器等,有时也要配置一些复用功能。
1)输入浮空模式(Input Floating)
引脚设置为输入模式,没有上下拉电阻,适用于有明显输入信号的时候。(没有信号时,引脚电位为可能为任意值)
2)输入上拉模式(Input Pull-up)
引脚设置为输入上拉模式,引脚内部连接上拉电阻,适用于输入信号不确定或需要默认高电平的情况。(与输入浮空模式相对应)
3)输入下拉模式(Input Pull-down)
引脚设置为输入下拉模式,引脚内部连接下拉电阻,适用于输入信号不确定或者默认低电平的情况。
4)输出推挽模式(Output Open-Drain)
引脚可以输出高低电平,一般用于驱动外设。
5)输出开漏模式(Output Open-Drain)
引脚可以输出低电平或高阻态,可以保证CPU一定的安全,以免被高电流破坏,也可以作为多路复用器等,用途十分广泛。
6)复用功能推挽模式(Alternate Function Push-Pull)
引脚被配置为特定的复用功能,如UART、SPI、I2C(这些是不同的串口通信协议UART为异步通信、SPI为同步通信、12C为多主多从通信)等。
7)复用功能开漏模式(Alternate Function Push-Down)
引脚被配置为特定的复用功能,输出为开漏模式。
8)模拟模式(Analog)
此时,输出模拟量,数字量被禁用。
输入浮空模式 | GPIO_Mode_IN_FLOATING |
输入上拉模式 | GPIO_Mode_IPU |
输入下拉模式 | GPIO_Mode_IPD |
输出推挽模式 | GPIO_Mode_Out_PP |
输出开漏模式 | GPIO_Mode_Out_OD |
复用功能推挽模式 | GPIO_Mode_AF_PP |
复用功能开漏模式 | GPIO_Mode_AF_OD |
模拟模式 | GPIO_Mode_AIN |
stm32寄存器映射
#define PERIPH_BASE ((uint32_t)0x40000000) //外设基地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2总线基地址
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) //GPIOA 基地址
typedef struct
{
__IO uint32_t CRL; //端口配置低寄存器,用于配置GPIOA的引脚0至7
__IO uint32_t CRH; //端口配置高寄存器,用于配置GPIOA的引脚8至15
__IO uint32_t IDR; //端口输入数据寄存器,用于读取GPIOA的引脚输入状态
__IO uint32_t ODR; //端口输出数据寄存器,用于设置GPIOA的引脚输出状态
__IO uint32_t BSRR; //端口位设置/清除寄存器,用于原地设置或清除GPIOA的引脚输出状态
__IO uint32_t BRR; //端口位清除寄存器,用于清除GPIOA的引脚输出状态
__IO uint32_t LCKR; //端口配置锁定寄存器,用于锁定GPIOA的配置
} GPIO_TypeDef;
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) //GPIOA结构
这里以GPIOA口作为示例,可以看出除了基地址外,其他地址都是通过基地址+移位计算得到的。