|
|
@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
# 1. ADC
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 1.1. ADC基本原理
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
什么是ADC(Analog-to-Digital Converter)?模拟信号转换为数字信号通过测量模拟信号的电压,把电压值转换成数字进行后续的操作。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADC的本质是通过测量电压值来获得被测信号的电压幅值,并保存成一个数值。通过这种机制,不仅可以测电压,还可以测电阻、电容、电感、压力、温度等,只要这些被测量通过一个传感器可以和电压之间产生某种函数关系。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
对电压进行测量后保存到的有效数据的位数被叫做精度,例如8位精度可以有256个值,10位精度的有1024个值;该MCU的ADC精度是12位的,有4096个值;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
另外,ADC中还有个重要的概念叫做参考电压,也就是测量电压的基准。在该芯片中,内部基准电压叫做 Vrefint,经查阅资料应该是2.048V,也就是说ADC最高能检测的电压是2048V。如果按照12位精度采样,那得到的分辨率是0.0005V。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> 问题:如果电压高于2.048V应该如何进行检测?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

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

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一个是温度热电偶,另外一个是电位器。具体使用我们在后面说明。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
扩展阅读:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[ADC原理](https://www.bilibili.com/video/BV1BV4y1V7nE/?spm_id_from=333.337.search-card.all.click&vd_source=3c8e333d6657680a469ddf0238f01d6a)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 1.2. PCM
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PCM是一种通过波形幅值测量和对信号进行数字化的一种方案:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[PCM视频讲解](https://www.bilibili.com/video/BV1yb4y1M7a2/?spm_id_from=333.337.search-card.all.click&vd_source=3c8e333d6657680a469ddf0238f01d6a)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
模拟信号通过间隔时间采样得到每个点的幅值,然后进行保存和处理。计算机中常见的wav格式就是PCM采样后的文件。衡量PCM的指标有两个:采样率和精度(ADC精度)。一般采样率越高越好,信号的失真越小,但是存储的空间越大。一般来说,采样率不能低于最高频率的两倍,因此以前常见的音频采样率是44k(声音最高20k),目前还有96k以上的高保真。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 1.3. 实例NTC温度测试
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
任务描述:通过NTC测量环境温度,并通过串口打印出来。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTC 又叫热敏电阻,温度的变化会改变其电阻值。通过这一特性,结合ADC就可以测量温度。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
开发版的NTC是如下电路:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

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

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
当NTC的电阻值变化的时候,PA4这个分压点检测到的电压会随之变化。当对这个电压进行ADC转换后,可以反向计算NTC的电阻值,然后根据NTC的电阻和温度的关系可以计算出温度。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTC是附件,与开发板这样连接:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1.3.1. 配置
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在引脚配置中,选择PA4,然后选择ADC1_IN4;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
设置ADC参数:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这样printf就可以打印小数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1.3.2. 代码编写
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在 inc 目录新建一个头文件 NTC.h,因为后面还会使用到NTC的一些功能;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```h
|
|
|
|
|
|
|
|
#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转换成温度的一些函数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @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 代码段引入头文件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
|
|
/* USER CODE BEGIN Includes */
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "NTC.h"
|
|
|
|
|
|
|
|
/* USER CODE END Includes */
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在 USER CODE BEGIN 2 代码段加入如下内容:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
完善主函数的循环:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
|
|
/* 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 温湿度传感器](https://www.bilibili.com/video/BV1QN411D7ak/?spm_id_from=333.788&vd_source=3c8e333d6657680a469ddf0238f01d6a)
|