You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6.2 KiB

1. ADC

1.1. ADC基本原理

什么是ADCAnalog-to-Digital Converter模拟信号转换为数字信号通过测量模拟信号的电压把电压值转换成数字进行后续的操作。

ADC的本质是通过测量电压值来获得被测信号的电压幅值并保存成一个数值。通过这种机制不仅可以测电压还可以测电阻、电容、电感、压力、温度等只要这些被测量通过一个传感器可以和电压之间产生某种函数关系。

对电压进行测量后保存到的有效数据的位数被叫做精度例如8位精度可以有256个值10位精度的有1024个值该MCU的ADC精度是12位的有4096个值

另外ADC中还有个重要的概念叫做参考电压也就是测量电压的基准。在该芯片中内部基准电压叫做 Vrefint经查阅资料应该是2.048V也就是说ADC最高能检测的电压是2048V。如果按照12位精度采样那得到的分辨率是0.0005V。

问题如果电压高于2.048V应该如何进行检测?

image-20241013171356277

以上是ADC的内部框图我们关注主要的是Vref、GPIO、ADC中断、DMA请求、ADCCLK。目前我们使用内部基准通过GPIO采集电压然后使用轮询模式读取电压值。其他方式还包括中断方式和DMA方式。

开发板内部有两个ADC的测试

image-20241013171711301

一个是温度热电偶,另外一个是电位器。具体使用我们在后面说明。

扩展阅读:

ADC原理

1.2. PCM

PCM是一种通过波形幅值测量和对信号进行数字化的一种方案

image-20241013172118023

PCM视频讲解

模拟信号通过间隔时间采样得到每个点的幅值然后进行保存和处理。计算机中常见的wav格式就是PCM采样后的文件。衡量PCM的指标有两个采样率和精度ADC精度。一般采样率越高越好信号的失真越小但是存储的空间越大。一般来说采样率不能低于最高频率的两倍因此以前常见的音频采样率是44k声音最高20k目前还有96k以上的高保真。

1.3. 实例NTC温度测试

任务描述通过NTC测量环境温度并通过串口打印出来。

NTC 又叫热敏电阻温度的变化会改变其电阻值。通过这一特性结合ADC就可以测量温度。

开发版的NTC是如下电路

image-20241013183636425

是接在PA4上面的一个电阻通过10K的R6形成分压等效电路如下 alt text

当NTC的电阻值变化的时候PA4这个分压点检测到的电压会随之变化。当对这个电压进行ADC转换后可以反向计算NTC的电阻值然后根据NTC的电阻和温度的关系可以计算出温度。

NTC是附件与开发板这样连接

ad78bbf910c2747701476e350990a89

1.3.1. 配置

在引脚配置中选择PA4然后选择ADC1_IN4

image-20241013185308417

设置ADC参数

image-20241013191944257

Continuous Conversion Mode设为Enable使ADC转换持续进行不需要每次获取之前手动触发转换ADC_Regular_ConversionMode -> Rank -> Sampling Time设为239.5 Cycles最长采样时间可以获得更稳定的转换结果。

打开串口2

在菜单project Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU Settings勾选Use float with printf ...

image-20241013192823116

这样printf就可以打印小数。

1.3.2. 代码编写

在 inc 目录新建一个头文件 NTC.h因为后面还会使用到NTC的一些功能

#ifndef INC_NTC_H_
#define INC_NTC_H_

#include "main.h"
#include "math.h"

extern float NTC_Temperature;

float ADC2Resistance(uint32_t adc_value);
float resistance2Temperature(float R1);

#endif /* INC_NTC_H_ */

在 src 目录新建 NTC.c 文件这个文件是NTC转换成温度的一些函数。

/**
 * @brief 通过ADC值计算NTC电阻
 *
 * @param adc_value ADC原始值 [0, 4095]
 * @retval 返回NTC电阻值浮点数类型单位Ω
 */

#include "NTC.h"

float NTC_Temperature;

float ADC2Resistance(uint32_t adc_value) {
	return (adc_value / (4096.0f - adc_value)) * 10000.0f;
}
/**
 * @brief 通过NTC电阻反推温度
 *
 * @param R1 NTC电阻值
 * @retval 返回温度float类型单位摄氏度
 */
float resistance2Temperature(float R1) {
	float B = 3950.0f;
	float R2 = 10000.0f;
	float T2 = 25.0f;
	return (1.0 / ((1.0 / B) * log(R1 / R2) + (1.0 / (T2 + 273.15))) - 273.15);
}

以下是 main.c文件的内容

在 USER CODE BEGIN Includes 代码段引入头文件

/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "NTC.h"
/* USER CODE END Includes */

在 USER CODE BEGIN 2 代码段加入如下内容:

	/* USER CODE BEGIN 2 */
	char send_buf[50] = { 0 };
	uint16_t adc_result = 0;
	float ntc_resistance = 0.0f;
	float temperature = 0.0f;
	HAL_ADC_Start(&hadc1);		// 开始连续ADC转换
	HAL_Delay(500);				// 等待ADC稳定

	/* USER CODE END 2 */

完善主函数的循环:

/* USER CODE BEGIN WHILE */
	while (1) {

		adc_result = HAL_ADC_GetValue(&hadc1); // 获取ADC值
		ntc_resistance = ADC2Resistance(adc_result); // 获取ADC值
		temperature = resistance2Temperature(ntc_resistance); // 获取ADC值
		sprintf(send_buf, "阻值%.1f Ω,温度: %.2f ℃\r\n", ntc_resistance,
				temperature); // 将变量打印为字符串
		HAL_UART_Transmit(&huart2, (uint8_t*) send_buf, strlen(send_buf), 10); // 通过串口2发送
		HAL_Delay(1000);
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */

1.3.3. 代码分析

2. I2C

I2C 温湿度传感器