跳到主要内容

06 ADC实验

up的视频讲解

把传感器电压转换成数字,再沿电路关系还原光照、温度与声音的变化。

up视频里的实验代码: 👣ADC实验代码

1 🌡️ 光/热传感器-光照/温度采集实验​

1.1 实验连接​

传感器 AO 接 PA1,串口 PA9 接 CH340 的 RXD,用于观察采样结果。

传感器 AO 接 PA1,串口 PA9 接 CH340 的 RXD,用于观察采样结果。
传感器 AO 接 PA1,串口 PA9 接 CH340 的 RXD,用于观察采样结果。

1.2 实验原理​

NTC 热敏电阻和光敏电阻先把物理量变化转换为阻值变化。分压电路再把阻值变化转换为 AO 电压,ADC 对这个电压采样。

物理量 → 电阻 → 电压 → ADC 结果,测量时顺着这条链路分析。
物理量 → 电阻 → 电压 → ADC 结果,测量时顺着这条链路分析。

读取结果后,先换算电压,再根据分压关系得到电阻,最后根据传感器模型计算温度或光照。每一步都有自己的参数,不能只看最终输出数字。

1.3 CubeMX配置​

选择 ADC1 的通道 1,对应 PA1。本实验只采集一个通道,关闭扫描和连续转换,规则组选择软件触发。

ADC1通道选择

温度和光照变化较慢,选用较长的采样时间,让输入采样电容有充分的充电时间。打开 ADC 中断,使程序能在转换完成后读取结果。

ADC规则组和采样时间
ADC中断配置

再开启 USART1 异步发送,与串口助手保持相同的波特率和帧格式。程序启动一次转换,回调保存结果,主循环发送并重新启动下一次转换。

1.4 实验代码​

全局​

#include <stdio.h>

uint16_t adc_val = 0;
uint8_t flag = 0;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance == ADC1)
{
adc_val = HAL_ADC_GetValue(&hadc1);
flag = 1;
}
}

main()​

HAL_ADC_Start_IT(&hadc1);

while(1)​

if(flag == 1)
{
char buf[64] = {0};
sprintf(buf,"adc_val=%d V_AO=%f\r\n",adc_val,adc_val/4096.0f*3.3f);
HAL_UART_Transmit(&huart1,buf,strlen(buf),1000);
flag = 0;
HAL_ADC_Start_IT(&hadc1);
}

1.5 温度/光照 计算​

沿 ADC 值、电压、电阻和温度的顺序计算,避免跳过中间的电路关系。
沿 ADC 值、电压、电阻和温度的顺序计算,避免跳过中间的电路关系。

下面分别给出温度和光照的计算代码。阅读时先核对固定电阻、标称电阻和模型参数,再看计算公式。光照代码中的经验关系适合观察变化,并不等同于经过标定的照度计。

1.6 温度计算代码​

//==================== NTC热敏电阻参数(B3950‑10K) ====================
#include "math.h"
#define NTC_R_FIX 10000.0f //电路上拉固定电阻R1=10k
#define R25 10000.0f //25℃标称NTC电阻
#define T25 298.15f //25℃开尔文
#define B 3950.0f //B值
#define ADC_MAX 4095.0f
/**
* @brief NTC热敏电阻B值模型计算温度
* @param adc_val: ADC原始采样值,范围0~4095
* @retval 温度值,单位℃
* @note 硬件电路:VCC →10k固定电阻 →AO采样点 →NTC →GND
*/
float NTC_GetTemperature(uint16_t adc_val)
{
// 根据ADC分压换算NTC当前实时电阻
float R_ntc = NTC_R_FIX * adc_val / (ADC_MAX - adc_val);
// NTC B值公式,计算开尔文温度
float invT = 1.0f / T25 + (1.0f / B) * logf(R_ntc / R25);
float T_K = 1.0f / invT;
// 开尔文温度转换为摄氏温度
float T_C = T_K - 273.15f;
return T_C;
}

1.7 光照计算代码​

//==================== GL5528光敏电阻参数 ====================
#include "math.h"
#define LDR_R_FIX 10000.0f //电路上拉固定电阻R1=10k
#define LDR_R10 10000.0f //10Lux时光敏电阻阻值10kΩ
#define LDR_GAMMA 0.7f //GL5528伽马值γ
#define ADC_MAX 4095.0f

/**
* @brief GL5528光敏电阻计算光照度
* @param adc_val: ADC原始采样值,范围0~4095
* @retval 光照度,单位Lux(勒克斯),仅相对值,非计量级精度
* @note 硬件电路:VCC →10k固定电阻 →AO采样点 →LDR →GND
* 公式: Lux = 10 * pow(R10 / Rldr, 1/gamma)
*/
float LDR_GetLux(uint16_t adc_val)
{
// 根据ADC分压换算光敏电阻当前实时电阻
float R_ldr = LDR_R_FIX * adc_val / (ADC_MAX - adc_val);

// 光敏电阻照度‑电阻经验公式,计算环境光照度Lux
float lux = 10.0f * powf( LDR_R10 / R_ldr, 1.0f / LDR_GAMMA );

return lux;
}

2 🎙️ 麦克风- 音频采集实验​

2.1 实验连接​

麦克风输出连接 PA1,串口继续把采样数据送到电脑。

麦克风输出连接 PA1,串口继续把采样数据送到电脑。
麦克风输出连接 PA1,串口继续把采样数据送到电脑。

2.2 实验原理​

麦克风把声音变化转成电压变化,ADC 把不同时刻的电压记录成一串数字。串口助手按顺序绘制这些数字,就得到时域波形。

本实验用定时器安排采样节奏,用 ADC 完成转换,再由主循环输出结果。先观察声音变化与波形的对应关系,后面的 DMA 课程再讨论连续数据的批量搬运。

2.3 CubeMX配置​

使用 TIM3 的更新事件触发 ADC:选择内部时钟,预分频设置为 72 - 1,自动重装载设置为 200 - 1。当定时器时钟为 72 MHz 时,更新频率为 5 kHz。

在 TIM3 的触发输出中选择更新事件,在 ADC 规则组中选择 TIM3 触发。将采样时间设为 7.5 个 ADC 时钟周期,随后重新生成工程。

主程序启动 ADC 等待触发,再启动 TIM3。此时下一次转换由定时器触发,不再由主循环反复软件启动。

串口输出只保留采样数字与换行,串口助手才能按数值绘制波形。这里的 5 kHz 是硬件触发频率;逐点文本发送能保留多少数据,还受到串口速度与程序处理时间影响。

2.4 实验代码​

全局​

#include <stdio.h>

uint16_t adc_val = 0;
uint8_t flag = 0;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance == ADC1)
{
adc_val = HAL_ADC_GetValue(&hadc1);
flag = 1;
}
}

main()​

HAL_ADC_Start_IT(&hadc1);
HAL_TIM_Base_Start(&htim3);

while(1)​

if(flag == 1)
{
char buf[64] = {0};
sprintf(buf,"%d\r\n",adc_val);
HAL_UART_Transmit(&huart1,buf,strlen(buf),1000);
flag = 0;
}