一、GPIO八种不同模式
输入浮空模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
输入上拉模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
输入下拉模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
模拟模式
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
开漏输出模式
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
开漏输出时,P-MOS不工作。若直接连接到该引脚,只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极,要得到高电平状态需要另外连接电源及上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
开漏复用输出模式
推挽输出模式
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
推挽输出模式,是根据这两个 MOS 管的工作方式来命名的。P-MOS 导通,N-MOS 关闭,对外输出高电平;N-MOS 导通,P-MOS 关闭,对外输出低电平。当引脚高低电平切换时,两个管子轮流导通,P 管负责灌电流,N 管负责拉电流。
推挽复用输出模式
以上图片都来着正点原子PPT
二、开漏与推挽
链接:Open-Drain&Push-Pull_Christal_RJ的博客-CSDN博客
开漏(open drain)和开集(open collector)的概念_你来吻的博客-CSDN博客
开漏输出(open drain)与推挽输出(push pull)学习详解及某个踩到的坑分享_qianzilu的博客-CSDN博客
三、寄存器
端口配置低寄存器
每组IO口包含下面七个寄存器:
- GPIOx_CRL :端口配置低寄存器
- GPIOx_CRH:端口配置高寄存器
- GPIOx_IDR:端口输入寄存器
- GPIOx_ODR:端口输出寄存器
- GPIOx_BSRR:端口位设置/清除寄存器
- GPIOx_BRR :端口位清除寄存器
- GPIOx_LCKR:端口配置锁存寄存器
以GPIOx_CRL为例:
CNF0[1:0]、CNF1[1:0]~CNF7[1:0] 这些寄存器决定了是以哪种模式来输入或者输出。如在输入模式下,01即为Port x (x可以是0、1、2~7)浮空输入模式,10即为上拉/下拉输入模式。
MODE0[1:0]、MODE1[1:0]~MODE7[1:0] 决定了是哪种输入/输出模式。如01即为Port x (x可以是0、1、2~7)最大输出速度为10MHz,10即为最大输出速度为2MHz。
上面的引脚只有Port 0~7,实际中我们会遇到Port0~15(如PC13引脚中的13),剩下的一半在GPIOx_CRH寄存器中。
寄存器操作
这篇文章仔细讲了寄存器怎么操作一只LED灯亮的过程。
STM32寄存器的简介、地址查找,与直接操作寄存器_stm32寄存器手册_yummy说电子的博客-CSDN博客
四、点亮一个LED
电亮一个LED需要配置时钟及所对应的GPIO引脚。手上使用的板子是野火的指南者,现在需要将PB5引脚置为低电平就可以点亮LED灯为红色。
配置时钟
时钟控制名字叫做RCC,属于AHB总线。可以看到,RCC的寄存器地址在 0x40021000~0x400213FF。
RCC的基地址是:0x40021000,RCC_APB2ENR的偏移地址是0x18,那么RCC_APB2ENR的实际地址就是0x40021000 + 0x18 = 0x40021018,这个相当于控制RCC_APB2ENR的内存的编号,也相当于指针。
当需要打开GPIOB的时钟时,只需要将第3位写为1就行。
unsigned int *pRCC_APB2ENR = (unsigned int *)0x40021018; //这个对应的是RCC内存地址。
*pRCC_APB2ENR = 0x00000008; //这个是对这个地址写入我们的操作,就是使能GPIOB的时钟,可以写成 *pRCC_APB2ENR = 0x00000001<<3。
偏移地址,意思是实际地址为基地址的基础上再加偏移地址。
复位值,就是指如果没有操作这个寄存器时,寄存器存放的默认值,在RCC_APB2ENR中,复位值为0x00000000,表示所有的时钟都默认关闭。
配置GPIOB5引脚为通用输出
GPIOB挂在APB2上,GPIOB的寄存器地址在 0X40010C00~0x40010FFF。
GPIOB的基地址是:0x40010C00,GPIOx_CRL的偏移地址为0x00,那么GPIOx_CRL的实际地址就是0x40010C00 + 0x00 = 0x40010C00,如果是控制PBB~PB15,就需要用到GPIOx_CRH寄存器,那时的偏移地址就是0x04。
配置GPIOB5的引脚在端口配置低寄存器中,将其配置为通用推挽输出,最大速度为10MHz。
unsigned int *pGPIOB_CRL = (unsigned int *)0x40010c00;
*pGPIOB_CRL = 0x100000; //转为二进制就是 0000 0000 0001 0000 0000 0000 0000 0000,其中第20、21为MODE5[1:0],写成了01,表示最大速度10MHz;22、23为CNF5[1:0],写成了00,表示通用推挽输出模式
3. 点亮LED需要输出低电平
除了配置好GPIOB引脚的功能外,那就需要对引脚写入高/低电平了,此时需要操作
GPIOx_ODR(x=A..E)寄存器。
该寄存器的基地址也是0x40010C00,GPIOx_ODR偏移地址为0x0C,那么GPIOx_ODR的实际地址就是0x40010C00 + 0x0C = 0x40010C0C。
此时我想将LED点亮,就需要将该位写为0(对应的是低电平),如果想熄灭就将该位写为1(对应的是高电平)。
unsigned int *pGPIOB_ODR = (unsigned int *)0x40010c0c;
*pGPIOB_ODR = 0x20; //亮,对应二进制:10 0000
// *pGPIOB_ODR = 0x00; 灭
//转为二进制就是 1 0000,第五位写为1为高电平,对应灭灯;写为0x00为低电平,对应亮灯。
4. 完整代码
int main(void)
{
unsigned int *pRCC_APB2ENR = (unsigned int *)0x40021018;
unsigned int *pGPIOB_CRL = (unsigned int *)0x40010c00;
unsigned int *pGPIOB_ODR = (unsigned int *)0x40010c0c;
*pRCC_APB2ENR = 0x00000008;
*pGPIOB_CRL = 0x100000;
*pGPIOB_ODR = 0x00;//如果想灭的话就改为0x20
return 0;
}