二十、 ADC光敏电阻实验
1. 模块来源
2. 规格参数
工作电压:3.3-5V
工作电流:1MA
模块尺寸:31.1475 x 14.097mm
输出方式:DO接口为数字量输出 AO接口为模拟量输出
读取方式:ADC
管脚数量:4 Pin(2.54mm间距排针)
3. 接线图
光敏电阻 | 开发板 |
---|---|
AO | PA5 |
DO | PA2 |
GND | GND |
VCC | 3V3 |
4. 配置流程
1.1 配置时钟
本案例使用ADC进行操作,需要开启ADC的时钟。 不过需要注意的是在用户手册中的ADC章节有进行说明。我我们的参考电压使用的是VDDA默认3.3V,所以ADC的最大时钟频率为24MHz。因此我们使用ADC时,需要将挂载ADC的时钟总线频率分频到24MHz以下。
本案例使用的是PCLK作为ADC时钟来源,其时钟频率为64MHz,我们需要将其分频到24MHz以下。而它分频的参数有2分频、4分频、6分频、8分频等等。选择4分频,则最终的ADC时钟频率为:
4分频满足了我们的要求。
1.2 配置引脚
每个ADC都可以共享多达13个外部通道,我们将光敏电阻模块的AO引脚连接在PA5引脚上,查找数据手册的引脚定义可知,PA5的模拟功能是ADC的通道5(用户手册439页)。
因为我们之前配置时钟的章节开启的是ADC的时钟,所以这里选择PA5的附加功能,ADC的通道5进行操作。要操作 GPIO 引脚,必不可少的就是对 GPIO 进行配置,包括开启时钟、配置模式、配置输出、设置功能等,还是这一系列的操作。
GPIO配置:
/* GPIO配置 */
__RCC_GPIOA_CLK_ENABLE(); // 开启GPIOA时钟
__RCC_ADC_CLK_ENABLE(); // 开启ADC时钟
PA05_ANALOG_ENABLE(); // PA05设定为模拟输入
2
3
4
5
6
7
这里直接使用原厂提供的宏开启GPIOA和ADC的时钟,设定PA05为模拟输入。
1.3 配置ADC
/* ADC配置 */
ADC_InitTypeDef ADC_InitStructure; // ADC初始化结构体
ADC_WdtTypeDef ADC_WdtStructure; // ADC看门狗结构体
ADC_SingleChTypeDef ADC_SingleChStructure; // ADC单通道转换结构体
// 配置ADC初始化结构体
ADC_InitStructure.ADC_OpMode = ADC_SingleChOneMode; //单通道单次转换模式
ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div4; // 时钟频率 = PCLK / 4 = 64MHz / 4 = 16MHz
ADC_InitStructure.ADC_SampleTime = ADC_SampTime5Clk; //5个ADC时钟周期
ADC_InitStructure.ADC_VrefSel = ADC_Vref_VDDA; //VDDA参考电压
ADC_InitStructure.ADC_InBufEn = ADC_BufDisable; //关闭跟随器
ADC_InitStructure.ADC_TsEn = ADC_TsDisable; //关闭内置温度传感器
ADC_InitStructure.ADC_DMAEn = ADC_DmaDisable; //不触发DMA
ADC_InitStructure.ADC_Align = ADC_AlignRight; //ADC转换结果右对齐
ADC_InitStructure.ADC_AccEn = ADC_AccDisable; //转换结果累加不使能
//ADC模拟看门狗通道初始化
ADC_WdtInit(&ADC_WdtStructure);
//配置单通道转换模式
ADC_SingleChStructure.ADC_DiscardEn = ADC_DiscardNull; // 单通道ADC转换结果溢出保存
ADC_SingleChStructure.ADC_Chmux = ADC_ExInputCH5; // 选择ADC转换通道,AIN5:PA05
ADC_SingleChStructure.ADC_InitStruct = ADC_InitStructure; // ADC初始化结构体
ADC_SingleChStructure.ADC_WdtStruct = ADC_WdtStructure; // ADC看门狗结构体
ADC_SingleChOneModeCfg(&ADC_SingleChStructure); // 初始化配置
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
参数说明
- ADC_InitStructure.ADC_OpMode = ADC_SingleChOneMode;: 设置ADC工作模式为单通道单次转换模式,即每次转换只针对一个指定通道,并且转换完成后不会自动进行下一次转换。
- ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div4;: 配置ADC时钟分频因子为4,如果PCLK(外设时钟)为64MHz,那么ADC时钟将被设置为16MHz。
- ADC_InitStructure.ADC_SampleTime = ADC_SampTime5Clk;: 设置采样时间为5个ADC时钟周期,较长的采样时间可以提高转换精度,但会增加转换时间。
- ADC_InitStructure.ADC_VrefSel = ADC_Vref_VDDA;: 选择VDDA(模拟电源电压)作为ADC的参考电压,这是常用的配置,意味着ADC的满量程范围将对应于VDDA的电压。
- ADC_InitStructure.ADC_InBufEn = ADC_BufDisable;: 关闭输入缓冲器(跟随器),在不需要额外驱动能力或增益时使用。
- ADC_InitStructure.ADC_TsEn = ADC_TsDisable;: 禁用内置温度传感器,如果不需要通过ADC读取芯片温度,则应关闭。
- ADC_InitStructure.ADC_DMAEn = ADC_DmaDisable;: 不使用DMA(直接存储器访问)来传输转换结果,适合简单应用或测试。
- ADC_InitStructure.ADC_Align = ADC_AlignRight;: 选择ADC转换结果右对齐,这是大多数应用的默认选择,便于直接读取结果。
- ADC_InitStructure.ADC_AccEn = ADC_AccDisable;: 禁止结果累加功能,每次转换的结果不会与前一次的结果相加。
- ADC_SingleChStructure.ADC_DiscardEn = ADC_DiscardNull;: 在单通道转换模式下,不丢弃任何转换结果,即使发生溢出也保留数据。
- ADC_SingleChStructure.ADC_Chmux = ADC_ExInputCH5;: 选择AIN5(PA05)作为ADC的输入通道,即对连接到PA05引脚的模拟信号进行转换。
1.4 使能ADC
ADC配置好之后并不能开始工作,还需要去使能,就是相当于有一个开关可以打开关闭。需要注意的是要先使能了ADC之后,才能开始进行自校准。
ADC_Enable(); //ADC使能
1.5 ADC转换
ADC_SoftwareStartConvCmd(ENABLE); //启动ADC转换
参数说明
- DISABLE: 如果传递此值,表示禁止软件启动ADC转换。
- ENABLE: 如果传递此值,表示允许软件启动ADC转换。
2. 数据采集
采集数据函数:
/**********************************************************
* 函 数 名 称:ADC_GET
* 函 数 功 能:读取一次ADC值
* 传 入 参 数:无
* 函 数 返 回:测量到的值
* 作 者:LCKFB
* 备 注:
**********************************************************/
uint32_t ADC_GET(void)
{
ADC_SoftwareStartConvCmd(ENABLE); //启动ADC转换
uint32_t adcValue = ADC_GetConversionValue(); // 获取数据
return adcValue;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
运行流程
- 启动ADC转换: 通过调用ADC_SoftwareStartConvCmd(ENABLE)函数,向ADC发送一个软件启动转换的命令。这行代码利用了之前讨论过的函数,确保ADC开始进行模数转换。ENABLE参数指示应该启动转换。
- 获取转换结果: 紧接着,通过调用ADC_GetConversionValue()函数来获取刚刚完成的ADC转换结果。这个函数的具体实现在代码片段中未给出,但它应当是从ADC的相关寄存器中读取最近完成的转换结果。
- 返回结果: 最后,将从ADC得到的数值(adcValue)作为函数的返回值,这样调用者就可以直接使用这个转换后的数字量进行进一步的处理或显示。
数据平均函数:
/**********************************************************
* 函 数 名 称:Get_Adc_Average
* 函 数 功 能:计算得出某个通道给定次数采样的平均值
* 传 入 参 数:times:采集次数
* 函 数 返 回:无
* 作 者:LC
* 备 注:
**********************************************************/
uint32_t Get_Adc_Average(uint8_t times)
{
uint32_t value = 0;
uint8_t t;
for(t=0;t<times;t++)
{
uint32_t temp = ADC_GET(); // 读取ADC的值
if(temp == 0) // 如果值是0,则读取失败,times-1。
{
times--;
continue;
}
value += temp; // 累加数据
delay_ms(5);
}
return value/times; // 平均
}
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
3. 实验现象
在main.c中调用uint32_t Get_Adc_Average(uint8_t times)函数,采集PA5引脚的电压,并通过串口输出。
int32_t main(void)
{
board_init(); // 开发板初始化
uart1_init(115200); // 串口1波特率115200
ADC_Config(); // ADC初始化
while(1)
{
printf("Value = %d\r\n",Get_Adc_Average(10));
delay_ms(1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
在灯光充足的情况下,ADC转换的值大约为4000左右,转换为实际电压接近3.3V。
当用手挡住光敏电阻后,采集到的值大约在1000左右,转换为实际电压接近0.8V。
如果没有光敏电阻,则可以连接到3.3V或者GND进行测试。当接入3.3V时采集到的值接近4095;当接入GND时,采集到的值接近0。
说明
关于这一章节的代码,在立创·地文星CW32F030C8T6开发板资料/第03章软件资料/代码例程/009ADC采集。