推挽输出的GPIO代码
dd在配置好的模板工程中的`Project`中的`main`函数中写:先进行初始化,自己定义一个初始化函数`void gpio_config()`,在这个函数中初始化时钟,配置GPIO为输出,配置输出为推挽。
在配置好的模板工程中的`Project`中的`main`函数中写:
先进行初始化,自己定义一个初始化函数`void gpio_config()`,在这个函数中初始化时钟,配置GPIO为输出,配置输出为推挽。
图上的前三个为初始化函数,怎么用这几个函数:
1.初始化时钟
选中`rcu_periph_clock_enable`右键选择Go To Definition可以查看这个函数的用法,下图是GD32的外设时钟控制函数及说明文档,涉及到 MCU(微控制器)内部 RCU(Reset and Clock Unit,复位与时钟控制单元)的操作,说明了函数`rcu_periph_clock_enable`的用法
因为我用的是PB2引脚,所以:`rcu_periph_clock_enable(RCU_GPIOB);`
2.配置GPIO为输出
选中`gpio_mode_set`(配置GPIO引脚的工作模式)右键选择Go To Definition可以查看这个函数的用法,下图是该函数的语法:
(1)GPIO端口
没什么好说的,你用哪组端口就写哪组
(2)GPIO引脚模式
输入模式(GPIO_MODE_INPUT):引脚被配置为输入,只能读,不会驱动电平,外部电路决定引脚上的电平,MCU只采样。如果输入引脚没有外部电路拉高或拉低,它的电平会漂浮,读到的值不稳定,所以需要配置上拉或下拉电阻,或者在外部硬件接电阻。用途:读取按键状态、读取外部传感器信号、检测外部设备状态
输出模式(GPIO_MODE_OUTPUT):引脚被配置为推挽输出或者开漏输出,MCU可以主动输出高低电平。推挽输出:输出0或1都直接由MCU驱动,速度快,驱动能力强。开漏输出:MCU只能拉低,不能拉高,拉高需要外部上拉电阻,适合I2C总线、多设备共享信号线。用途:点亮LED、控制继电器、蜂鸣器、给其他芯片发送高低电平控制信号
操作 | 中文术语 | 英文术语 | 输出电平 | 描述 |
推 | 推 / 源出 | Push / Source | 1 (高电平) | 从VCC向外推送电流,将电压推高。 |
挽 | 挽 / 灌入 | Pull / Sink | 0 (低电平) | 将外部电流吸入到GND,将电压拉低。 |
复用功能模式(GPIO_MODE_AF):当MCU的某个引脚除了GPIO功能之外,还可以作为外设接口的引脚使用,就需要配置为复用模式。MCU内部自动把该引脚连接到外设,不再当普通GPIO用,必须在代码中设置AF寄存器选中复用功能编号(AF0~AF15)。用途:UART的TX、RX引脚,SPI的MISO、MOSI、SCK、CS,I2C的SDA、SCL,TIM定时器的PWM输出,CAN总线引脚。
模拟模式(GPIO_MODE_ANALOG):引脚被配置为模拟输入/输出,MCU内部的数字输入电路被关闭,从而引脚电平不会被数字采样电路干扰,功耗更低,输入阻抗更高。用途:ADC模拟输入、DAC模式输出
(3)上拉/下拉配置
这实际上配置了 MCU 内部集成的上拉/下拉电阻,不用外接物理电阻。
悬空(GPIO_PUPD_NONE):MCU内部不上拉也不下拉,引脚完全悬空。
上拉(GPIO_PUPD_PULLUP):在引脚内部通过一个几十kΩ的电阻连接到VCC。用途:按键检测:如果按键一端接地,一端接 MCU 引脚 → 配置上拉,这样按下前电平是高,按下后电平是低。I²C 总线:SDA、SCL 都需要上拉电阻(一般外部电阻,内部上拉不够强)。防止输入悬空:当引脚没有外部驱动电平时,内部上拉保证引脚电平稳定为高。
下拉(GPIO_PUPD_PULLDOWN):在引脚内部通过一个几十kΩ的电阻连接到GND。用途:按键检测:如果按键一端接 VCC,一端接 MCU 引脚 → 配置下拉,这样按下前电平是低,按下后电平是高。防止输入悬空:当引脚没有外部驱动电平时,内部下拉保证引脚电平稳定为低。
场景 | 模式 | 上下拉配置 | 说明 |
---|---|---|---|
读取按键 | 输入模式 | 上拉或下拉 | 防止悬空 |
点亮 LED | 输出模式 | 无(通常不需要) | MCU 主动控制电平 |
控制继电器 | 输出模式 | 无 | 驱动外部器件 |
UART 通信 | 复用模式 | 通常不上下拉 | 串口硬件会驱动电平 |
I²C 总线 | 复用模式(开漏) | 上拉(外部更好) | 总线需要高电平回弹 |
ADC 输入 | 模拟模式 | 无(或外部电路决定) | 防止数字干扰 |
低功耗待机 | 模拟模式 | 无 | 降低输入电流 |
因为我用的PB2引脚,并且是点亮LED,所以:`gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);`
3.配置输出为推挽(输出中有推挽和开漏)
选择`gpio_output_options_set`右键选择Go To Definition可以查看这个函数的用法,下图是该函数的语法:
参数 | 作用 | 可选值 | 说明 |
---|---|---|---|
gpio_periph |
要配置的 GPIO 端口 | GPIOA / GPIOB / … |
指定操作哪个 GPIO 组 |
otype |
输出类型 | GPIO_OTYPE_PP (推挽) GPIO_OTYPE_OD (开漏) |
决定输出驱动方式 |
speed |
输出速度 | GPIO_OSPEED_2MHZ / GPIO_OSPEED_25MHZ / GPIO_OSPEED_50MHZ / GPIO_OSPEED_MAX |
决定上升/下降沿速度 |
pin |
要配置的引脚 | GPIO_PIN_x (x=0..15) 或 GPIO_PIN_ALL |
可以配置单个或多个 |
场景 | 推荐输出类型 | 推荐速度 | 解释 |
---|---|---|---|
点亮 LED | 推挽 | 2MHz / 25MHz | LED 频率低,不需要高速切换 |
按键输入 | 推挽/开漏 + 上拉/下拉 | 2MHz | 通常用开漏 + 外部上拉,防止悬空 |
I²C 总线 | 开漏 | 50MHz | 需要多个器件共享一根线,必须开漏 |
SPI 总线 | 推挽 | 50MHz / MAX | SPI 速度快,需要高驱动能力 |
PWM 输出 | 推挽 | 50MHz / MAX | 驱动能力强,减少延迟 |
至此,完成了三个初始化,代码:
void gpio_config(){
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_2);
}
4.输出高低电平状态
选择`gpio_bit_set`右键选择Go To Definition可以查看这个函数的用法,下图是该函数的语法:
同理按照上面操作也可以查看`gpio_bit_reset`函数的语法。
另外不管是什么操作都要用函数`systick_config();` 用于初始化系统滴答定时器,提供 1ms 时基。如果不写这个函数就无法调用延时函数delay_1ms
MCU 核心时钟频率不同:
-
每个 MCU 的主频不同,比如:
-
GD32 或 STM32F103 → 72 MHz
-
STM32F407 → 168 MHz
-
-
SysTick 计数器每次计数的时间 = 1 / MCU 时钟频
MCU 时钟 = 72 MHz
SysTick 计数一次 = 1 / 72,000,000 s ≈ 13.88 ns
也就是说,SysTick 每计数一次,只经过 13.88 纳秒,不是我们想要的 1ms。
设置计数周期产生 1ms 中断:
-
我们希望 SysTick 每 1ms 触发一次中断
-
那么就需要让计数器 计数 1ms 的时钟数 后才触发一次中断。
重载值 = MCU 时钟频率 / 1000
-
例如:72 MHz MCU
-
重载值 = 72,000,000 / 1000 = 72,000
-
这意味着 SysTick 计数 72,000 次 → 刚好 1ms → 触发中断
-
-
不同 MCU 主频不同 → 重载值也不同
→ 所以要根据SystemCoreClock
动态计算
只要重载值 ≤ 0xFFFFFF,直接 MCU 时钟 / 1000 就能得到 1ms 中断。
主函数代码:
int main(void)
{
systick_config(); // 系统滴答定时器
gpio_config(); // 初始化
while(1) {
gpio_bit_set(GPIOB, GPIO_PIN_2); // PB2 = 高电平
delay_1ms(500); // 500x1=500ms 延时0.5s
gpio_bit_reset(GPIOB, GPIO_PIN_2); // PB2 = 低电平
delay_1ms(500); // 延时0.5s
}
}
5.完整代码:
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
//#include "gd32f450i_eval.h"
//³õʼ»¯GPIO_PB2
void gpio_config(){
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_2);
}
int main(void)
{
systick_config();
gpio_config();
while(1) {
gpio_bit_set(GPIOB, GPIO_PIN_2);
delay_1ms(500);
gpio_bit_reset(GPIOB, GPIO_PIN_2);
delay_1ms(500);
}
}
更多推荐
所有评论(0)