12.4 DMA项目:多通道电压采样
# 12.4 DMA项目:多通道电压采样
本实验利用STM32的DMA功能实现三路信号(电位器电压、内部温度传感器、内部参考电压)的高效采集,结合OLED实时显示,减少CPU资源占用。
核心功能:
- DMA传输:自动搬运ADC数据至内存,解放CPU。
- 多通道采集:同步采样外部电压、温度、参考电压。
- 实时显示:OLED动态刷新三路信号数值。
# 1. 建立新工程
① 建立一个新的STM32工程;
② 选择芯片“STM32F103C8T6”;
③ 设置工程的名称为“12 DMA”;
④ 选择SWD调试方式;
⑤ 开启外部高速时钟源并修改主频为72MHz。
# 2. 配置ADC1
① 点击“Pinout&Configuration”标签页;
② 在左侧导航栏中点击“Analog”;
③ 双击“ADC1”进行配置;
④ 启用“IN6”、“Temperature Sensor Channel”和“Vrefint Channel”。

# 3. DMA配置
① 进入“Pinout & Connectivity”标签页; ② 在“System Core”里选择DMA; ③ 点击“Add”; ④ 分别在“DMA Request”选择“ADC1”,在“Channel”选择“DMA1 Channel1”,在“Direction”选择“Peripheral To Memory”,在“Priority”选择“Low”; ⑤ 点击刚添加的“ADC1”设置“Mode”为“Circular”; ⑥设置“Data Width”为“Half Word”并设置“Increment Address”为“Memory”。

# 4. 配置I2C1
参考第9章,使能I²C。
# 5. 生成代码
勾选生成单独外设文件,保存生成工程代码。
# 12.4.2 软件设计
# 1. 引用相应头文件
在“/* USER CODE BEGIN Includes /”与“/ USER CODE END Includes */”注释之间的代码块引用相应头文件,用于调用OLED驱动函数及输入输出库。
/* USER CODE BEGIN Includes */
#include "oled.h"
#include <string.h>
#include <stdio.h>
/* USER CODE END Includes */
2
3
4
5
6
# 2. 定义内部温度传感器校准参数
在“/* USER CODE BEGIN PD /”与“/ USER CODE END PD */”注释之间的代码块定义了内部温度传感器的校准参数,用于后续计算实际温度值。
/* USER CODE BEGIN PD */
// 内部温度传感器的相关校准参数
#define VREFINT_CAL_ADDR 0x1FFFF7BA
#define VREFINT_CAL (*(uint16_t*)VREFINT_CAL_ADDR)
#define V25 1.43f // 单位:V
#define AVG_SLOPE 0.0043f // 单位:V/℃
/* USER CODE END PD */
2
3
4
5
6
7
# 3. 定义相关变量
在“/* USER CODE BEGIN 0/”与“/USER CODE END 0 */”注释之间的代码块定义了一些用于存储ADC数据、转换后物理量、传感器电压以及显示信息的变量。
/* USER CODE BEGIN 0 */
static uint16_t value[3];
static float physical[3];
float vsense = 0.0;
static char message0[30],message1[30],message2[30];
/* USER CODE END 0 */
2
3
4
5
6
# 4. 初始化及启动相关操作
在“/* USER CODE BEGIN 2/”与“/USER CODE END 2 */”注释之间的代码块进行了硬件延时、OLED初始化、ADC校准以及启动ADC的DMA传输等操作。
/* USER CODE BEGIN 2 */
HAL_Delay(50);
OLED_Init();
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)value, 3);
/* USER CODE END 2 */
2
3
4
5
6
# 5. 读取ADC值并显示
HAL_ADC_Start_DMA( )函数的参数为ADC句柄&hadc1和存储ADC值的数组地址,用于启动DMA方式读取ADC转换结果。在main.c文件中找到/* USER CODE BEGIN WHILE */注释块,插入以下代码。
/* USER CODE BEGIN WHILE */
while (1)
{
//电压值转换
physical[0] = (value[0] / 4095.0) * 3.3;
//内部温度传感器数值转换
vsense = (value[1] / 4095.0) * 3.3;
physical[1] = ((V25 - vsense) / AVG_SLOPE) + 25.0f;
//内部参考电压转换
physical[2] = (value[2] / 4095.0) * 3.3;
sprintf(message0,"V:%d %0.2fV",value[0],physical[0]);
sprintf(message1,"T:%d %0.1fC",value[1],physical[1]);
sprintf(message2,"R:%d %0.2fV",value[2],physical[2]);
OLED_NewFrame();
OLED_PrintString(0, 0, message0, &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 20, message1, &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 40, message2, &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(500);
/* USER CODE END WHILE */
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 12.4.3 下载验证
# 现象与步骤
- 硬件连接:
- 电位器接PA6,OLED通过I²C连接。
- 烧录程序:
- 代码烧录后,DMA自动启动三路信号采集。
- 功能验证:
- 旋转电位器,观察电压值变化。
- OLED显示三路数据(示例):
V:3397 2.74V
T:1781 23.8C
R:1528 1.23V
关键说明:
- 温度计算参数:
V25
:25℃时传感器电压(典型值1.43V)。AVG_SLOPE
:温度-电压斜率(典型值4.3mV/℃)。
- 参考电压:用于校准ADC,提高测量精度。
- DMA模式:循环模式确保数据持续更新,避免数据覆盖。