基于STM32的高精度智能压力变送器
本文介绍了一个具有就地显示功能、RS485串口通信功能、4-20mA线性标准化电流输出功能的压力变送器仪表的设计。该仪表量程为0-1MPa,精度在1级以内,且具有配套的基于MFC的上位机软件。
硬件选型与设计
测量部分
压力传感器
压力的测量使用了MPM280
型压阻式压力传感器,它的耐压范围为0-2MPa
,低压参考端通大气,测得的压力为表压。MPM280
可以将气压信号转化为应变片的形变。MPM280
为全桥接法,通过给全桥一个恒定且稳定的电压激励,便可以生成电压模拟信号供电路采集。
压力的生成使用了实验室提供的斯贝克SPMK2000E
高压气体压力源,它自带一个高精度的量程为0-2MPa的标准表,同时提供了两个接入压力表的接口,通过压杆可以向装置内打气,并通过螺杆精密产生压力。
ADC芯片
HX711
是一款高精度的24
位A/D转换器芯片,该芯片集成了包括稳压电源、片内时钟振荡器等电路。利用HX711
可以将全桥输出的微小模拟信号转化成为24位的数字信号,并由单片机进行读取,后经过单片机内部程序,通过标定的数值,将ADC读数转换为压力值。
HX711
内置输入选择开关与2个通道,可任意选取通道A或通道B与其内部的低噪声可编程放大器相连。通道A的可编程增益为128或64,对应的满额度差分输入信号幅值分别为±20mV或±40mV。通道B则为固定的32增益。芯片内提供稳压电源,可直接向外部传感器和芯片内的A/D转换器提供电源。
压力传输与显示
就地显示与上位机连接
就地显示使用了工业中常用的LCD1602
液晶显示屏,用于实时显示当前的压力值。
工业仪表常常使用RS485
电平来进行强抗干扰的低速通信。本设计同样使用RS485
电平将压力表与上位机连接。仪表使用一块MAX485
芯片,将单片机的TTL
电平转换为RS485
电平。上位机使用常见的USB转TTL模块,并通过TTL
-RS485
转换模块将电平转换为RS485
电平。
4-20mA远传部分
在信号远传中,若不使用电流传输方式而是电压传输方式,被传输的信号将会容易受到导线电阻的影响,这会对传输精度造成影响。因此,本设计使用通用的4-20mA
电流信号来传输压力值。当电流为4mA
时,代表压力为0Pa
,电流为20mA
时,代表压力为最大量程1MPa
。
单片机将传感器产生的模拟信号转换成数字信号后才能处理,因此需要利用高精度DA芯片将数字信号重新转换为模拟信号才能够转换为模拟电流。本设计使用高精度12位DAC芯片TLC5615
,产生可调的电压信号,并经由电流环电路,产生4-20mA
线性标准化的电流信号。
XTR115
是单片4-20mA
电流信号两线变送器。它提供了完整的电桥激励、传感器线性化和电流输出电路,可利用VREG脚从附加的外部输入电路提供电流。
下面列为整个系统的信号转化流图。
电路的设计
变送器的整体原理图如下图所示。PDF版的高清原理图可在文末链接中下载。
软件设计
上位机设计
串口接收到的数据的处理
在处理串口接收数据的时候,首先注册了串口数据接收的事件函数,当串口接收到有效数据时事件函数会被执行。在接收事件函数中,首先获取串口接收到的数据,并将数据转换为字节数组以便后续处理。接着,在事件函数内会调用数据的处理函数,这个函数内包含数据包的CRC校验与数据每一帧的解析与存储,并且会根据所选择的小数格式来读取浮点型小数。
串口相关的所有函数都被设置在了一个窗口内,这个窗口包含串口控件的初始化、消息处理函数、参数设置以及打开关闭串口等菜单的功能。这个窗口中的定时器负责周期性采集传感器数据,并使用其中的串口接收事件函数来获取数据,并对数据进行处理,将处理之后的数据存储到数据存储结构体内,同时显示到窗口上的文本框中。
Modbus通信协议
Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议。通过此协议,控制器相互之间、或控制器经由网络可以和其它设备之间进行通信。Modbus协议使用的是主从通讯技术,即由主设备主动查询和操作从设备。Modbus通讯物理接口可以选用串口(包括RS232和RS485),也可以选择以太网口。
Modbus协议的数据包主要分为四部分:设备地址、功能代码、数据与校验值。对于本次计算机与压力表的通信来说,计算机就是主机,负责向压力表查询数据;而压力表相当于从机,相应主机的查询请求并返回对应的数据。主机发送的命令基本结构如下:
字节 | 0x01 | 0x03 | 0x13 | 0xBA | 0x00 | 0x0F | 0x20 | 0xAF |
---|---|---|---|---|---|---|---|---|
意义 | 设备地址 | “读”功能代码 | 目标寄存器起始地址高位 | 目标寄存器起始地址低位 | 读取字节数高位 | 读取字节数低位 | CRC校验码低位 | CRC校验码高位 |
从机回复的数据包结构如下:
字节 | 01 | 03 | 0A | 00 00 00 00 | 00 00 00 00 | 00 00 | xx xx |
---|---|---|---|---|---|---|---|
意义 | 设备地址 | “读”功能代码 | 返回数据长度(int) | 压力(float) | 温度(未使用,float) | 状态(int) | CRC校验码高低位 |
实际Modbus应用时,一个总线往往并联数个仪表,因此每个仪表需要有自己唯一的地址,主机查询数据的时候,仪表需要根据自身地址确定是否响应请求,同时根据CRC校验的结果确定数据包是否有效。一旦确定数据包有效,即根据主机请求的数据地址,返回相应的数据。
定时采集并显示压力参数曲线
串口相关的代码都放在了串口控制面板这一个窗口类之中。在这个窗口类中,通过打开串口的按钮,设定了一个定时器,在这个定时器的事件函数中,控制串口向压力表发送查询压力函数;压力表接收到查询指令后返回数据包,触发串口的接收事件函数,在接收事件函数内,对数据包进行解包处理,并将数据更新到结构体内保存以及显示到文本框中。 程序在解析数据包的过程中,首先验证CRC校验码。如果校验失败则丢弃数据包,如果验证成功,则接收数据包,并根据数据包中每一个数据的位置,使用浮点数转换函数,将16进制数据转换为正确的浮点数。
单片机主控程序设计
单片机采用STM32F103C8T6
。单片机首先设置HX711
ADC与TLC5615
的采样周期与时钟周期,然后循环读取数据,并通过参考电压换算公式转换为模拟电压信号,同时使用RS485
接口,使用与上位机匹配的Modbus
协议进行数据传输。
ADC采集与量化
ADC的作用是将传感器的输出端电压转化为数字信号,通过量化、拟合得到相应的气压值。HX711
采集到的数据是24位的。由于电压传感器输出端输出的电压值变换范围不够大,因此需要编程设置ADC在采集时使用B通道并采用32
倍增益采集。
作为压阻式传感器,其与气压的对应关系并非是完全线性的,存在一定的非线性误差;且需要确定其灵敏度和零点值,所以需要对ADC读数进行标定与多项式拟合。通过拟合,得出如下使用三次曲线的拟合结果。
y = 0.00000000000000000116 x^3 - 0.00000000000000750175 x^2 + 0.00000770572583981333 x - 0.00105882952018538000
通过三次曲线拟合,使个别点的相对误差降低到0.1%,基本消除了传感器与检测电路的非线性误差,保证了变送器的精度,得到了ADC读数与气压值的精确对应关系。
主程序
下面为单片机程序的主函数部分。主函数首先对各个外设进行初始化,然后进入主循环。在主循环中,程序首先读取ADC的值,然后使用最近8次的读数进行平均以降低误差和抖动。接下来,使用拟合公式,将ADC读数转换为压力值,并分别使用LCD显示、发送到上位机和使用DAC输出对应的电流。
int main(void)
{
char str[20];
int val;
float pressure;
delay_init();
uart_init(9600);
HX711_Init();
LCD1602_Init();
TLC5615_Init();
LED_KEY_BUZZ_Init();
while(1)
{
HX711_data[HX711_dataIndex] = HX711_Read()>>5;//读取AD数据 舍弃低5位
HX711_dataIndex ++;
if(HX711_dataIndex >= HX711_DATA_SIZE)
HX711_dataIndex = 0;
val = getAverage(HX711_data,HX711_DATA_SIZE);//将最近的8次数据平均 提高稳定性
pressure = getPressure(val);//根据公式拟合气压值
sprintf(str,"%6.3fMPa",pressure);
LCD1602_ShowStr(0,3,str);//使用LCD屏幕就地显示
memcpy(modbusData+3,(void*)&pressure,4);//ModBus总线数据
transmitterOutput(pressure,1);//使用DAC输出电流 参数为当前压力值与最大压力值
}
}
下面的代码主要包括了对数据进行平均值处理和根据ADC读数拟合气压值的函数。
#define HX711_DATA_SIZE 8
int32_t HX711_data[HX711_DATA_SIZE];
uint8_t HX711_dataIndex = 0;
void transmitterOutput(float outData,float maxData)
{
float ma = 4 + outData / maxData * (20-4);//换算变送器数值
TLC5615_Update(ma/20*1023);//将4-20ma换算为电压值
}
int32_t getAverage(int32_t* dat,uint8_t num)
{
uint8_t i;
int32_t sum = 0;
for(i = 0;i < num;i ++)
{
sum += dat[i];
}
return sum / num;
}
double getPressure(double x)//根据公式拟合气压值
{
return
0.00000000000000000116 * pow(x,3)
- 0.00000000000000750175 * pow(x,2)
+ 0.00000770572583981333 * pow(x,1)
- 0.00105882952018538000 * pow(x,0);
}
实验结果
测试现场布置如下图。
下图中展示了电路板的各个模块。引出了用于连接压力传感器全桥的4个引脚和4-20mA
电流输出的2个引脚。左下部是LCD1602
显示模块,中间为STM32
最小系统、TCL5615
模块、HX711
模块和XTR115
模块。
下图为校验现场的实测压力。可以看到上图中的就地显示值与下图中标准表的显示几乎一致,且对应的4-20mA输出值换算至压力的误差也很低。
与此同时,上位机软件通过RS485总线与变送器通信,可以实时获取当前压力值并显示在屏幕上,并绘制成曲线图。