在使用51单片机的时候基本上不需要额外的配置IO,不过在使用特定的IO的时候需要额外的设计外围电路,比如PO口它是没有内置上拉电阻的。因此若想P0输出高电平,它就需要外接上拉电平。(当然这不是说它输入不需要上拉电阻,主要是它作为输入端的时候接收高电平就是共外围电路的上拉电阻)。
操作目标是控制STM32F103C8T6上某个IO口让其置1或者置0.
GPIO是APB2上的外设资源。
APB2是AMBA总线结构中的一种,主要用于低带宽的周边外设之间的连接。
APB2(Advanced Peripheral Bus 2)是ARM公司提出的AMBA总线结构之一,属于一种片上总线结构。APB2主要用于连接低速外设,如I2C、UART、SPI等,这些外设通常具有低带宽和低功耗的需求。
APB2的特点
- 低带宽:APB2主要用于连接低速外设,适合那些不需要高速数据传输的外设。
- 非流水作业:APB2的传输至少需要两个时钟周期,且数据在时钟的上升沿变化,不需要等待周期和回应信号。
- 控制逻辑简单:APB2只有四个控制信号,传输可以采用状态机表示,控制逻辑相对简单。
APB2与其他总线的区别
- 与AHB的区别:AHB是高级高性能总线,主要用于连接高性能模块如CPU、DMA和高速存储器。APB2则是用于连接低速外设。
- 与APB3和APB4的区别:APB3增加了PREADY和PSLVERR信号,用于反馈读和写的状态;APB4增加了PPROT和PSTRB信号,用于提供保护机制和字节选通功能。
在51单片机中如果我们要是某个IO口,比如P1.0端口输出高电平 ,直接赋值即可。但作为输入端就稍微麻烦点需要先赋值P1.0为高电平,再读取P1.0端口的电压。需要两步走。
GPIO作为一种外设资源,在使用它的时候要经过这么几步走,
- 第一步:假设要是能PC13使其输出高电平,经查得知PC13是GPIOC的编号13的IO口(按照顺序因该是第14位IO,是从0开始编的)所以第一步使能能APB2外设总线时钟寄存器
APB2这个外设使能时钟寄存器名字是RCC_APB2ENR,作为32位的单片机它的特殊功能寄存器一般也是32位,点一下APB2上的外设个数,刚好是16个,GPIOC是其中的一位,然后我们看一下手册上的描述(库函数里有21个)
确实是0-15位可控制,后16位是保留的。从他的复位值可知默认的都是0;详细查看可知
可知位4(是第5位)至1,即可使能GPIOC I/O口。即 RCC->APB2EBR = 0x00000010
= 0B 0000 0000 0000 0000 0000 0000 0001 0000
- 第二步:GPIO和51单片机的IO口的不同之处是它的输入输出是分开的需要额外的进行功能选择的,而且对应IO口处于什么结构模式也是需要选择的,
在STM32中控制这些功能,每个IO口需要4位,16个IO就是64位,因此这些IO口的功能选择控制寄存器就分成了两个,端口控制高寄存器(CRH)和端口控制低寄存器(CRL),PC13应是由CRH控制,打开手册得知:
先看一下它的复位值:0x4444 4444 = 0b0100 0100 0100 0100 0100 0100 0100 0100
可以看到0100代表的是浮空输入模式,即STM32上电后的复位状态都是浮空输入模式。
浮空输入(GPIO_Mode_IN_FLOATING)
- 电路结构:无内部上下拉电阻,引脚悬空。
- 特点:
- 电平由外部电路决定。
- 未连接外部电路时,电平可能不稳定(易受干扰)。
因此控制这个IO口我们选择0011 (通用推挽输出模式速度50HZ) 即我们赋值寄存器
GPIOC->CRH = 0x0030 0000;当然这个写法是不太对,其它位我们都赋值为0了,
一般来说需要先把该处的控制位清0;即GPIOC->CRH &= 0x1101 1111;
然后再通过或运算给控制位赋值:即GPIOC->CRH |= 0x0030 0000;(1个16进制数代表4个2进制数)
第三步:选择输出高电平还是低电平,在51机中我们直接就是使用赋值语句进行赋值,如:P1.0 = 0;但是在STM32中是在专用的寄存器里操作的而且分输入和输出,端口输出数据寄存器(GPIOx_ODR) (x=A..E),端口输入数据寄存器(GPIOx_IDR) (x=A..E),目前是需要输出一个低电平,
我们是需要在位13处写0,正常情况下还是需要经过与或运算才是正确的赋值方式,这边就直接赋值其它位都置0:
GPIOC->ODR = 0x0000 0000;//输出低电平
GPIOC->ODR = 0x0000 2000//输出高电平
经过这三步我们就成功使PC13端口输出低电平或者高电平(通用推挽输出方式,50MHZ)
这是使用寄存器的方式进行操作。还有使用库函数的,库函数就不叙述了。
笔者的资料来自B站江协科技。
模式 | 电平特性 | 驱动能力 | 适用场景 | 注意事项 |
---|---|---|---|---|
模拟输入 | 模拟信号 | - | ADC/DAC | 禁用数字功能 |
浮空输入 | 由外部决定 | - | 外部有上下拉的总线 | 避免悬空 |
下拉输入 | 默认低电平 | - | 检测高电平有效信号 | 外部信号需强驱动 |
上拉输入 | 默认高电平 | - | 检测低电平有效信号 | 外部信号需强驱动 |
推挽输出 | 主动驱动高 / 低电平 | 强 | LED、高速信号 | 避免总线冲突 |
开漏输出 | 需外部上拉 | 弱 | I2C、电平转换 | 必须外接上拉电阻 |
复用推挽 | 外设驱动高 / 低电平 | 强 | 定时器 PWM、USART_TX | 需配置外设功能 |
复用开漏 | 外设驱动 + 外部上拉 | 弱 | I2C、CAN 总线 | 需配置外设功能 |
一、输入模式
1. 模拟输入(GPIO_Mode_AIN)
- 电路结构:引脚直连 ADC/DAC 模块,断开内部上下拉电阻。
- 特点:
- 无施密特触发器,直接传递模拟信号。
- 禁止数字信号输入(无法读取高低电平)。
- 应用:
- ADC 电压采集(如传感器信号)。
- DAC 模拟输出(某些引脚支持)。
2. 浮空输入(GPIO_Mode_IN_FLOATING)
- 电路结构:无内部上下拉电阻,引脚悬空。
- 特点:
- 电平由外部电路决定。
- 未连接外部电路时,电平可能不稳定(易受干扰)。
- 应用:
- 需要外部上拉或下拉的场景(如总线通信:I2C 的 SDA/SCL 需外部上拉)。
- 电平由外部设备驱动(如中断信号线)。
3. 下拉输入(GPIO_Mode_IPD)
- 电路结构:内部连接下拉电阻(约 20-50kΩ),默认低电平。
- 特点:
- 引脚悬空时,默认读取低电平。
- 外部高电平可覆盖下拉。
- 应用:
- 避免引脚悬空引发误触发(如按键检测低电平有效)。
4. 上拉输入(GPIO_Mode_IPU)
- 电路结构:内部连接上拉电阻(约 20-50kΩ),默认高电平。
- 特点:
- 引脚悬空时,默认读取高电平。
- 外部低电平可覆盖上拉。
- 应用:
- 避免引脚悬空引发误触发(如按键检测高电平有效)。
二、输出模式
5. 推挽输出(GPIO_Mode_Out_PP)
- 电路结构:P-MOS 和 N-MOS 组合,可主动输出高 / 低电平。
- 特点:
- 高电平:P-MOS 导通,输出 VDD。
- 低电平:N-MOS 导通,输出 GND。
- 驱动能力强,适合高速切换。
- 应用:
- 驱动 LED、继电器等负载。
- 高频信号(如 PWM、SPI 时钟)。
6. 开漏输出(GPIO_Mode_Out_OD)
- 电路结构:仅 N-MOS,需外部上拉电阻输出高电平。
- 特点:
- 高电平:N-MOS 关闭,电平由外部上拉电阻决定。
- 低电平:N-MOS 导通,输出 GND。
- 支持 “线与” 逻辑,但上升沿较慢。
- 应用:
- I2C、SMBUS 等总线通信。
- 电平转换(如 5V 与 3.3V 设备通信)。
7. 复用推挽(GPIO_Mode_AF_PP)
- 电路结构:与普通推挽相同,但输出由外设控制(如 USART、SPI)。
- 特点:
- 外设自动管理电平输出(如定时器 PWM、串口 TX)。
- 高驱动能力,适合高频外设。
- 应用:
- 外设功能引脚(如 TIMx_CHx、USART_TX)。
- 需要硬件自动控制的场景。
8. 复用开漏(GPIO_Mode_AF_OD)
- 电路结构:与普通开漏相同,但输出由外设控制。
- 特点:
- 需外部上拉电阻,支持 “线与” 逻辑。
- 由外设自动管理电平(如 I2C 的 SDA/SCL)。
- 应用:
- I2C、CAN 总线等复用功能。
- 多设备共享总线通信。
这是驱动电路,然后我们调用端口各个功能测试一下他们的区别:
- GPIO_Mode_IPU 使PC13处于输入状态,并且内部设置上拉电阻,LED熄灭,端口电压3.2V
可以设置端口电压为低电平,这时LED会点亮不过亮度不够端口电压为1V。
- GPIO_Mode_IPD 使PC13处于输入状态,并且内部设置下拉电阻,LED依然会点亮不过亮度不够
端口电压1V
- GPIO_Mode_IN_FLOATING LED熄灭端口电压1.3V,推测是是驱动电流不够。
- 当设置IO输出端口的时候如果忘记设置频率将无法正确使IO工作,同理如果忘记设计其它参数IO口也无法正确使能?从测试结果看电压是1.3V即端口状态是之前的浮空输入状态。
使用库函数配置IO口使PC13端口输出低电平
#include "stm32f10x.h" // Device header
int main(void)
{//RCC->APB2ENR = 0x00000010; //APB2 外设时钟使能寄存器//GPIOC->CRH = 0x00300000; //端口配置高寄存器//GPIOC->ODR = 0X00000000; //端口输出数据寄存器RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC,&GPIO_InitStructure);//GPIO_SetBits(GPIOC,GPIO_Pin_13);//端口设置为1GPIO_ResetBits(GPIOC,GPIO_Pin_13); //端口设置为0while(1){}
}
GPIOpin的选择上可以用或运算:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7 ; //GPIO引脚,赋值为0,2,3,4,6,7
库函数与对应的寄存器列举
下面的程序是PB14外部中断的初始化过程
void CountSensor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//AFIO时钟使能/*GPIO初始化 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;//上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 ; //14位GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB,&GPIO_InitStructure); //使能GPIOB_14设置/*AFIO选择引脚*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);///*EXIT初始化*/EXTI_InitTypeDef EXIT_InitStructure;EXIT_InitStructure.EXTI_Line = EXTI_Line14 ;EXIT_InitStructure.EXTI_LineCmd = ENABLE ;EXIT_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择外部中断EXIT_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling ;//下降沿EXTI_Init(&EXIT_InitStructure);//使能外部中断设置/*设置NVIC,中断优先级设置 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2 ;NVIC_Init(&NVIC_InitStructure); //使能NVIC中断设置
配置外部中断PB14、上拉电阻、下降沿触发。中断优先级 抢占2 响应2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB时钟使能
寄存器 APB2ENR bit 3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//AFIO时钟使能
寄存器 APB2ENR bit 0
GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;//上拉GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 ; //14位GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB,&GPIO_InitStructure); //使能GPIOB_14设置
见前文的说明不赘述,其中的上下拉模式要特别说明一下
由手册发现上拉/下来输入模式由同一组控制位控制,怎么区分设置呢?
输入模式下的上拉电阻和下拉电阻寄存器配置 由GPIOx_ODR寄存器控制,为0则为下拉,为1则为上拉。ODR寄存器原先是数据输出寄存器。由上述的两图可以看到当配置为GPIO_Mode_IPU;时ODR14为1,下拉时为0.
/*AFIO选择引脚*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//
AFIO(Alternate Function Input/Output)复用端口选择寄存器配置
该端口,本例采用的是中断配置因此不设置默认。
端口复用功能配置,本案都是使用主功能因此也不配置。


EXTI_InitTypeDef EXIT_InitStructure;EXIT_InitStructure.EXTI_Line = EXTI_Line14 ;EXIT_InitStructure.EXTI_LineCmd = ENABLE ;EXIT_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择外部中断EXIT_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling ;//下降沿EXTI_Init(&EXIT_InitStructure);//使能外部中断设置
配置外部中断寄存器:

EXIT_InitStructure.EXTI_Line = EXTI_Line14 ;EXIT_InitStructure.EXTI_LineCmd = ENABLE ;
EXIT_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择外部中断
默认是全屏蔽的,程序是使能bit14
默认是全屏蔽的即复位值是0x0000 0000. EMR(Event Mask Interrupt)

RTSR(Rising Trigger Selection Register),我们选择的是下降沿因此无需设置即默认。
FTSR(Falling edge Trigger Selection Register) 我们配置是bit14位因此需要设置为1
//EXIT_InitStructure.EXTI_Line = EXTI_Line14 ;//EXIT_InitStructure.EXTI_LineCmd = ENABLE ;EXIT_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling ;//下降沿
软件中断是通过代码或者寄存器操作触发中断,之前代码中是采用GPOI触发是硬件触发中断因此无需设置即默认即可。
PR(Pull Reques),挂起寄存器是操作事件触发的,因此这里也无需设置。至此外部中断EXTI寄存器完毕。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2 ;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2 ;NVIC_Init(&NVIC_InitStructure); //使能NVIC中断设置






一、定义与核心功能
-
事件寄存器
- 功能:用于配置和控制硬件事件的触发条件(如边沿检测)及是否允许事件信号传递到硬件模块(如DMA、ADC等)。
- 典型寄存器:
EMR
(事件屏蔽寄存器):控制事件触发是否有效。RTSR/FTSR
(上升沿/下降沿触发选择寄存器):配置事件的触发条件。
-
中断寄存器
- 功能:管理中断请求的触发、优先级配置及中断屏蔽状态,直接关联CPU的中断响应流程12。
- 典型寄存器:
IMR
(中断屏蔽寄存器):控制中断请求是否被CPU响应。EXTICR
(外部中断配置寄存器):设置中断线对应的GPIO引脚及触发方式。
二、触发机制差异
特性 | 事件寄存器 | 中断寄存器 |
---|---|---|
触发目标 | 直接驱动硬件模块(如DMA、ADC) | 触发CPU中断服务程序(ISR)13 |
响应方式 | 硬件自动处理,无需CPU介入 | 需CPU保存现场并执行ISR12 |
典型应用 | 低延迟数据传输、周期性触发操作 | 异步任务处理、紧急事件响应23 |
三、配置流程对比
-
事件寄存器配置示例
- 通过
RTSR
设置上升沿触发事件。 - 通过
EMR
使能事件触发,信号直接传递至外设模块。
- 通过
-
中断寄存器配置示例
- 通过
EXTICR
绑定GPIO引脚到中断线。 - 通过
IMR
使能中断请求,并设置NVIC优先级。
- 通过
四、关键设计差异
- 事件寄存器:
- 通过硬件链路实现快速响应,适用于实时性要求高且无需复杂逻辑的场景。
- 典型应用:DMA触发、定时器同步23。
- 中断寄存器:
- 依赖CPU介入,适合需要执行复杂逻辑或修改程序流程的场景。
- 典型应用:按键检测、通信协议处理。
五、总结
- 事件寄存器通过硬件链路实现快速响应,中断寄存器依赖CPU处理异步任务。
- 两者常结合使用,例如:事件触发DMA传输,传输完成后通过中断通知CPU23。