GD32 开发完全指南
GD32 是兆易创新(GigaDevice)的 ARM Cortex-M 系列单片机,与 STM32 高度兼容但性能更强
一、GD32 与 STM32 对比
1.1 硬件对比
GD32F103 vs STM32F103:
| 特性 | GD32F103 | STM32F103 |
|------------|-----------------|-----------------|
| 内核 | Cortex-M3 | Cortex-M3 |
| 主频 | 108MHz | 72MHz |
| Flash | 64-512KB | 64-512KB |
| RAM | 20-96KB | 20-64KB |
| 价格 | 更便宜 | 较贵 |
| 兼容性 | 引脚兼容 | 原厂 |
| 功耗 | 略高 | 标准 |
GD32 优势:
├── 性价比高(便宜 30-50%)
├── 主频更高(108MHz vs 72MHz)
├── 引脚兼容,可直接替换
└── 国产芯片,供应链稳定
1.2 开发环境
GD32 开发环境:
IDE 选择:
├── Keil MDK(最常用)
├── IAR EWARM
├── GCC + VSCode
└── GD32 All In One(官方 IDE)
固件库:
├── GD32 标准库(类似 STM32 标准库)
├── GD32 HAL 库(类似 STM32 HAL)
└── 兼容 STM32 代码(需少量修改)
下载工具:
├── J-Link(推荐)
├── ST-Link(兼容)
├── DAP-Link
└── 串口 ISP
二、GPIO 操作
2.1 GPIO 基本配置
c
// GD32 GPIO 基本配置 - 标准库
#include "gd32f10x.h"
// LED 接在 PA5
#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOA
// 按键接在 PC13
#define KEY_PIN GPIO_PIN_13
#define KEY_PORT GPIOC
void gpio_config(void) {
// 使能 GPIO 时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOC);
// 配置 LED(推挽输出)
gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED_PIN);
// 配置按键(上拉输入)
gpio_init(KEY_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, KEY_PIN);
}
int main(void) {
gpio_config();
while (1) {
if (RESET == gpio_input_bit_get(KEY_PORT, KEY_PIN)) {
// 按键按下
gpio_bit_set(LED_PORT, LED_PIN); // 点亮 LED
} else {
gpio_bit_reset(LED_PORT, LED_PIN); // 熄灭 LED
}
}
}
2.2 GPIO 常用函数
c
// GD32 GPIO 常用函数
// 配置 GPIO
void gpio_init(uint32_t gpio_periph, uint8_t mode, uint8_t speed, uint32_t pin);
// 模式参数:
// GPIO_MODE_AIN - 模拟输入
// GPIO_MODE_IN_FLOATING - 浮空输入
// GPIO_MODE_IPD - 下拉输入
// GPIO_MODE_IPU - 上拉输入
// GPIO_MODE_OUT_OD - 开漏输出
// GPIO_MODE_OUT_PP - 推挽输出
// GPIO_MODE_AF_OD - 复用开漏
// GPIO_MODE_AF_PP - 复用推挽
// 速度参数:
// GPIO_OSPEED_10MHZ
// GPIO_OSPEED_2MHZ
// GPIO_OSPEED_50MHZ
// 设置引脚(高电平)
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin);
// 复位引脚(低电平)
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin);
// 写入引脚
void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, bit_state bit_value);
// 读取输入
FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin);
// 读取输出
FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin);
// 读取整个端口
uint16_t gpio_input_port_get(uint32_t gpio_periph);
uint16_t gpio_output_port_get(uint32_t gpio_periph);
2.3 GPIO 操作封装
c
// GPIO 操作宏封装
#ifndef __GPIO_H
#define __GPIO_H
#include "gd32f10x.h"
// 引脚定义宏
#define PIN(port, pin) (((port) << 4) | (pin))
#define PIN_PORT(pin) ((pin) >> 4)
#define PIN_PIN(pin) ((pin) & 0x0F)
// 端口映射
#define PORT_A 0x0
#define PORT_B 0x1
#define PORT_C 0x2
#define PORT_D 0x3
#define PORT_E 0x4
#define PORT_F 0x5
#define PORT_G 0x6
// 示例定义
#define LED1_PIN PIN(PORT_A, 5)
#define LED2_PIN PIN(PORT_B, 0)
#define KEY1_PIN PIN(PORT_C, 13)
// GPIO 初始化结构体
typedef struct {
uint8_t port;
uint8_t pin;
uint8_t mode;
uint8_t speed;
} GPIO_Config_t;
// 初始化函数
void GPIO_InitPin(GPIO_Config_t *config) {
uint32_t gpio_periph;
uint32_t gpio_pin = 1 << config->pin;
switch (config->port) {
case PORT_A: gpio_periph = GPIOA; rcu_periph_clock_enable(RCU_GPIOA); break;
case PORT_B: gpio_periph = GPIOB; rcu_periph_clock_enable(RCU_GPIOB); break;
case PORT_C: gpio_periph = GPIOC; rcu_periph_clock_enable(RCU_GPIOC); break;
case PORT_D: gpio_periph = GPIOD; rcu_periph_clock_enable(RCU_GPIOD); break;
case PORT_E: gpio_periph = GPIOE; rcu_periph_clock_enable(RCU_GPIOE); break;
default: return;
}
gpio_init(gpio_periph, config->mode, config->speed, gpio_pin);
}
// 写引脚
void GPIO_WritePin(uint8_t port, uint8_t pin, uint8_t value) {
uint32_t gpio_periph;
uint32_t gpio_pin = 1 << pin;
switch (port) {
case PORT_A: gpio_periph = GPIOA; break;
case PORT_B: gpio_periph = GPIOB; break;
case PORT_C: gpio_periph = GPIOC; break;
default: return;
}
if (value) {
gpio_bit_set(gpio_periph, gpio_pin);
} else {
gpio_bit_reset(gpio_periph, gpio_pin);
}
}
// 读引脚
uint8_t GPIO_ReadPin(uint8_t port, uint8_t pin) {
uint32_t gpio_periph;
uint32_t gpio_pin = 1 << pin;
switch (port) {
case PORT_A: gpio_periph = GPIOA; break;
case PORT_B: gpio_periph = GPIOB; break;
case PORT_C: gpio_periph = GPIOC; break;
default: return 0;
}
return gpio_input_bit_get(gpio_periph, gpio_pin) == SET ? 1 : 0;
}
#endif
三、串口通信
3.1 串口初始化
c
// GD32 USART 初始化 - 标准库
#include "gd32f10x.h"
#include <stdio.h>
// 使用 USART0 (PA9-TX, PA10-RX)
#define USART0_TX_PIN GPIO_PIN_9
#define USART0_RX_PIN GPIO_PIN_10
#define USART0_GPIO_PORT GPIOA
void usart0_init(uint32_t baudrate) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
// 配置 TX(复用推挽输出)
gpio_init(USART0_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, USART0_TX_PIN);
// 配置 RX(浮空输入)
gpio_init(USART0_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, USART0_RX_PIN);
// 复位 USART
usart_deinit(USART0);
// 配置 USART
usart_baudrate_set(USART0, baudrate);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
// 使能 USART
usart_enable(USART0);
}
// 发送一个字节
void usart_send_byte(uint8_t data) {
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
usart_data_transmit(USART0, data);
while (RESET == usart_flag_get(USART0, USART_FLAG_TC));
}
// 发送字符串
void usart_send_string(const char *str) {
while (*str) {
usart_send_byte(*str++);
}
}
// 接收一个字节
uint8_t usart_receive_byte(void) {
while (RESET == usart_flag_get(USART0, USART_FLAG_RBNE));
return (uint8_t)usart_data_receive(USART0);
}
// 重定向 printf
int fputc(int ch, FILE *f) {
usart_send_byte((uint8_t)ch);
return ch;
}
int main(void) {
usart0_init(115200);
printf("GD32 USART Demo\r\n");
while (1) {
if (SET == usart_flag_get(USART0, USART_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART0);
usart_send_byte(data); // 回显
}
}
}
3.2 串口中断
c
// GD32 USART 中断接收
#include "gd32f10x.h"
#define RX_BUFFER_SIZE 256
volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t rx_index = 0;
volatile uint8_t rx_complete = 0;
void usart0_interrupt_init(void) {
// 配置 USART(省略 GPIO 和基本配置...)
// 使能接收中断
usart_interrupt_enable(USART0, USART_INT_RBNE);
// 配置 NVIC
nvic_irq_enable(USART0_IRQn, 0, 0);
}
// USART0 中断服务函数
void USART0_IRQHandler(void) {
if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
uint8_t data = (uint8_t)usart_data_receive(USART0);
if (data == '\n') {
rx_complete = 1;
} else {
if (rx_index < RX_BUFFER_SIZE - 1) {
rx_buffer[rx_index++] = data;
}
}
}
}
int main(void) {
usart0_init(115200);
usart0_interrupt_init();
while (1) {
if (rx_complete) {
rx_complete = 0;
// 处理接收到的数据
rx_buffer[rx_index] = '\0';
printf("Received: %s\r\n", rx_buffer);
rx_index = 0;
}
}
}
3.3 串口 DMA
c
// GD32 USART DMA 发送和接收
#include "gd32f10x.h"
#define TX_BUFFER_SIZE 128
#define RX_BUFFER_SIZE 256
uint8_t tx_buffer[TX_BUFFER_SIZE];
uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint8_t dma_tx_complete = 0;
volatile uint8_t dma_rx_complete = 0;
void dma_config(void) {
// 使能 DMA 时钟
rcu_periph_clock_enable(RCU_DMA0);
// DMA 配置(USART0 TX 使用 DMA0 通道4)
dma_parameter_struct dma_init_struct;
dma_deinit(DMA0, DMA_CH4);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)tx_buffer;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = 0; // 发送时设置
dma_init_struct.periph_addr = USART0_DATA_ADDRESS;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init(DMA0, DMA_CH4, &dma_init_struct);
// 使能 DMA 传输完成中断
dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 0);
// 使能 USART DMA 发送
usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
}
// DMA 发送
void usart_dma_send(uint8_t *data, uint16_t len) {
memcpy(tx_buffer, data, len);
dma_channel_disable(DMA0, DMA_CH4);
dma_memory_address_config(DMA0, DMA_CH4, (uint32_t)tx_buffer);
dma_transfer_number_config(DMA0, DMA_CH4, len);
dma_channel_enable(DMA0, DMA_CH4);
dma_tx_complete = 0;
}
// DMA0 通道4 中断
void DMA0_Channel4_IRQHandler(void) {
if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_FTF);
dma_tx_complete = 1;
}
}
四、定时器
4.1 定时器中断
c
// GD32 定时器中断 - 标准库
#include "gd32f10x.h"
#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOA
volatile uint32_t timer_tick = 0;
void timer2_init(uint32_t period_ms) {
// 使能时钟
rcu_periph_clock_enable(RCU_TIMER2);
// 复位定时器
timer_deinit(TIMER2);
// 定时器基本配置
// 108MHz / 108 = 1MHz (1us)
// 1MHz * 1000 = 1ms
timer_parameter_struct timer_initpara;
timer_initpara.prescaler = 107; // PSC = 108 - 1
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = period_ms * 1000 - 1; // ARR
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2, &timer_initpara);
// 使能更新中断
timer_interrupt_enable(TIMER2, TIMER_INT_UP);
// 配置 NVIC
nvic_irq_enable(TIMER2_IRQn, 1, 0);
// 使能定时器
timer_enable(TIMER2);
}
// 定时器2中断服务函数
void TIMER2_IRQHandler(void) {
if (SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP)) {
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
timer_tick++;
// 每500ms翻转LED
if (timer_tick % 500 == 0) {
gpio_bit_write(LED_PORT, LED_PIN,
(FlagStatus)(1 - gpio_output_bit_get(LED_PORT, LED_PIN)));
}
}
}
int main(void) {
// 使能 GPIO 时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 配置 LED
gpio_init(LED_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LED_PIN);
// 初始化定时器(1ms周期)
timer2_init(1);
while (1) {
// 主循环可以使用 timer_tick 做定时任务
}
}
4.2 PWM 输出
c
// GD32 PWM 输出 - 标准库
#include "gd32f10x.h"
// 使用 TIMER1 CH0 (PA8)
#define PWM_GPIO_PORT GPIOA
#define PWM_GPIO_PIN GPIO_PIN_8
#define PWM_TIMER TIMER1
#define PWM_CHANNEL TIMER_CH_0
void pwm_init(uint32_t frequency, uint8_t duty) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_TIMER1);
// 配置 PWM 引脚(复用推挽输出)
gpio_init(PWM_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, PWM_GPIO_PIN);
// 复位定时器
timer_deinit(PWM_TIMER);
// 定时器基本配置
// 目标频率:frequency Hz
// 时钟:108MHz
// PSC = 107, ARR = 108000000 / 108 / frequency - 1
timer_parameter_struct timer_initpara;
timer_initpara.prescaler = 107; // 1MHz 时钟
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 1000000 / frequency - 1; // ARR
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(PWM_TIMER, &timer_initpara);
// PWM 输出配置
timer_oc_parameter_struct timer_ocinitpara;
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(PWM_TIMER, PWM_CHANNEL, &timer_ocinitpara);
// 配置 PWM 模式0
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL,
(timer_initpara.period + 1) * duty / 100);
timer_channel_output_mode_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_SHADOW_DISABLE);
// 使能定时器
timer_primary_output_config(PWM_TIMER, ENABLE);
timer_enable(PWM_TIMER);
}
// 设置占空比 (0-100)
void pwm_set_duty(uint8_t duty) {
uint32_t arr = TIMER_CAR(PWM_TIMER) + 1;
uint32_t pulse = arr * duty / 100;
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, pulse);
}
int main(void) {
// 初始化 PWM:1kHz 频率,50% 占空比
pwm_init(1000, 50);
while (1) {
// 呼吸灯效果
for (int i = 0; i <= 100; i++) {
pwm_set_duty(i);
delay_1ms(10);
}
for (int i = 100; i >= 0; i--) {
pwm_set_duty(i);
delay_1ms(10);
}
}
}
4.3 舵机控制
c
// GD32 舵机控制(50Hz PWM)
#include "gd32f10x.h"
#define SERVO_GPIO_PORT GPIOA
#define SERVO_GPIO_PIN GPIO_PIN_8
#define SERVO_TIMER TIMER1
#define SERVO_CHANNEL TIMER_CH_0
// 舵机参数
#define SERVO_FREQ 50 // 50Hz
#define SERVO_PERIOD_US 20000 // 20ms
#define SERVO_MIN_PULSE 500 // 0.5ms
#define SERVO_MAX_PULSE 2500 // 2.5ms
void servo_init(void) {
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_TIMER1);
gpio_init(SERVO_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SERVO_GPIO_PIN);
timer_deinit(SERVO_TIMER);
// 1us 分辨率:108MHz / 108 = 1MHz
timer_parameter_struct timer_initpara;
timer_initpara.prescaler = 107;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = SERVO_PERIOD_US - 1; // 20000us = 20ms
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(SERVO_TIMER, &timer_initpara);
timer_oc_parameter_struct timer_ocinitpara;
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(SERVO_TIMER, SERVO_CHANNEL, &timer_ocinitpara);
timer_channel_output_pulse_value_config(SERVO_TIMER, SERVO_CHANNEL, 1500);
timer_channel_output_mode_config(SERVO_TIMER, SERVO_CHANNEL, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(SERVO_TIMER, SERVO_CHANNEL, TIMER_OC_SHADOW_DISABLE);
timer_primary_output_config(SERVO_TIMER, ENABLE);
timer_enable(SERVO_TIMER);
}
// 设置舵机角度 (0-180度)
void servo_set_angle(uint8_t angle) {
if (angle > 180) angle = 180;
// 脉宽:500us - 2500us
uint32_t pulse = SERVO_MIN_PULSE + (SERVO_MAX_PULSE - SERVO_MIN_PULSE) * angle / 180;
timer_channel_output_pulse_value_config(SERVO_TIMER, SERVO_CHANNEL, pulse);
}
int main(void) {
servo_init();
while (1) {
// 0度 -> 90度 -> 180度 -> 90度 -> 0度
servo_set_angle(0);
delay_1ms(1000);
servo_set_angle(90);
delay_1ms(1000);
servo_set_angle(180);
delay_1ms(1000);
servo_set_angle(90);
delay_1ms(1000);
}
}
五、ADC
5.1 单通道 ADC
c
// GD32 ADC 单通道 - 标准库
#include "gd32f10x.h"
// 使用 ADC0 通道0 (PA0)
#define ADC_GPIO_PORT GPIOA
#define ADC_GPIO_PIN GPIO_PIN_0
#define ADC_CHANNEL ADC_CHANNEL_0
#define ADC_PERIPH ADC0
void adc_init(void) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_ADC0);
// 配置 ADC 引脚(模拟输入)
gpio_init(ADC_GPIO_PORT, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, ADC_GPIO_PIN);
// 复位 ADC
adc_deinit();
// ADC 基本配置
adc_mode_config(ADC_MODE_FREE);
adc_special_function_config(ADC_PERIPH, ADC_SCAN_MODE, DISABLE);
adc_special_function_config(ADC_PERIPH, ADC_CONTINUOUS_MODE, DISABLE);
adc_data_alignment_config(ADC_PERIPH, ADC_DATAALIGN_RIGHT);
// 配置通道
adc_channel_length_config(ADC_PERIPH, ADC_REGULAR_CHANNEL, 1);
adc_regular_channel_config(ADC_PERIPH, 0, ADC_CHANNEL, ADC_SAMPLETIME_55POINT5);
// 配置外部触发
adc_external_trigger_source_config(ADC_PERIPH, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
adc_external_trigger_config(ADC_PERIPH, ADC_REGULAR_CHANNEL, ENABLE);
// 使能 ADC
adc_enable(ADC_PERIPH);
delay_1ms(1);
// ADC 校准
adc_calibration_enable(ADC_PERIPH);
}
// 读取 ADC 值
uint16_t adc_read(void) {
// 启动转换
adc_software_trigger_enable(ADC_PERIPH, ADC_REGULAR_CHANNEL);
// 等待转换完成
while (!adc_flag_get(ADC_PERIPH, ADC_FLAG_EOC));
// 读取结果
return adc_regular_data_read(ADC_PERIPH);
}
// 读取电压(mV)
uint32_t adc_read_voltage(void) {
uint16_t adc_value = adc_read();
return (uint32_t)adc_value * 3300 / 4095;
}
int main(void) {
adc_init();
usart0_init(115200);
while (1) {
uint16_t raw = adc_read();
uint32_t voltage = adc_read_voltage();
printf("ADC: %d, Voltage: %dmV\r\n", raw, voltage);
delay_1ms(500);
}
}
5.2 多通道 ADC(DMA)
c
// GD32 ADC 多通道 DMA - 标准库
#include "gd32f10x.h"
#define ADC_CHANNELS 4
#define ADC_PERIPH ADC0
uint16_t adc_values[ADC_CHANNELS];
void adc_dma_init(void) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_ADC0);
rcu_periph_clock_enable(RCU_DMA0);
// 配置 ADC 引脚
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ,
GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
// 配置 DMA
dma_parameter_struct dma_init_struct;
dma_deinit(DMA0, DMA_CH0);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)adc_values;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number = ADC_CHANNELS;
dma_init_struct.periph_addr = (uint32_t)(&ADC_RDATA(ADC_PERIPH));
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init(DMA0, DMA_CH0, &dma_init_struct);
dma_circulation_enable(DMA0, DMA_CH0);
dma_channel_enable(DMA0, DMA_CH0);
// 配置 ADC
adc_deinit();
adc_mode_config(ADC_MODE_FREE);
adc_special_function_config(ADC_PERIPH, ADC_SCAN_MODE, ENABLE);
adc_special_function_config(ADC_PERIPH, ADC_CONTINUOUS_MODE, ENABLE);
adc_data_alignment_config(ADC_PERIPH, ADC_DATAALIGN_RIGHT);
// 配置通道
adc_channel_length_config(ADC_PERIPH, ADC_REGULAR_CHANNEL, ADC_CHANNELS);
adc_regular_channel_config(ADC_PERIPH, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(ADC_PERIPH, 1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(ADC_PERIPH, 2, ADC_CHANNEL_2, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(ADC_PERIPH, 3, ADC_CHANNEL_3, ADC_SAMPLETIME_55POINT5);
// 配置 DMA
adc_dma_mode_enable(ADC_PERIPH);
// 使能 ADC
adc_enable(ADC_PERIPH);
delay_1ms(1);
adc_calibration_enable(ADC_PERIPH);
// 启动连续转换
adc_software_trigger_enable(ADC_PERIPH, ADC_REGULAR_CHANNEL);
}
// 获取指定通道电压
float get_channel_voltage(uint8_t channel) {
if (channel >= ADC_CHANNELS) return 0;
return adc_values[channel] * 3.3f / 4095.0f;
}
int main(void) {
adc_dma_init();
usart0_init(115200);
while (1) {
printf("CH0: %.2fV CH1: %.2fV CH2: %.2fV CH3: %.2fV\r\n",
get_channel_voltage(0),
get_channel_voltage(1),
get_channel_voltage(2),
get_channel_voltage(3));
delay_1ms(500);
}
}
六、I2C
6.1 I2C 主机
c
// GD32 I2C 主机 - 标准库
#include "gd32f10x.h"
// I2C0: PB6-SCL, PB7-SDA
#define I2C_PERIPH I2C0
#define I2C_SCL_PORT GPIOB
#define I2C_SCL_PIN GPIO_PIN_6
#define I2C_SDA_PORT GPIOB
#define I2C_SDA_PIN GPIO_PIN_7
void i2c_init(void) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_I2C0);
// 配置 I2C 引脚(复用开漏输出)
gpio_init(I2C_SCL_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
gpio_init(I2C_SDA_PORT, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
// 复位 I2C
i2c_deinit(I2C_PERIPH);
// 配置 I2C
i2c_clock_config(I2C_PERIPH, 100000, I2C_DTCY_2); // 100kHz
i2c_mode_addr_config(I2C_PERIPH, I2C_I2CMODE_ENABLE,
I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(I2C_PERIPH);
i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
}
// 等待 I2C 空闲
void i2c_wait_idle(void) {
while (i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY));
}
// 发送起始信号
void i2c_start(void) {
i2c_start_on_bus(I2C_PERIPH);
while (!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));
}
// 发送停止信号
void i2c_stop(void) {
i2c_stop_on_bus(I2C_PERIPH);
while (I2C_CTL0(I2C_PERIPH) & I2C_CTL0_STOP);
}
// 发送地址 + 写
void i2c_send_address_w(uint8_t addr) {
i2c_master_addressing(I2C_PERIPH, addr << 1, I2C_MASTER_TRANSMIT);
while (!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
}
// 发送地址 + 读
void i2c_send_address_r(uint8_t addr) {
i2c_master_addressing(I2C_PERIPH, addr << 1, I2C_MASTER_RECEIVE);
while (!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
}
// 发送一个字节
void i2c_write_byte(uint8_t data) {
i2c_data_transmit(I2C_PERIPH, data);
while (!i2c_flag_get(I2C_PERIPH, I2C_FLAG_BTC));
}
// 接收一个字节
uint8_t i2c_read_byte(uint8_t ack) {
if (ack) {
i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
} else {
i2c_ack_config(I2C_PERIPH, I2C_ACK_DISABLE);
}
while (!i2c_flag_get(I2C_PERIPH, I2C_FLAG_RBNE));
return i2c_data_receive(I2C_PERIPH);
}
// 写寄存器
void i2c_write_reg(uint8_t dev_addr, uint8_t reg, uint8_t data) {
i2c_wait_idle();
i2c_start();
i2c_send_address_w(dev_addr);
i2c_write_byte(reg);
i2c_write_byte(data);
i2c_stop();
}
// 读寄存器
uint8_t i2c_read_reg(uint8_t dev_addr, uint8_t reg) {
uint8_t data;
i2c_wait_idle();
i2c_start();
i2c_send_address_w(dev_addr);
i2c_write_byte(reg);
i2c_start();
i2c_send_address_r(dev_addr);
data = i2c_read_byte(0);
i2c_stop();
return data;
}
// 写多字节
void i2c_write_bytes(uint8_t dev_addr, uint8_t reg, uint8_t *data, uint16_t len) {
i2c_wait_idle();
i2c_start();
i2c_send_address_w(dev_addr);
i2c_write_byte(reg);
for (uint16_t i = 0; i < len; i++) {
i2c_write_byte(data[i]);
}
i2c_stop();
}
// 读多字节
void i2c_read_bytes(uint8_t dev_addr, uint8_t reg, uint8_t *data, uint16_t len) {
i2c_wait_idle();
i2c_start();
i2c_send_address_w(dev_addr);
i2c_write_byte(reg);
i2c_start();
i2c_send_address_r(dev_addr);
for (uint16_t i = 0; i < len; i++) {
data[i] = i2c_read_byte(i < len - 1);
}
i2c_stop();
}
七、SPI
7.1 SPI 主机
c
// GD32 SPI 主机 - 标准库
#include "gd32f10x.h"
// SPI0: PA5-SCK, PA6-MISO, PA7-MOSI, PA4-CS
#define SPI_PERIPH SPI0
#define SPI_SCK_PORT GPIOA
#define SPI_SCK_PIN GPIO_PIN_5
#define SPI_MISO_PORT GPIOA
#define SPI_MISO_PIN GPIO_PIN_6
#define SPI_MOSI_PORT GPIOA
#define SPI_MOSI_PIN GPIO_PIN_7
#define SPI_CS_PORT GPIOA
#define SPI_CS_PIN GPIO_PIN_4
void spi_init(void) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SPI0);
// 配置 SPI 引脚
gpio_init(SPI_SCK_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SPI_SCK_PIN);
gpio_init(SPI_MOSI_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SPI_MOSI_PIN);
gpio_init(SPI_MISO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SPI_MISO_PIN);
gpio_init(SPI_CS_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SPI_CS_PIN);
// CS 默认高电平
gpio_bit_set(SPI_CS_PORT, SPI_CS_PIN);
// 复位 SPI
spi_deinit(SPI_PERIPH);
// 配置 SPI
spi_init_struct spi_init_struct;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; // Mode 0
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_8; // 108MHz / 8 = 13.5MHz
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI_PERIPH, &spi_init_struct);
// 使能 SPI
spi_enable(SPI_PERIPH);
}
// CS 控制
#define SPI_CS_LOW() gpio_bit_reset(SPI_CS_PORT, SPI_CS_PIN)
#define SPI_CS_HIGH() gpio_bit_set(SPI_CS_PORT, SPI_CS_PIN)
// 收发一个字节
uint8_t spi_transfer(uint8_t data) {
// 等待发送缓冲区空
while (RESET == spi_i2s_flag_get(SPI_PERIPH, SPI_FLAG_TBE));
// 发送数据
spi_i2s_data_transmit(SPI_PERIPH, data);
// 等待接收缓冲区非空
while (RESET == spi_i2s_flag_get(SPI_PERIPH, SPI_FLAG_RBNE));
// 读取接收数据
return spi_i2s_data_receive(SPI_PERIPH);
}
// 写多字节
void spi_write_bytes(uint8_t *data, uint16_t len) {
for (uint16_t i = 0; i < len; i++) {
spi_transfer(data[i]);
}
}
// 读多字节
void spi_read_bytes(uint8_t *data, uint16_t len) {
for (uint16_t i = 0; i < len; i++) {
data[i] = spi_transfer(0xFF);
}
}
// 写寄存器
void spi_write_reg(uint8_t reg, uint8_t value) {
SPI_CS_LOW();
spi_transfer(reg);
spi_transfer(value);
SPI_CS_HIGH();
}
// 读寄存器
uint8_t spi_read_reg(uint8_t reg) {
uint8_t value;
SPI_CS_LOW();
spi_transfer(reg | 0x80); // 读命令
value = spi_transfer(0xFF);
SPI_CS_HIGH();
return value;
}
八、外部中断
8.1 外部中断配置
c
// GD32 外部中断 - 标准库
#include "gd32f10x.h"
// 按键接在 PA0
#define KEY_GPIO_PORT GPIOA
#define KEY_GPIO_PIN GPIO_PIN_0
#define EXTI_LINE EXTI_0
#define EXTI_PORT_SOURCE EXTI_SOURCE_GPIOA
#define EXTI_PIN_SOURCE EXTI_SOURCE_PIN0
#define EXTI_IRQn EXTI0_IRQn
volatile uint8_t key_pressed = 0;
void exti_init(void) {
// 使能时钟
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_AF);
// 配置按键引脚(下拉输入)
gpio_init(KEY_GPIO_PORT, GPIO_MODE_IPD, GPIO_OSPEED_50MHZ, KEY_GPIO_PIN);
// 配置 EXTI
gpio_exti_source_select(EXTI_PORT_SOURCE, EXTI_PIN_SOURCE);
exti_init_struct exti_init_struct;
exti_init_struct.line_mode = EXTI_MODE_INTERRUPT;
exti_init_struct.line_polarity = EXTI_TRIGGER_RISING; // 上升沿触发
exti_init_struct.line_enable = EXTI_LINE;
exti_init_struct.line_polarity = EXTI_TRIGGER_RISING;
exti_init(&exti_init_struct);
// 配置 NVIC
nvic_irq_enable(EXTI_IRQn, 2, 0);
}
// EXTI0 中断服务函数
void EXTI0_IRQHandler(void) {
if (RESET != exti_flag_get(EXTI_LINE)) {
exti_flag_clear(EXTI_LINE);
key_pressed = 1;
}
}
int main(void) {
exti_init();
usart0_init(115200);
while (1) {
if (key_pressed) {
key_pressed = 0;
printf("Key pressed!\r\n");
}
}
}
九、常用延时函数
c
// GD32 延时函数
#include "gd32f10x.h"
// 简单延时(需要根据主频调整)
void delay_us(uint32_t us) {
uint32_t count = us * (SystemCoreClock / 1000000) / 5;
while (count--) {
__NOP();
}
}
void delay_ms(uint32_t ms) {
while (ms--) {
delay_us(1000);
}
}
// 使用 SysTick 精确延时
static volatile uint32_t systick_ms = 0;
void systick_init(void) {
SysTick_Config(SystemCoreClock / 1000); // 1ms 中断
}
void SysTick_Handler(void) {
systick_ms++;
}
void delay_ms_systick(uint32_t ms) {
uint32_t start = systick_ms;
while ((systick_ms - start) < ms);
}
uint32_t get_tick(void) {
return systick_ms;
}
十、GD32 vs STM32 代码对比
| 功能 | STM32 HAL | GD32 标准库 |
|---|---|---|
| GPIO 初始化 | HAL_GPIO_Init() | gpio_init() |
| GPIO 写 | HAL_GPIO_WritePin() | gpio_bit_set/reset() |
| GPIO 读 | HAL_GPIO_ReadPin() | gpio_input_bit_get() |
| 串口初始化 | HAL_UART_Init() | usart_init() + usart_enable() |
| 串口发送 | HAL_UART_Transmit() | usart_data_transmit() |
| 串口接收 | HAL_UART_Receive() | usart_data_receive() |
| 定时器初始化 | HAL_TIM_Base_Init() | timer_init() |
| 定时器启动 | HAL_TIM_Base_Start_IT() | timer_enable() + timer_interrupt_enable() |
| PWM 设置 | __HAL_TIM_SET_COMPARE() | timer_channel_output_pulse_value_config() |
| ADC 初始化 | HAL_ADC_Init() | adc_init() + adc_enable() |
| ADC 启动 | HAL_ADC_Start() | adc_software_trigger_enable() |
| ADC 读取 | HAL_ADC_GetValue() | adc_regular_data_read() |
| I2C 初始化 | HAL_I2C_Init() | i2c_clock_config() + i2c_enable() |
| SPI 初始化 | HAL_SPI_Init() | spi_init() + spi_enable() |
| 延时 | HAL_Delay() | delay_1ms() |
本文档为 GD32 开发参考,与 STM32 文档配合使用