ZZZ-22-制作简易变送器

本篇继 [[ZZZ-21-串口通讯+VOFA]],这节学习制作“数字式压力变送器”的雏形

在 CEMS(烟气在线监测系统)中,几乎所有的流量计、压力变送器和氧分析仪都使用 4-20mA 电流环 协议。[[ZZZ-21-串口通讯+VOFA]] 中实现在在 VOFA 中电压图形的输出,这里我们继续沿用它的单片机配置

1. 模拟方案设计

虽然我们手头没有真实的电流传感器,但我们可以通过数学模拟:

  • 硬件模拟:假设你在 ADC 引脚上接了一个 150Ω 的采样电阻(工业常用值)。
  • 电压区间:
    • 4mA 对应电压:$4mA \times 150\Omega = 0.6V$
    • 20mA 对应电压:$20mA \times 150\Omega = 3.0V$
    • 0.6V ~ 3.0V 就是我们的“有效工作区”。
    • 低于 0.5V(约 3.3mA):判定为传感器断线。

2. 核心算法实现

硬件:USB 转 TTL 模块;两个传感器:一个电位器(方便调节),一个随便什么模拟输出量传感器

我们将之前的代码升级,加入电流换算、压力转换(假设量程 0-1.6MPa)以及报警逻辑。

1
2
3
4
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
1
2
3
4
5
6
/* USER CODE BEGIN PV */
#define SAMPLES 10  // 每个通道采样 10 次
#define CHANNELS 2 // 共 2 个通道

uint16_t adc_buffer[SAMPLES * CHANNELS]; // 长度为 20 的数组
/* USER CODE END PV */

注意这里规定了压力传感器的量程 0-1.6 MPa

1
2
3
4
5
6
7
8
9
  /* USER CODE BEGIN 1 */
  static float filter_volt_A = 0.0f;
  const float alpha = 0.15f; // 滤波系数,你可以尝试修改这个值观察 VOFA+ 上的变化
  const float R_SAMPLE = 150.0f;    // 采样电阻 150 欧
  const float P_MAX = 1.6f;         // 假设压力传感器量程 0-1.6 MPa
  const float I_MIN = 4.0f;         // 工业标准 4mA
  const float I_MAX = 20.0f;        // 工业标准 20mA
  const float I_FAULT = 3.6f;       // 断线阈值 3.6mA(通常 4mA 以下即报警)
  /* USER CODE END 1 */
1
2
3
4
5
6
7
8
/* USER CODE BEGIN 2 */
// 为了精准,建议先进行 ADC 校准(F1系列特有)
HAL_ADCEx_Calibration_Start(&hadc1);

// 核心命令:启动 ADC + DMA
// 参数:ADC句柄,存储的目标地址,要搬运的数据个数
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, SAMPLES * CHANNELS);
/* USER CODE END 2 */
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  while (1)
  {
  	uint32_t sum_A = 0;
  	uint32_t sum_B = 0;

  	// 1. 计算平均值(作为原始输入值值)
  	for(int i = 0; i < SAMPLES; i++) {
  		sum_A += adc_buffer[i * CHANNELS];
  		sum_B += adc_buffer[i * CHANNELS + 1];
  	}

  	// 计算当前这一刻的原始电压
  	float raw_volt_A = (float)sum_A / SAMPLES * 3.3f / 4095.0f;
  	//这里只用到了一个传感器,传感器B的数据都没有要
  	//float raw_volt_B = (float)sum_B / SAMPLES * 3.3f / 4095.0f;

  	// 2. 核心算法:一阶滞后滤波(只对 A 进行处理作为演示)
  	// 公式:本次输出 = alpha * 本次采样 + (1 - alpha) * 上次输出
  	filter_volt_A = alpha * raw_volt_A + (1.0f - alpha) * filter_volt_A;

  	// --- 1. 获取之前的精准滤波电压 ---
	// (假设你已经用 VREFINT 计算出了 real_volt_A)
	float volt = filter_volt_A;

	// --- 2. 换算为电流 (mA) ---
	float current_mA = (volt / R_SAMPLE) * 1000.0f;

	// --- 3. 换算为物理量 (压力 MPa) ---
	// 公式:Pressure = (Current - 4) * (Max_P / (20 - 4))
	float pressure = (current_mA - I_MIN) * (P_MAX / (I_MAX - I_MIN));
	if (pressure < 0) pressure = 0; // 负数强制清零

	// --- 4. 工业逻辑处理 ---
	int is_fault = (current_mA < I_FAULT) ? 1 : 0; // 断线检测
	int is_high_alarm = (pressure > 1.2f) ? 1 : 0; // 超压报警 (1.2MPa)

	// --- 5. VOFA+ 多维度输出 ---
	// 通道:电流(mA), 压力(MPa), 故障状态(0/1), 报警状态(0/1)
	printf("%.2f,%.3f,%d,%d\n", current_mA, pressure, is_fault, is_high_alarm);

	HAL_Delay(20);

    /* USER CODE END WHILE */

3. 你在 VOFA+ 中会看到什么?

当你转动电位器模拟传感器输出时:

  1. 电流线:你会看到它在 $0 \sim 22mA$ 之间波动。
  2. 压力线:它会严格跟随电流。你会发现,当电流低于 $4mA$ 时,压力变为 $0$。
  3. 故障线 (is_fault):当你把电位器拧到底(模拟断线,电压接近 $0V$)时,这根线会从 $0$ 跳到 $1$。
  4. 报警线 (is_high_alarm):当压力模拟值超过 $1.2MPa$ 时,你会看到一个台阶跳变。

4. 为什么这比单纯测电压更专业?

  • 零点偏移 (Zero Offset):在 CEMS 中,如果传感器显示 $4.01mA$ 而不是 $4.00mA$,我们就需要进行“零点校准”。
  • 故障自诊断:如果系统发现电流是 $0mA$,它不会报错“压力低”,而是报错“传感器断线”。这是工业仪表最基本的鲁棒性要求。
  • 抗噪声:由于你之前已经加了两级滤波,你的压力读数在 VOFA+ 上会非常稳定,即使电流有微小的波动,转换后的压力值依然可以精确到小数点后三位。
Licensed under CC BY-NC-SA 4.0