二十二、 ADC光敏电阻实验
模块来源
采购链接:
https://item.taobao.com/item.htm?spm=2013.1.0.0.68c07a63p9f0me&id=522579320463
资料下载链接:
https://pan.baidu.com/s/1VMFN1fVo5jxB80IYTsY67A
资料提取码:y8jw
规格参数
工作电压:3.3-5V
工作电流:1MA
模块尺寸:31.1475 x 14.097mm
输出方式: DO接口为数字量输出 AO接口为模拟量输出
读取方式:ADC
管脚数量:4 Pin(2.54mm间距排针)
1.配置流程
一般使用ADC功能,都需要有以下几个步骤。
- 配置时钟
- 配置引脚
- 配置ADC模式
- 配置数据对齐方式
- 配置分辨率
- 配置采集通道
- 配置触发方式
- 开启校准
- 使能ADC
1.1 配置时钟
本案例使用ADC0进行操作,需要开启ADC0的时钟。 不过需要注意的是GD32F4的用户手册写出,ADC的最大时钟频率为40MHz。V因此我们使用ADC时,需要将挂载ADC的时钟总线频率分频到40MHz以下。
ADC的时钟来源有AHB(168MHz)和APB2(84MHz),我们需要选择一个时钟源,并将其分频到40MHz以下。
本案例使用的是APB2作为ADC时钟来源,其最大时钟频率为84MHz,我们需要将其分频到40MHz以下。而它分频的参数有2分频、4分频、6分频、8分频等等。如选择2分频,则最终的ADC时钟频率为 84 / 2 = 42MHz,这明显没有达到我们的40MHz以下的要求。选择4分频,最终的ADC时钟频率为:
4分频满足了我们的要求。
1.2 配置引脚
GD32F407VET6一共有16个外部ADC通道,我们将光敏电阻模块的AO引脚连接在PC1引脚上,查找数据手册的引脚定义可知,PC1的附加功能有ADC0的通道11,ADC1的通道11,ADC2的通道11。
因为我们之前配置时钟的章节开启的是ADC0的时钟,所以这里选择PC1的附加功能,ADC0的通道11进行操作。要操作 GPIO 引脚,必不可少的就是对 GPIO 进行配置,包括开启时钟、配置模式、配置输出、设置功能等,还是这一系列的操作。
PC1引脚和ADC0通道11的宏定义如下:
/* PC1 ADC0_IN11 */
#define BSP_ADC_GPIO_RCU RCU_GPIOC
#define BSP_ADC_GPIO_PORT GPIOC
#define BSP_ADC_GPIO_PIN GPIO_PIN_1
/* PC1 ADC0_IN11 */
#define BSP_ADC_RCU RCU_ADC0
#define BSP_ADC ADC0
#define BSP_ADC_CHANNEL ADC_CHANNEL_11
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时钟
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功能时,引脚必须设置为模拟浮空模式,如设置为上拉或下拉模式,则采集的电压是不准确的。
1.3 配置ADC模式
ADC的模式有4种,分别是单次、连续、扫描和间断转换模式。具体的讲解见章节【22.1.2. GD32的ADC介绍】,这里我们配置为扫描模式,这样就可以根据自己的需要,配置采集通道进行依次扫描采集对应引脚的模拟信号。也可以根据需要配置为连续模式和间断模式。
扫描模式配置如下:
//使能扫描模式
adc_special_function_config(BSP_ADC, ADC_SCAN_MODE, ENABLE);
2
GD32还有一个同步模式。只有在具有两个或三个 ADC 的设备上,可以使用 ADC 同步模式。 ADC的同步模式是一种使用相同时钟或者外部同步信号的多路采样模式,以实现多个ADC采样时序的严格同步,从而提高AD转换的精度。比如ADC0和ADC1同时采样。在使用ADC的同步模式时,需要按照正确的顺序配置各种参数和模块进行初始化设置。
而我们使用的是独立模式,独立模式是指ADC使用单独的触发信号进行采样转换,可以被用于单次转换或者轮寻方式下的连续转换。在独立模式下,ADC模块中的各个转换通道之间是独立的,每个 ADC 都独立工作。
我们通常只需要使用独立模式即可。
独立模式配置如下:
//配置ADC为独立模式
adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
2
1.4 配置数据对齐方式
GD32F407VET6微控制器的ADC支持各种数据对齐方式以适应不同的应用场景。常见的数据对齐方式包括左对齐和右对齐。在右对齐模式下,ADC的数据在转换结束后被右对齐到最低位,不足的位数在高位填充0。右对齐模式允许实现在没有精度的损失下更好的动态范围。
在左对齐模式下,ADC的数据被左对齐到最高位,不足的位数在低位填充0。左对齐模式可以提高分辨率,但会导致动态范围降低。
我们配置为右对齐方式,这样我们可以直接将转换完成的数据进行运算。
右对齐方式的配置如下:
//数据右对齐
adc_data_alignment_config(BSP_ADC, ADC_DATAALIGN_RIGHT);
2
1.5 配置分辨率
GD32F407VET6的分辨率可以配置为6、8、10、12 位。我们可以通过降低 ADC 的分辨率,获得较快的转换时间(tADC)。对于那些不需要高精度数据的应用,可以使用较低的分辨率来实现更快速地转换。
这里我们配置为12位分辨率。分辨率的配置如下:
//ADC0设置为12位分辨率
adc_resolution_config(BSP_ADC, ADC_RESOLUTION_12B);
2
1.6 配置采集通道
我们需要配置的是使用的通道和采集通道个数。这里我们使用的是常规通道组,并且只需要转换一个通道。后续需要采集多个通道时,只需要修改采集的通道即可。
采集通道的配置如下:
//ADC0设置为规则组 一共使用 1 个通道
adc_channel_length_config(BSP_ADC,ADC_ROUTINE_CHANNEL, 1);
2
1.7 使能ADC
ADC配置好之后并不能开始工作,还需要去使能,就是相当于有一个开关可以打开关闭。需要注意的是要先使能了ADC之后,才能开始进行自校准。
//ADC0使能
adc_enable(BSP_ADC);
2
1.8 配置触发方式
触发的方式有两种,分别是外部触发方式和软件触发方式。 其中外部触发输入的上升沿、下降沿可以触发规则组或注入组的转换。具体见GD32F4用户手册的第271页。需要注意的是可以实时修改外部触发选择,在修改期间不会出现触发事件。
软件触发方式是由软件触发启动,通常用在单次采样转换中。在软件触发模式下,ADC转换工作被触发后,由软件控制以固定的时间间隔进行转换,因此通常用于采集时间不太关键,但要求精度较高的应用。
这里选择的是软件触发方式,软件触发方式的配置如下:
//ADC外部触发禁用, 即只能使用软件触发
adc_external_trigger_config(BSP_ADC,ADC_ROUTINE_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
//使能软件触发
adc_software_trigger_enable(BSP_ADC, ADC_ROUTINE_CHANNEL);
2
3
4
1.9 开启校准
ADC 带有一个前置校准功能。在校准期间,ADC 会计算一个出厂校准系数,这个系数是应用于 ADC 内部的,它直到 ADC 下次掉电才无效。在 A/D 转换前应执行校准操作。在校准期间,应用不能使用 ADC,它必须等到校准完成。通过软件设置 CLB=1 来对校准进行初始化,在校准期间CLB 位会一直保持 1,直到校准完成,该位由硬件清 0。可以直接使用库函数调用校准,完成操作。
开启校准的配置如下:
//开启ADC自校准
adc_calibration_enable(BSP_ADC);
2
3
这个函数使能ADC,有一个参数,就是要使能的ADC。
最终的ADC全部配置参数如下:
void bsp_adc_init(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(BSP_ADC, ADC_SCAN_MODE, ENABLE);
//配置ADC为独立模式
adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
//数据右对齐
adc_data_alignment_config(BSP_ADC, ADC_DATAALIGN_RIGHT);
//ADC0设置为12位分辨率
adc_resolution_config(BSP_ADC, ADC_RESOLUTION_12B);
//ADC0设置为规则组 一共使用 1 个通道
adc_channel_length_config(BSP_ADC,ADC_ROUTINE_CHANNEL, 1);
//ADC0使能
adc_enable(BSP_ADC);
//ADC外部触发禁用, 即只能使用软件触发
adc_external_trigger_config(BSP_ADC,ADC_ROUTINE_CHANNEL,EXTERNAL_TRIGGER_DISABLE);
//使能软件触发
adc_software_trigger_enable(BSP_ADC, ADC_ROUTINE_CHANNEL);
//开启ADC自校准
adc_calibration_enable(BSP_ADC);
}
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
2. 采集转换
我们之前使用的是扫描模式并使用的是软件触发方式,因此当我们要采集信号时,需要配置好采集通道并开启软件转换。开启转换后,等待EOC标志位置1。其中EOC为转换完成标志位,我们可以通过判断其是否置1,确定是否转换完成。转换完成后将数据从16位寄存器中取出。
/**********************************************************
* 函 数 名 称:Get_ADC_Value
* 函 数 功 能:读取ADC值
* 传 入 参 数:ADC_CHANNEL_x=要采集的通道
* 函 数 返 回:测量到的值
* 作 者:LC
* 备 注:默认采样周期为15个ADC采样时间
**********************************************************/
unsigned int Get_ADC_Value(uint8_t ADC_CHANNEL_x)
{
unsigned int adc_value = 0;
//设置采集通道
adc_routine_channel_config(BSP_ADC, 0, ADC_CHANNEL_x, ADC_SAMPLETIME_15);
//开始软件转换
adc_software_trigger_enable(BSP_ADC, ADC_ROUTINE_CHANNEL);
//等待 ADC0 采样完成
while( adc_flag_get(BSP_ADC, ADC_FLAG_EOC) == RESET )
{
}
//读取采样值
adc_value = adc_routine_data_read(BSP_ADC);
//返回采样值
return adc_value;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3. 实验现象
在main.c中调用unsigned int Get_ADC_Value(uint8_t ADC_CHANNEL_x);函数,采集PC1引脚的电压,并通过串口输出。
int main(void)
{
board_init();
bsp_uart_init();
uint16_t value = 0;
bsp_adc_init();
while(1)
{
value = Get_ADC_Value(BSP_ADC_CHANNEL);
printf("value = %d\r\n", value );
printf("voltage = %f V\r\n", value / 4095.0 * 3.3 );
delay_ms(500);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在灯光充足的情况下,ADC转换的值大约为4000左右,转换为实际电压接近3.3V。
当用手挡住光敏电阻后,采集到的值大约在60左右,转换为实际电压接近0V。
如果没有光敏电阻,则可以连接到3.3V或者GND进行测试。当接入3.3V时采集到的值接近4095;当接入GND时,采集到的值接近0。
完整代码下载:
文件下载
在下载中心
的入门手册资料百度网盘链接中软件资料
-> 代码例程
里面下载!