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”。

ADC通道配置

# 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”。

DMA配置

# 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 */

1
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 */
1
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 */
1
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 */
1
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 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 12.4.3 下载验证

# 现象与步骤

  1. 硬件连接
    • 电位器接PA6,OLED通过I²C连接。
  2. 烧录程序
    • 代码烧录后,DMA自动启动三路信号采集。
  3. 功能验证
    • 旋转电位器,观察电压值变化。
    • OLED显示三路数据(示例):
      • V:3397 2.74V
      • T:1781 23.8C
      • R:1528 1.23V
        DMA配置

关键说明

  • 温度计算参数
    • V25:25℃时传感器电压(典型值1.43V)。
    • AVG_SLOPE:温度-电压斜率(典型值4.3mV/℃)。
  • 参考电压:用于校准ADC,提高测量精度。
  • DMA模式:循环模式确保数据持续更新,避免数据覆盖。