GD32F103学习笔记——ADC接口使用

Posted Leung_ManWah

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GD32F103学习笔记——ADC接口使用相关的知识,希望对你有一定的参考价值。

一、简介

ADC(Analog-to-Digital Converter),即模拟-数字转换器,可以将连续变化的模拟信号转换为离散的数字信号,进而使用数字电路进行处理,称之为数字信号处理。

GD32F103 系列有 3 个 ADC,精度为 12 位,每个 ADC 最多有 18 个多路复用通道,可以转换来自 16个外部通道和 2 个内部通道的模拟信号。模拟看门狗允许应用程序来检测输入电压是否超出用户设定的高低阈值。各种通道的 A/D 转换可以配置成单次、连续、扫描或间断转换模式。ADC 转换的结果可以按照左对齐或右对齐的方式存储在 16 位数据寄存器中。

二、API说明

以下 ADC 接口位于 GD32F10x_Firmware_Library_V2.2.2\\Firmware\\GD32F10x_standard_peripheral\\Include\\gd32f10x_adc.h

2.1 adc_mode_config

功能配置ADC同步模式
函数定义void adc_mode_config(uint32_t mode)
参数mode:ADC运行模式
返回

mode:ADC运行模式,详细列表如下:

含义
ADC_MODE_FREE所有ADC运行于独立模式
ADC_DAUL_REGULAL_PARALLEL_INSERTED_PARALLELADC0和ADC1运行在规则并行+注入并行组合模式
ADC_DAUL_REGULAL_PARALLEL_INSERTED_ROTATIONADC0和ADC1运行在规则并行+交替触发组合模式
ADC_DAUL_INSERTED_PARALLEL_REGULAL_FOLLOWUP_FASTADC0和ADC1运行在注入并行+快速交叉组合模式
ADC_DAUL_INSERTED_PARALLEL_REGULAL_FOLLOWUP_SLOWADC0和ADC1运行在注入并行+慢速交叉组合模式
ADC_DAUL_INSERTED_PARALLELADC0和ADC1运行在注入并行模式
ADC_DAUL_REGULAL_PARALLELADC0和ADC1运行在规则并行模式
ADC_DAUL_REGULAL_FOLLOWUP_FASTADC0和ADC1运行在快速交叉模式
ADC_DAUL_REGULAL_FOLLOWUP_SLOWADC0和ADC1运行在慢速交叉模式
ADC_DAUL_INSERTED_TRIGGER_ROTATIONADC0和ADC1运行在交替触发模式

2.2 adc_special_function_config

功能使能或除能ADC特殊功能
函数定义void adc_special_function_config(uint32_t adc_periph, uint32_t function, ControlStatus newvalue)
参数adc_periph:ADCx(x=0,1,2)
function:功能配置
newvalue:功能使能ENABLE/除能DISABLE
返回

function:功能配置,详细列表如下:

含义
ADC_SCAN_MODE扫描模式选择
ADC_INSERTED_CHANNEL_AUTO注入组自动转换
ADC_CONTINUOUS_MODE连续模式选择

2.3 adc_data_alignment_config

功能配置ADCx数据对齐方式
函数定义void adc_data_alignment_config(uint32_t adc_periph, uint32_t data_alignment)
参数adc_periph:ADCx(x=0,1,2)
data_alignment:数据对齐方式选择
返回

data_alignment:数据对齐方式选择,详细列表如下:

含义
ADC_DATAALIGN_RIGHTLSB对齐
ADC_DATAALIGN_LEFTMSB对齐

2.4 adc_channel_length_config

功能配置规则通道组或注入通道组的长度
函数定义void adc_channel_length_config(uint32_t adc_periph, uint8_t adc_channel_group, uint32_t length)
参数adc_periph:ADCx(x=0,1,2)
adc_channel_group:通道组选择
length:通道长度,规则通道组为1-16,注入通道组为1-4
返回

adc_channel_group:通道组选择,详细列表如下:

含义
ADC_REGULAR_CHANNEL规则通道组
ADC_INSERTED_CHANNE注入通道组

2.5 adc_external_trigger_source_config

功能配置ADC外部触发源
函数定义void adc_external_trigger_source_config(uint32_t adc_periph, uint8_t adc_channel_group, uint32_t external_trigger_source)
参数adc_periph:ADCx(x=0,1,2)
adc_channel_group:通道组选择
external_trigger_source:规则通道组或注入通道组触发源
返回

external_trigger_source:规则通道组或注入通道组触发源,详细列表如下:

含义
ADC0_1_EXTTRIG_REGULAR_T0_CH0TIMER0 CH0事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T0_CH1TIMER0 CH1事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T0_CH2TIMER0 CH2事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T1_CH1TIMER1 CH1事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T2_TRGOTIMER2 TRGO事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T3_CH3TIMER3 CH3事件(规则组)
ADC0_1_EXTTRIG_REGULAR_T7_TRGOTIMER7 TRGO事件(规则组)
ADC0_1_EXTTRIG_REGULAR_EXTI_11外部中断线11(规则组)
ADC0_1_2_EXTTRIG_REGULAR_NONE软件触发(规则组)
ADC2_EXTTRIG_REGULAR_T2_CH0TIMER2 CH0事件(规则组)
ADC2_EXTTRIG_REGULAR_T1_CH2TIMER1 CH2事件(规则组)
ADC2_EXTTRIG_REGULAR_T0_CH2TIMER0 CH2事件(规则组)
ADC2_EXTTRIG_REGULAR_T7_CH0TIMER7 CH0事件(规则组)
ADC2_EXTTRIG_REGULAR_T7_TRGOTIMER7 TRGO事件(规则组)
ADC2_EXTTRIG_REGULAR_T4_CH0TIMER4 CH0事件(规则组)
ADC2_EXTTRIG_REGULAR_T4_CH2TIMER4 CH2事件(规则组)
ADC0_1_EXTTRIG_INSERTED_T0_TRGOTIMER0 TRGO事件(注入组)
ADC0_1_EXTTRIG_INSERTED_T0_CH3TIMER0 CH3事件(注入组)
ADC0_1_EXTTRIG_INSERTED_T1_TRGOTIMER1 TRGO事件(注入组)
ADC0_1_EXTTRIG_INSERTED_T1_CH0TIMER1 CH0事件(注入组)
ADC0_1_EXTTRIG_INSERTED_T2_CH3TIMER2 CH3事件(注入组)
ADC0_1_EXTTRIG_INSERTED_T3_TRGOTIMER3 TRGO事件(注入组)
ADC0_1_EXTTRIG_INSERTED_EXTI_15外部中断线15(注入组)
ADC0_1_EXTTRIG_INSERTED_T7_CH3TIMER7 CH3事件(注入组)
ADC0_1_2_EXTTRIG_INSERTED_NONE软件触发(注入组)
ADC2_EXTTRIG_INSERTED_T0_TRGOTIMER0 TRGO事件(注入组)
ADC2_EXTTRIG_INSERTED_T0_CH3TIMER0 CH3事件(注入组)
ADC2_EXTTRIG_INSERTED_T3_CH2TIMER3 CH2事件(注入组)
ADC2_EXTTRIG_INSERTED_T7_CH1TIMER7 CH1事件(注入组)
ADC2_EXTTRIG_INSERTED_T7_CH3TIMER7 CH3事件(注入组)
ADC2_EXTTRIG_INSERTED_T4_TRGOTIMER4 TRGO事件(注入组)
ADC2_EXTTRIG_INSERTED_T4_CH3TIMER4 CH3事件(注入组)

2.6 adc_external_trigger_config

功能配置ADC外部触发
函数定义void adc_external_trigger_config(uint32_t adc_periph, uint8_t adc_channel_group, ControlStatus newvalue)
参数adc_periph:ADCx(x=0,1,2)
adc_channel_group:通道组选择
newvalue:通道使能ENABLE/禁能DISABLE
返回

2.7 adc_enable

功能使能ADCx外设
函数定义void adc_enable(uint32_t adc_periph)
参数adc_periph:ADCx(x=0,1,2)
返回

2.8 adc_calibration_enable

功能ADCx校准复位
函数定义void adc_calibration_enable(uint32_t adc_periph)
参数adc_periph:ADCx(x=0,1,2)
返回

2.9 adc_regular_channel_config

功能配置ADC规则通道组
函数定义void adc_regular_channel_config(uint32_t adc_periph, uint8_t rank, uint8_t adc_channel, uint32_t sample_time)
参数adc_periph:ADCx(x=0,1,2)
rank:规则组通道序列,取值范围为0~15
adc_channel:ADC通道x(x=0…17)(只有ADC0,可取值x=16和17)
sample_time:采样时间
返回

sample_time:采样时间,详细列表如下:

含义
ADC_SAMPLETIME_1POINT51.5周期
ADC_SAMPLETIME_7POINT57.5周期
ADC_SAMPLETIME_13POINT513.5周期
ADC_SAMPLETIME_28POINT528.5周期
ADC_SAMPLETIME_41POINT541.5周期
ADC_SAMPLETIME_55POINT555.5周期
ADC_SAMPLETIME_71POINT571.5周期
ADC_SAMPLETIME_239POINT5239.5周期

2.10 adc_software_trigger_enable

功能ADC软件触发使能
函数定义void adc_software_trigger_enable(uint32_t adc_periph, uint8_t adc_channel_group)
参数adc_periph:ADCx(x=0,1,2)
channel_group:通道组选择
返回

2.11 adc_flag_get

功能获取ADC标志位
函数定义FlagStatus adc_flag_get(uint32_t adc_periph, uint32_t adc_flag)
参数adc_periph:ADCx(x=0,1,2)
adc_flag:ADC标志位
返回SET或RESET

adc_flag:ADC标志位,详细列表如下:

含义
ADC_FLAG_WDE模拟看门狗事件标志位
ADC_FLAG_EOC组转换结束标志位
ADC_FLAG_EOIC注入通道组转换结束标志位
ADC_FLAG_STIC注入通道组转换开始标志位
ADC_FLAG_STRC规则通道组转换开始标志位

2.12 adc_flag_clear

功能清除ADC标志位
函数定义void adc_flag_clear(uint32_t adc_periph, uint32_t adc_flag)
参数adc_periph:ADCx(x=0,1,2)
adc_flag:ADC标志位
返回

2.13 adc_regular_data_read

功能读ADC规则组数据寄存器
函数定义uint16_t adc_regular_data_read(uint32_t adc_periph)
参数adc_periph:ADCx(x=0,1,2)
返回ADC转换值(0-0xFFFF)

2.14 adc_interrupt_flag_get

功能获取ADC中断标志位
函数定义FlagStatus adc_interrupt_flag_get(uint32_t adc_periph, uint32_t adc_interrupt)
参数adc_periph:ADCx(x=0,1,2)
adc_interrupt:ADC中断标志位
返回SET或RESET

adc_interrupt:ADC中断标志位,详细列表如下:

含义
ADC_INT_WDE模拟看门狗中断标志位
ADC_INT_EOC组转换结束中断标志位
ADC_INT_EOIC注入通道组转换结束中断标志位

2.15 adc_interrupt_flag_clear

功能清除ADC中断标志位
函数定义void adc_interrupt_flag_clear(uint32_t adc_periph, uint32_t adc_interrupt)
参数adc_periph:ADCx(x=0,1,2)
adc_interrupt:ADC中断标志位
返回

2.16 adc_interrupt_enable

功能ADC中断使能
函数定义void adc_interrupt_enable(uint32_t adc_periph, uint32_t adc_interrupt)
参数adc_periph:ADCx(x=0,1,2)
adc_interrupt:ADC中断标志位
返回

三、ADC电压采集

3.1 电压输入范围

ADC 输入范围为: V R E F − ≤ V I N ≤ V R E F + V_REF- ≤ V_IN ≤ V_REF+ VREFVINVREF+。由 VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。

我们在设计原理图的时候一般把 VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到 ADC 的输入电压范围为:0~3.3V

如果我们想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,我们可以在外部加一个电压调理电路,把需要转换的电压抬升或者降压到 0~3.3V,这样 ADC 就可以测量。

3.2 ADC通道选择

GD32 的 ADC 多达 18 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0、ADCx_IN1…ADCx_IN5。这 16 个通道对应着不同的 IO 口,具体是哪一个 IO 口可以从手册查询到。其中 ADC0/1/2 还有内部通道:ADC0 的通道 16 连接到了芯片内部的温度传感器,Vrefint 连接到了通道 17。ADC1 的模拟通道 16 和 17 连接到了内部的 VSS。ADC2 的模拟通道 9、14、15、16 和 17 连接到了内部的 VSS。

ADC0ADC1ADC2
通道0PA0PA0PA0
通道1PA1PA1PA1
通道2PA2PA2PA2
通道3PA3PA3PA3
通道4PA4PA4PF6
通道5PA5PA5PF7
通道6PA6PA6PF8
通道7PA7PA7PF9
通道8PB0PB0PF10
通道9PB1PB1连接内部VSS
通道10PC0PC0PC0
通道11PC1PC1PC1
通道12PC2PC2PC2
通道13PC3PC3PC3
通道14PC4PC4连接内部VSS
通道15PC5PC5连接内部VSS
通道16连接内部温度传感器Vsense连接内部VSS连接内部VSS
通道17连接内部参考电压输入Vrefint连接内部VSS连接内部VSS

3.3 编程要点

  1. 初始 ADC 用到的 GPIO
  2. 设置 ADC 的工作参数并初始化
  3. 设置 ADC 工作时钟
  4. 设置 ADC 转换通道顺序及采样时间
  5. 配置使能 ADC 转换完成中断,在中断/轮询内读取转换完数据
  6. 使能 ADC
  7. 使能软件触发 ADC 转换

ADC 转换结果数据使用中断/轮询方式读取,这里没有使用 DMA 进行数据传输。

3.4 ADC初始化

使用到 GPIO 时候都必须开启对应的 GPIO 时钟,GPIO 用于 AD 转换功能必须配置为模拟输入模式。

ADC 工作参数具体配置为:独立模式、单通道采集不需要扫描、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为 1

rcu_adc_clock_config() 函数用来配置 ADC 的工作时钟,接收一个参数,设置的是 PCLK2 的分频系数,ADC 的时钟最大不能超过 14M。

adc_enable() 函数控制 ADC 转换启动。最后,进行 ADC 校准。

/*------------------时钟配置------------------*/
// GPIO时钟使能
rcu_periph_clock_enable(RCU_GPIOC);
// ADC时钟使能
rcu_periph_clock_enable(RCU_ADC1);
// ADC时钟8分频,最大14MHz
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
    
/*------------------ADC GPIO配置------------------*/
// 必须为模拟输入
gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
    
/*------------------ADC工作模式配置------------------*/
// 只使用一个ADC,属于独立模式
adc_mode_config(ADC_MODE_FREE);
// 多通道用扫描模式
//    adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);
// 单通道用连续转换模式
adc_special_function_config(ADC1, ADC_CONTINUOUS_MODE, ENABLE);
    
// 结果转换右对齐
adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
// 转换通道1个
adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 1);
    
// 不用外部触发转换,软件开启即可
adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);
    
// 使能ADC
adc_enable(ADC1);
delay_1ms(1);                                                   // 等待1ms
// 使能ADC校准
adc_calibration_enable(ADC1);

3.5 获取ADC转化值

adc_regular_channel_config() 函数用来绑定 ADC 通道的转换顺序和时间。它接收 4 个形参,第一个形参选择 ADC 外设,可为 ADC0、ADC1 或 ADC2;第二个形参为通道的转换顺序,可选为 1 到 16;第三个形参通道选择,总共可选 18 个通道;第四个形参为采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。

调用 adc_software_trigger_enable() 函数进行软件触发 ADC 开始转换。

adc_regular_data_read() 函数是获取 ADC 转换结果值的库函数,只有一个形参为 ADC 外设,可选为 ADC0、ADC1 或 ADC2,该函数还返回一个 16 位的 ADC 转换结果值。

uint16_t adcValue = 0;
    
// 配置ADC通道转换顺序,采样时间为55.5个时钟周期
adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_13, ADC_SAMPLETIME_55POINT5);
// 由于没有采用外部触发,所以使用软件触发ADC转换
adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL);   
    
while(!adc_flag_get(ADC1, ADC_FLAG_EOC));                       // 等待采样完成
adc_flag_clear(ADC1, ADC_FLAG_EOC);                             // 清除结束标志
    
adcValue = adc_regular_data_read(ADC1);                         // 读取ADC数据

3.6 ADC中断初始化

利用 ADC 转换完成中断可以非常方便的保证我们读取到的数据是转换完成后的数据而不用担心该数据可能是 ADC 正在转换时“不稳定”的数据。我们使用 adc_interrupt_enable() 函数使能 ADC 转换完成中断,并在中断服务函数中读取转换结果数据。

// 使能ADC中断
nvic_irq_enable(ADC0_1_IRQn, 0, 0);
// 清除ADC规则组转换结束中断标志
adc_interrupt_flag_clear(ADC1, ADC_INT_FLAG_EOC);
// 使能ADC规则组转换结束中断
adc_interrupt_enable(ADC1, ADC_INT_EOC);

3.7 ADC中断处理函数

我们使能了 ADC 转换完成中断,在 ADC 转换完成后就会进入中断服务函数,我们在中断服务函数内直接读取 ADC 转换结果保存在变量(在 main.c 中定义)中。

extern uint16_t adcValue;
/*!
    \\brief      this function handles ADC0 and ADC1 interrupt
    \\param[in]  none
    \\param[out] none
    \\retval     none
*/
void ADC0_1_IRQHandler(void)

    adc_interrupt_flag_clear(ADC1, ADC_INT_FLAG_EOC);               // 清除ADC规则组转换结束中断标志
    adcValue = adc_regular_data_read(ADC1);                             // 读取ADC数据

ADC 中断处理函数名称要与 ADC外设 相对应,可在 startup_gd32f10x_hd.s 启动文件中查看:

;                   /* external interrupts handler */
                    DCD     WWDGT_IRQHandler                  ; 16:Window Watchdog Timer
                    DCD     LVD_IRQHandler                    ; 17:LVD through EXTI Line detect
                    DCD     TAMPER_IRQHandler                 ; 18:Tamper Interrupt   
                    DCD     RTC_IRQHandler                    ; 19:RTC through EXTI Line
                    DCD     FMC_IRQHandler                    ; 20:FMC
                    DCD     RCU_IRQHandler                    ; 21:RCU
                    DCD     EXTI0_IRQHandler                  ; 22:EXTI Line 0
                    DCD     EXTI1_IRQHandler                  ; 23:EXTI Line 1
                    DCD     EXTI2_IRQHandler                  ; 24:EXTI Line 2
                    DCD     EXTI3_IRQHandler                  ; 25:EXTI Line 3
                    DCD     EXTI4_IRQHandler                  ; 26:EXTI Line 4
                    DCD     DMA0_Channel0_IRQHandler          ; 27:DMA0 Channel 0
                    DCD     DMA0_Channel1_IRQHandler          ; 28:DMA0 Channel 1
                    DCD     DMA0_Channel2_IRQHandler          ; 29:DMA0 Channel 2
                    DCD     DMA0_Channel3_IRQHandler          ; 30:DMA0 Channel 3
                    DCD     DMA0_Channel4_IRQHandler          ; 31:DMA0 Channel 4
                    DCD     DMA0_Channel5_IRQHandler          ; 32:DMA0 Channel 5 
                    DCD     DMA0_Channel6_IRQHandler          ; 33:DMA0 Channel 6
                    DCD     ADC0_1_IRQHandler                 ; 34:ADC0 and ADC1
                    DCD     USBD_HP_CAN0_TX_IRQHandler        ; 35:USBD and CAN0 TX
                    DCD     USBD_LP_CAN0_RX0_IRQHandler       ; 36:USBD and CAN0 RX0
                    DCD     CAN0_RX1_IRQHandler               ; 37:CAN0 RX1
                    DCD     CAN0_EWMC_IRQHandler              ; 38:CAN0 EWMC
                    DCD     EXTI5_9_IRQHandler                ; 39:EXTI Line 5 to EXTI Line 9
                    DCD     TIMER0_BRK_IRQHandler             ; 40:TIMER0 Break
                    DCD     TIMER0_UP_IRQHandler              ; 41:TIMER0 Update
                    DCD     TIMER0_TRG_CMT_IRQHandler         ; 42:TIMER0 Trigger and Commutation
                    DCD     TIMER0_Channel_IRQHandler         ; 43:TIMER0 Channel Capture Compare
                    DCD     TIMER1_IRQHandler                 ; 44:TIMER1
                    DCD     TIMER2_IRQHandler                 ; 45:TIMER2
                    DCD     TIMER3_IRQHandler                 ; 46:TIMER3
                    DCD     I2C0_EV_IRQHandler                ; 47:I2C0 Event
                    DCD     I2C0_ER_IRQHandler                ; 48:I2C0 Error
                    DCD     I2C1_EV_IRQHandler                ; 49:I2C1 Event
                    DCD     I2C1_ER_IRQHandler                ; 50:I2C1 Error
                    DCD     SPI0_IRQHandler                   ; 51:SPI0
                    DCD     SPI1_IRQHandler                   ; 52:SPI1
                    DCD     USART0_IRQHandler                 ; 53:USART0
                    DCD     USART1_IRQHandler                 ; 54:USART1
                    DCD     USART2_IRQHandler                 ; 55:USART2
                    DCD     EXTI10_15_IRQHandler              ; 56:EXTI Line 10 to EXTI Line 15
                    DCD     RTC_Alarm_IRQHandler              ; 57:RTC Alarm through EXTI Line
                    DCD     USBD_WKUP_IRQHandler              ; 58:USBD WakeUp from suspend through EXTI Line
                    DCD     TIMER7_BRK_IRQHandler             ; 59:TIMER7 Break Interrupt
                    DCD     TIMER7_UP_IRQHandler              ; 60:TIMER7 Update Interrupt
                    DCD     TIMER7_TRG_CMT_IRQHandler         ; 61:TIMER7 Trigger and Commutation Interrupt
                    DCD     TIMER7_Channel_IRQHandler         ; 62:TIMER7 Channel Capture Compare 
                    DCD     ADC2_IRQHandler                   ; 63:ADC2
                    DCD     EXMC_IRQHandler                   ; 64:EXMC
                    DCD     SDIO_IRQHandler                   ; 65:SDIO
                    DCD     TIMER4_IRQHandler                 ; 66:TIMER4
                    DCD     SPI2_IRQHandler                   ; 67:SPI2
                    DCD     UART3_IRQHandler                  ; 68:UART3
                    DCD     UART4_IRQHandler                  ; 69:UART4
                    DCD     TIMER5_IRQHandler                 ; 70:TIMER5
                    DCD     TIMER6_IRQHandler                 ; 71:TIMER6
                    DCD     DMA1_Channel0_IRQHandler          ; 72:DMA1 Channel0
                    DCD     DMA1_Channel1_IRQHandler          ; 73:DMA1 Channel1
                    DCD     DMA1_Channel2_IRQHandler          ; 74:DMA1 Channel2
                    DCD     DMA1_Channel3_4_IRQHandler        ; 75:DMA1 Channel3 and Channel4

四、ADC多通道轮询读取

4.1 board_adc.c

/*********************************************************************
 * INCLUDES
 */
#include "gd32f10x.h"
#include "systick.h"

#include "board_adc.h"

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief ADC驱动初始化
 @param 无
 @return 无
*/
void ADC_Init(void)

    /*------------------时钟配置------------------*/
    // GPIO时钟使能
    rcu_periph_clock_enable(RCU_GPIOC);
    // ADC时钟使能
    rcu_periph_clock_enable(RCU_ADC1);
    // ADC时钟8分频,最大14MHz
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
    
    /*------------------ADC GPIO配置------------------*/
    // 必须为模拟输入
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    
    /*------------------ADC工作模式配置------------------*/
    // 只使用一个ADC,属于独立模式
    adc_mode_config(ADC_MODE_FREE);
    // 多通道用扫描模式
    adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);
    // 单通道用连续转换模式
//    adc_special_function_config(ADC1, ADC_CONTINUOUS_MODE, ENABLE);
    
    // 结果转换右对齐
    adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
    // 转换通道1个
    adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 1);
    
    // 不用外部触发转换,软件开启即可
    adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
    adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);
    
    // 使能ADC
    adc_enable(ADC1);
    delay_1ms(1);                                                   // 等待1ms
    // 使能ADC校准
    adc_calibration_enable(ADC1);


/**
 @brief ADC读取
 @param channel -[in] ADC通道
 @return ADC采样值
*/
uint16_t ADC_Read(uint8_t channel)

    uint16_t adcValue = 0;
    
    // 配置ADC通道转换顺序,采样时间为55.5个时钟周期
    adc_regular_channel_config(ADC1, 0, channel, ADC_SAMPLETIME_55POINT5);
    // 由于没有采用外部触发,所以使用软件触发ADC转换
    adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL);   
    
    while(!adc_flag_get(ADC1, ADC_FLAG_EOC));                       // 等待采样完成
    adc_flag_clear(ADC1, ADC_FLAG_EOC);                             // 清除结束标志
    
    adcValue = adc_regular_data_read(ADC1);                         // 读取ADC数据
    return adcValue;


/****************************************************END OF FILE****************************************************/

4.2 board_adc.h

#ifndef _BOARD_ADC_H_
#define _BOARD_ADC_H_

/*********************************************************************
 * INCLUDES
 */
#include "gd32f10x_adc.h"
 
/*********************************************************************
 * DEFINITIONS
 */

/*********************************************************************
 * API FUNCTIONS
 */
void ADC_Init(void);
uint16_t ADC_Read(uint8_t channel);

#endif /* _BOARD_ADC_H_ */

4.3 main.c

#include <stdio.h>
#include "gd32f10x.h"
#include "systick.h"

#include "board_adc.h"
#include "board_usart.h"

static volatile uint16_t s_adcValue = 0;
static volatile uint16_t s_volValue = 0;
static volatile uint16_t s_adcValue2 = 0;
static volatile uint16_t s_volValue2 = 0;

int main(void)

    systick_config();//系统主频108MHZ,采用外部晶振,由两个宏决定(__SYSTEM_CLOCK_108M_PLL_HXTAL与HXTAL_VALUE)
    
    ADC_Init();
    USART_Init();
	
    while(1)
    
        s_adcValue = ADC_Read(ADC_CHANNEL_13);  // 读取ADC采样值
        printf("adc1_13: %d ", s_adcValue);
        s_volValue = s_adcValue * 3300 / 4095;  // 转换成电压值
        printf("vol: %d\\r\\n", s_volValue);
        
        s_adcValue2 = ADC_Read(ADC_CHANNEL_14); // 读取ADC采样值
        printf("adc1_14: %d ", s_adcValue2);
        s_volValue2 = s_adcValue2 * 3300 / 4095; // 转换成电压值
        printf("vol: %d\\r\\n", s_volValue2);
        delay_1ms(500);
    

串口打印添加查看:GD32F103学习笔记(7)——USART串口使用
查看打印:

4.4 工程代码

百度网盘:https://pan.baidu.com/s/1pMFKeyZDeIZ1ejBfpc-Y0Q?pwd=lp1j 提取码:lp1j

五、ADC单通道中断读取

5.1 board_adc.c

/*********************************************************************
 * INCLUDES
 */
#include "gd32f10x.h"
#include "systick.h"

#include "board_adc.h"

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief ADC驱动初始化
 @param 无
 @return 无
*/
void ADC_Init(void)

    /*------------------时钟配置------------------*/
    // GPIO时钟使能
    rcu_periph_clock_enable(RCU_GPIOA以上是关于GD32F103学习笔记——ADC接口使用的主要内容,如果未能解决你的问题,请参考以下文章

GD32F103学习笔记——EXTI(外部中断)接口使用

GD32F103学习笔记——GPIO接口使用

GD32F103学习笔记——在GD32F103移植STM32F103代码

GD32F103学习笔记——在GD32F103移植STM32F103代码

STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器

GD32F103学习笔记——USART串口使用