配置流程
一般使用ADC功能,都需要有以下几个步骤。
- 配置时钟
- 配置引脚
- 配置ADC模式
- 配置数据对齐方式
- 配置分辨率
- 配置采集通道
- 配置触发方式
- 使能ADC
配置时钟
本案例使用ADC进行操作,需要开启ADC的时钟。 不过需要注意的是GD32VW55x的用户手册写出,ADC的最大时钟频率为42MHz。因此我们使用ADC时,需要将挂载ADC的时钟总线频率分频到42MHz以下。
ADC的时钟来源有AHB(160MHz)
和APB2(160MHz)
,我们需要选择一个时钟源,并将其分频到42MHz
以下。
本案例使用的是APB2
作为ADC时钟来源,其最大时钟频率为160MHz
,我们需要将其分频到42MHz
以下。而它分频的参数有2分频、4分频、6分频、8分频等等。如选择2分频,则最终的ADC时钟频率为 160 / 2 = 80 MHz
,这明显没有达到我们的42MHz
以下的要求。选择4分频
,最终的ADC时钟频率为:
160 / 4 = 40MHz
4分频
满足了我们的要求。
配置引脚
GD32VW553HQM6一共有11个外部ADC通道,我们将光敏电阻模块的AO引脚连接在PB0引脚上,查找数据手册的引脚定义可知,PB0的附加功能有ADC的通道8。
因为我们之前配置时钟的章节开启的是ADC的时钟,所以这里选择PB0的附加功能,ADC的通道8进行操作。要操作 GPIO 引脚,必不可少的就是对 GPIO 进行配置,包括开启时钟、配置模式、配置输出、设置功能等,还是这一系列的操作。
PB0引脚和ADC通道8的宏定义如下:
/* PB0 ADC_IN8 */
#define BSP_ADC_GPIO_RCU RCU_GPIOB
#define BSP_ADC_GPIO_PORT GPIOB
#define BSP_ADC_GPIO_PIN GPIO_PIN_0
/* PB0 ADC_IN8 */
#define BSP_ADC_RCU RCU_ADC
#define BSP_ADC ADC
#define BSP_ADC_CHANNEL ADC_CHANNEL_8
2
3
4
5
6
7
8
9
初始化GPIO引脚的配置如下:
//使能引脚时钟
rcu_periph_clock_enable(BSP_ADC_GPIO_RCU);
//使能ADC时钟
rcu_periph_clock_enable(BSP_ADC_RCU);
//配置ADC时钟为4分频
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
//配置引脚为模拟浮空输入模式
gpio_mode_set(BSP_ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_ADC_GPIO_PIN);
2
3
4
5
6
7
8
以上代码需要注意的是使用ADC功能时,引脚必须设置为模拟浮空模式,如设置为上拉或下拉模式,则采集的电压是不准确的。
配置ADC模式
ADC的模式有4种,分别是单次、连续、扫描和间断转换模式。具体的讲解见章节【GD32的ADC介绍】,这里我们配置为扫描模式,这样就可以根据自己的需要,配置采集通道进行依次扫描采集对应引脚的模拟信号。也可以根据需要配置为连续模式和间断模式。
扫描模式配置如下:
//使能扫描模式
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
2
配置数据对齐方式
GD32VW553HQM6 微控制器的ADC支持各种数据对齐方式以适应不同的应用场景。常见的数据对齐方式包括左对齐和右对齐。在右对齐模式下,ADC的数据在转换结束后被右对齐到最低位,不足的位数在高位填充0。右对齐模式允许实现在没有精度的损失下更好的动态范围。
在左对齐模式下,ADC的数据被左对齐到最高位,不足的位数在低位填充0。左对齐模式可以提高分辨率,但会导致动态范围降低。
我们配置为右对齐方式,这样我们可以直接将转换完成的数据进行运算。
右对齐方式的配置如下:
//数据右对齐
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
2
配置分辨率
GD32VW553HQM6的分辨率可以配置为6、8、10、12 位。我们可以通过降低 ADC 的分辨率,获得较快的转换时间(tADC)。对于那些不需要高精度数据的应用,可以使用较低的分辨率来实现更快速地转换。
这里我们配置为12位分辨率。分辨率的配置如下:
//ADC0设置为12位分辨率
adc_resolution_config(ADC_RESOLUTION_12B);
2
配置采集通道
我们需要配置的是使用的通道和采集通道个数。这里我们使用的是常规通道组,并且只需要转换一个通道。后续需要采集多个通道时,只需要修改采集的通道即可。
采集通道的配置如下:
//ADC0设置为规则组 一共使用 1 个通道
adc_channel_length_config(ADC_ROUTINE_CHANNEL, 1);
2
配置触发方式
触发的方式有两种,分别是外部触发方式和软件触发方式。
其中外部触发输入的上升沿、下降沿可以触发规则组或注入组的转换。具体见GD32VW55x用户手册的第202页。需要注意的是可以实时修改外部触发选择,在修改期间不会出现触发事件。
软件触发方式是由软件触发启动,通常用在单次采样转换中。在软件触发模式下,ADC转换工作被触发后,由软件控制以固定的时间间隔进行转换,因此通常用于采集时间不太关键,但要求精度较高的应用。
这里选择的是软件触发方式,软件触发方式的配置如下:
//ADC外部触发禁用, 即只能使用软件触发
adc_external_trigger_config(ADC_ROUTINE_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
//使能软件触发
adc_software_trigger_enable(ADC_ROUTINE_CHANNEL);
2
3
4
使能ADC
ADC配置好之后并不能开始工作,还需要去使能,就是相当于有一个开关可以打开关闭。需要注意的是要先使能了ADC之后,才能开始进行自校准。
//ADC使能
adc_enable();
2
最终的ADC全部配置参数如下:
void AdcConfig(void)
{
//使能引脚时钟
rcu_periph_clock_enable(BSP_ADC_GPIO_RCU);
//使能ADC时钟
rcu_periph_clock_enable(BSP_ADC_RCU);
//配置ADC时钟
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
//配置引脚为模拟输入模式
gpio_mode_set(BSP_ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, BSP_ADC_GPIO_PIN);
//使能扫描模式
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
//数据右对齐
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
//ADC0设置为12位分辨率
adc_resolution_config(ADC_RESOLUTION_12B);
//ADC0设置为规则组 一共使用 1 个通道
adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);
//ADC外部触发禁用, 即只能使用软件触发
adc_external_trigger_config(ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
//使能软件触发
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
//ADC0使能
adc_enable();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
采集转换
我们之前使用的是扫描模式并使用的是软件触发方式,因此当我们要采集信号时,需要配置好采集通道并开启软件转换。开启转换后,等待EOC标志位置1。其中EOC为转换完成标志位,我们可以通过判断其是否置1,确定是否转换完成。转换完成后将数据从16位寄存器中取出。
/**********************************************************
* 函 数 名 称:Get_ADC_Value
* 函 数 功 能:读取ADC值
* 传 入 参 数:ADC_CHANNEL_x=要采集的通道
* 函 数 返 回:测量到的值
* 作 者:LC
* 备 注:默认采样周期为14.5个ADC采样时间
**********************************************************/
unsigned int Get_ADC_Value(uint8_t ADC_CHANNEL_x)
{
//设置采集通道
adc_routine_channel_config(0, ADC_CHANNEL_x, ADC_SAMPLETIME_14POINT5);
//开始软件转换
adc_software_trigger_enable(ADC_ROUTINE_CHANNEL);
//等待 ADC 采样完成
while(!adc_flag_get(ADC_FLAG_EOC));
//清除ADC0 采样完成标志位
adc_flag_clear(ADC_FLAG_EOC);
//返回读取到的采样值
return (adc_routine_data_read());
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
实验现象
在main.c中调用unsigned int Get_ADC_Value(uint8_t ADC_CHANNEL_x);
函数,采集PC1
引脚的电压,并通过串口输出。
#include "gd32vw55x.h"
#include "systick.h"
#include <stdio.h>
#include "bsp_adc.h"
#include "bsp_usart.h"
int main(void)
{
unsigned int adc_value = 0;
float voltage = 0.0;
/* 使能全局中断 */
eclic_global_interrupt_enable();
/* 中断分组 */
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL2_PRIO2);
//滴答定时器初始化
systick_config();
//板载LED初始化
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_output_options_set(GPIOC,GPIO_OTYPE_PP,GPIO_OSPEED_25MHZ,GPIO_PIN_13);
gpio_bit_set(GPIOC, GPIO_PIN_13);
//串口0初始化
uart0InitConfig();
//ADC功能初始化
AdcConfig();
printf("start Demo\r\n");
while(1)
{
//获取ADC通道8的采集数据
adc_value = Get_ADC_Value(ADC_CHANNEL_8);
//输出采样值
printf("adc_value = %d\r\n", adc_value );
//转换为实际电压
voltage = (float)adc_value / 4095.0 * 3.3;
//输出采样到的电压
printf( "voltage = %.2f\r\n", voltage ,3);
delay_1ms(1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
在灯光充足的情况下,ADC转换的值大约为920左右,转换为实际电压接近0.5V。
当用手当住光敏电阻后,采集到的值大约在3790左右,转换为实际电压接近3.0V。
如果没有光敏电阻,则可以连接到3.3V或者GND进行测试。当接入3.3V时采集到的值接近4095;当接入GND时,采集到的值接近0。
关于这一章节的代码,可以在开发板资料/03 - 软件资料/代码例程/里面的011ADC光敏电阻实验
。
下载中心跳转📦
资料下载中心:点击跳转🚀