GD32 vs STM32

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 文档配合使用

相关推荐
czhaii2 小时前
STM32 F103 Altium一键下载PCB图
stm32·单片机·嵌入式硬件
雾削木3 小时前
基于STM32F411RET6 + 双路MB85RS2MT的铁电U盘
stm32·单片机·嵌入式硬件
笨笨饿3 小时前
33_顺序表(待完善)
linux·服务器·c语言·嵌入式硬件·算法·学习方法
点灯小铭3 小时前
基于单片机的多路温湿度采集与WIFI智能报警控制系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
嵌入式×边缘AI:打怪升级日志3 小时前
MX6ULL 的 GPIO 操作方法(保姆级教程)
stm32·单片机·嵌入式硬件
点灯小铭3 小时前
基于单片机的球类比赛专用计分与暂停管理系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
自小吃多5 小时前
TMC220X芯片 串口工具连接交互
笔记·嵌入式硬件
笨笨饿5 小时前
34_数据结构_栈
c语言·开发语言·数据结构·人工智能·嵌入式硬件·算法
Wave8455 小时前
基于 STM32 的模块化多功能手表系统:从架构设计到低功耗深度实践
stm32·嵌入式硬件·智能手表