前言:
stm32单片机的GPIO一共有8种工作模式,4种输出模式,4种输入模式。分别是通用推挽输出,通用开漏输出,复用推挽输出,复用开漏输出;上拉输入,下拉输入,悬空输入,模拟输入。
<输出工作模式>:
GPIO的四种工作模式可以再次分成:
具体如何分析推挽,开漏,复用,通用,需要从stm32IO口的结构来分析:
输出部分的电路可以直接简化成下图:
推挽模式:
当从输出数据寄存器读取到1的时候,P—MOS管导通,N—MOS管截止,IO口输出1;当从输出数据寄存器读取到0的时候,N—MOS管导通,P—MOS管截止,IO口输出0。
开漏模式:
P—MOS管始终截止。当从输出数据寄存器读取到1的时候,P—MOS管截止,N—MOS管截止,IO口成高阻状态;当从输出数据寄存器读取到0的时候,N—MOS管导通,P—MOS管截止,IO口输出0。
通用模式和复用模式:
通用模式:CPU直接向寄存器写入数据。
复用模式:单片机上的其他外设来向寄存器写入数据。
最大输出速度:
四种输出模式的代码配置示例:
下面以 STM32 标准外设库为例,演示如何将 GPIO 配置为推挽输出、开漏输出、复用推挽输出和复用开漏输出四种模式。初始化时先开启 GPIO 所在端口的时钟,再调用 GPIO_Init 函数完成配置。
/* 开启 GPIOA 和 GPIOB 时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; /* 1. 推挽输出:驱动 LED、蜂鸣器等需要强驱动能力的负载 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 2. 开漏输出:I2C 总线、电平转换、多设备共享总线等场景 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出 GPIO_Init(GPIOA, &GPIO_InitStructure); /* 3. 复用推挽输出:USART、SPI、定时器 PWM 等外设输出引脚 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); /* 4. 复用开漏输出:I2C 外设引脚、需要开漏驱动的复用功能 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏输出 GPIO_Init(GPIOA, &GPIO_InitStructure);实际使用时,应根据负载类型和外设需求选择合适的输出模式:驱动 LED、蜂鸣器等普通负载常用推挽输出;I2C 总线或需要电平转换时使用开漏输出并外接上拉电阻;USART、SPI、PWM 等外设信号输出使用复用推挽输出;I2C 外设引脚则使用复用开漏输出。
<输入工作模式>:
输入模式的简化电路图:
输入上拉:
电路中接入上拉电阻,当GPIO口的状态是1的时候输入数据寄存器也是1,GPIO口的状态是0的时候输入数据寄存器也是0,当GPIO口悬空的时候,输入数据寄存器默认值为1。上拉的意思主要是在GPIO口悬空的时候,写入寄存器的默认值是1还是0。
输入下拉:
电路中接入下拉电阻,当GPIO口的状态是1的时候输入数据寄存器也是1,GPIO口的状态是0的时候输入数据寄存器也是0,当GPIO口悬空的时候,输入数据寄存器默认值为0。
输入浮空:
电路中不接入如何电阻,当GPIO口的状态是1的时候输入数据寄存器也是1,GPIO口的状态是0的时候输入数据寄存器也是0,当GPIO口悬空的时候,输入数据寄存器也悬空。
模拟模式:(后续用到补充)
四种输入模式的代码配置示例:
下面以 STM32 标准外设库为例,演示如何将 GPIO 配置为上拉输入、下拉输入、浮空输入和模拟输入四种模式。初始化时先开启 GPIO 所在端口的时钟,再调用 GPIO_Init 函数完成配置。
/* 开启 GPIOA 和 GPIOC 时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; /* 1. 上拉输入:按键检测、读取开关状态等场景,悬空时默认读到高电平 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 2. 下拉输入:读取需要默认低电平的传感器信号,悬空时默认读到低电平 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); /* 3. 浮空输入:外部已接上拉/下拉电阻或由外部电路确定电平的场景 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); /* 4. 模拟输入:ADC 采样、比较器等模拟信号采集场景 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入 GPIO_Init(GPIOA, &GPIO_InitStructure);实际使用时,应根据外部电路和应用需求选择合适的输入模式:按键或开关检测常用上拉输入;需要默认低电平的信号可用下拉输入;外部电路已确定电平或使用开漏输出驱动时选择浮空输入;采集电压、电流等模拟量时必须使用模拟输入模式。
<驱动GPIO口>
步骤:开启时钟—初始化—写入数据或者读取数据。
初始化是选择io口号,工作模式,输出速度。再调用初始化函数。
PA1端口接按键,实现当按键按下的时候PA0口的LED亮;松开的时候LED灭。
代码:
#include "stm32f10x.h" int main() { //开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //初始化PA0 GPIO_InitTypeDef Init_Struct = {0}; Init_Struct.GPIO_Pin = GPIO_Pin_0; Init_Struct.GPIO_Speed = GPIO_Speed_2MHz; Init_Struct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA,&Init_Struct); //初始化PA1选择输入上拉,当按键为按下的时候输入1,按下的时候输入0 Init_Struct.GPIO_Pin = GPIO_Pin_1; Init_Struct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA,&Init_Struct); while(1) { if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_RESET)//按下的时候点亮led { GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); } else //松开的时候led灭 { GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); } } return 0; }