3. 使用ADC采集电位器电压并串口输出
任务目标
本案例基于GD32微控制器,完成以下闭环:配置ADC规则组通道采集电位器分压电压,将采样值转换为实际电压值,并通过串口(USART)以可读格式输出。最终通过串口助手观察电压数值随电位器旋钮变化,验证ADC与串口通信链路正确。
硬件连接与前置条件
- 开发板:GD32F103系列(以GD32F103C8T6为例,其他型号需核对引脚与时钟配置)
- 电位器:10kΩ,两端接3.3V与GND,中间抽头接PA1(ADC通道1)
- 串口:USART0(PA9-TX, PA10-RX),通过USB-TTL模块连接PC,波特率115200
- 软件:Keil MDK或IAR,GD32标准外设库(V3.x)
核心实现代码
以下代码完成ADC初始化(规则组、软件触发、单次转换)、USART0初始化及电压数据轮询发送。代码基于GD32标准外设库,使用gd32f10x.h头文件。
/* main.c - GD32F103 ADC电位器电压采集与串口输出 */
#include "gd32f10x.h"
#include <stdio.h>
/* 重定向fputc到USART0,用于printf */
int fputc(int ch, FILE *f) {
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
static void gpio_config(void) {
/* PA1: ADC输入模拟浮空 */
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
/* PA9: TX复用推挽; PA10: RX浮空输入 */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
}
static void usart0_config(void) {
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
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_enable(USART0);
}
static void adc_config(void) {
/* 使能ADC时钟并配置分频 */
rcu_periph_clock_enable(RCU_ADC0);
adc_clock_config(ADC_ADCCK_PCLK2_DIV6); /* 约12MHz,ADC时钟≤14MHz */
/* ADC复位与规则组配置 */
adc_deinit(ADC0);
adc_mode_config(ADC_MODE_FREE); /* 独立模式 */
adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE); /* 单次转换 */
adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1U);
/* 通道1,采样时间55.5周期,软件触发 */
adc_regular_channel_config(ADC0, 0U, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE); /* 软件触发 */
adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
/* 使能ADC并校准 */
adc_enable(ADC0);
delay_1ms(1U);
adc_calibration_enable(ADC0);
}
int main(void) {
/* 系统时钟默认108MHz(需在system_gd32f10x.c中配置) */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
gpio_config();
usart0_config();
adc_config();
while(1) {
/* 软件触发一次转换并等待完成 */
adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
while(RESET == adc_flag_get(ADC0, ADC_FLAG_ENDC));
uint16_t adc_value = adc_regular_data_read(ADC0);
float voltage = (float)adc_value * 3.3f / 4095.0f;
/* 串口输出:原始值 + 电压值 */
printf("ADC=%4d, Voltage=%.2fV\r\n", adc_value, voltage);
delay_1ms(500U); /* 500ms输出一次 */
}
}
编译与运行
- 创建GD32标准外设库工程,将上述代码替换
main.c内容。 - 在
system_gd32f10x.c中确认系统时钟为108MHz(__SYSTEM_CLOCK_108M_PLL_HXTAL宏定义)。 - 编译并下载至开发板。
- 连接串口至PC,打开串口助手(波特率115200,8N1)。
验证方法与通过标准
- 现象:串口助手每500ms收到一行数据,格式如
ADC=2048, Voltage=1.65V。 - 判定通过:旋转电位器旋钮,ADC值与电压值随之线性变化;电压范围在0V~3.3V之间;电压计算值与万用表实测值误差小于±0.05V(忽略电源纹波与ADC量化误差)。
- 预期输出示例(电位器居中时):
ADC=2048, Voltage=1.65V。该值由12位ADC满量程4095与3.3V基准直接计算得出,非实测结果。
常见问题排查
- 串口无输出:检查PA9/PA10接线是否交叉连接;确认
usart_baudrate_set与串口助手波特率一致;检查fputc重定向是否生效(需包含stdio.h并勾选微库)。 - 电压值固定不变:确认电位器抽头确实连接PA1;检查ADC通道号是否与引脚匹配(PA1对应ADC_CHANNEL_1)。
- 电压值跳变过大:在电位器抽头与GND之间并联0.1μF电容滤波;检查电源是否稳定。