4-20ma液位传感器在工业自动化和日常应用中非常常见,例如水位监测、液体储罐管理等。本文将结合STM32 HAL库,带你实现一个简单的液位监测demo,从电路设计到代码实现,实现通过单通道ADC采集4-20ma液位传感器的信号,并通过串口将采集到的液位百分比打印输出。具体流程包括:通过分压电阻将获得4-20ma液位传感器的分压电压,再利用运算放大器LM2904对信号进行放大,随后将信号输入STM32的ADC2模块读取通道6(对应引脚PA6)。最终,处理后的液位百分比数据通过串口1发送至串口助手进行实时显示。
目录
[2.4液位百分比为 22%的换算](#2.4液位百分比为 22%的换算)
[2.液位百分比为 22%的测试验证](#2.液位百分比为 22%的测试验证)
一、开发环境
硬件:自己搭建采样电路
单片机:STM32F407ZGT6
Keil版本:5.32
STM32CubeMX版本:6.9.2
STM32Cube MCU Packges版本:STM32F4 V1.27.1
二、4-20ma投入液压式液位传感器
4-20ma投入液压式液位变送器(下面称液位传感器)采用高性能的扩散硅压阻式压力传感器作为测量元件,经过高可靠性的放大处理电路及精密温度补偿,将被测介质的表压或绝压转换为标准的电压或电流信号。本产品体积小巧,使用安装方便,直接投入水中即可测量出变送器末端到液面的液位高度。接线方式:一共两条线,红色接到DC正极,另外一根接到FL端子处.
三、硬件电路
1.设计思路
4-20ma投入液压式液位变送器里面的压阻式压力传感器,经分压电路生成电压信号,信号经LM2904放大后输入MCU的ADC口。对于单片机来说,只能知道ADC引脚口的电压,知道电压再反推液位传感器的电流,再通过查4-20ma与液位曲线表来确定此时的液位高度百分比。
LM2904内部包括有两个独立的、高增益、内部频率补偿的双运算放大器。不经过LM2904运算放大器直接输入STM32的ADC可能会导致信号幅度不足、信号质量下降、ADC输入阻抗不匹配以及系统稳定性和可靠性降低等问题。因此,在大多数情况下,建议使用运算放大器LM2904来放大和调理传感器信号,以确保输入到ADC的信号具有足够的幅度、清晰度和稳定性。
2.电阻分压与增益计算:
通过电阻分压比和LM2904增益计算电压。S+5v的电压是V0,R74和R69、R75并联后的总电阻记为Rzfl,V1,V2,V3,V4所在点的电压值.IR74为R74的电流.IR66_4K99为R66_4K99的电流.I(R75_6K8+R69_10K0)为流经R75_6K8和R69_10K0的电流.I(R74_R75_R69)为流经R74_0K150和R75_6K8和R69_10K0总电流,Ifl为液位传感器的电流。
2.1基本公式与定义
1>根据并联电阻计算公式1/R总=1/R1+1/R2推导出,R2=(R总*R1)/(R1-R总),对应到电路图的标识如下
1/Rzfl=1/R74_0K150+1/(R75_6K8+R69_10K0)
Rzfl=148.7Ω
2>根据串联电阻分压原理R1/R2=U1/U2=(U-U2)/U2,推导出R2=R1*U2/(U-U2),对应到电路图的标识如下
Rzfl=R66_4K99*V1/(V0-V1)
3>V1=V0*R74_0K150/(R66_4K99+R74_0K150)
4>V2=V1*R75_6K8/(R75_6K8+R69_10K0)
通过计算电阻分压比和LM2904的增益,可以准确计算出ADC引脚口的电压。
5>V3=V4=V2*(1+R63_6K8/R67_10K0)
6>V4=V0*R74_0K150/(R66_4K99+R74_0K150)*R75_6K8/(R75_6K8+R69_10K0)*(1+R63_6K8/R67_10K0)=0.68*V1
7>对于4mA至20mA的线性电流输出类型,电流与液位之间的关系是线性的。计算公式可以表示为:
I = (液位/量程) × (20mA - 4mA) + 4mA 其中:I 是输出电流;液位是当前测量的液位高度;量程是液位传感器能够测量的最大液位高度。I = (液位/量程) × (20mA - 4mA) + 4mA
4mA对应液位为0%(即液位最低点)
20mA对应液位为100%(即液位最高点)
那么,电流(I,单位为mA)与液位百分比(P,单位为%)之间的关系可以表示为:
P=(I−4)/(20−4)×100%=(Ifl−4)/16×100%
2.2不接传感器(开路)时的电压计算
V0=5.3V,
V4=V0*R74_0K150/(R66_4K99+R74_0K150)*R75_6K8/(R75_6K8+R69_10K0)*(1+R63_6K8/R67_10K0)=0.105V
2.3液位百分比为0%的换算
如果用液位传感器在0%下测试时,此时的电流约3.98ma,ADC口的电压486mv。
对应的电阻电流电压数据如下:
V0=5.3V
V4=V3=0.486V
V2=V3/(1+6800/10000)=V3/1.68=0.29V
V1=V4/0.68=V2*(R75_6K8+R69_10K0)/R75_6K8=V2*(R75_6K8+R69_10K0)/R75_6K8=V2*2.47=0.716V
IR74=V1/(R74_0K150)=0.716/150=4.8ma
IR66_4K99=(V0-V1)/R66_4K99=(5.3-0.716)/R66_4K99=0.9ma
I(R75_6K8+R69_10K0)=(V0-V1)/(R75_6K8+R69_10K0)=(5.3-0.716)/(R75_6K8+R69_10K0)=0.017ma
IRzfl=V1/Rzfl=(5.3-0.716)/148.7Ω
Ifl=IR74+I(R75_6K8+R69_10K0)-IR66_4K99=4.8ma+0.017ma-0.9ma=3.92ma
液位百分比P=(I−4)/(20−4)×100%=(3.92−4)/16×100%=0%
2.4液位百分比为 22%的换算
如果用液位传感器在22%下测试时,此时的电流约7.49ma,ADC口的电压884mv。
对应的电阻电流电压数据如下:
V0=5.3V
V4=V3=0.834V
V2=V3/(1+6800/10000)=V3/1.68=0.496V
V1=V4/0.68=V2*(R75_6K8+R69_10K0)/R75_6K8=V2*(R75_6K8+R69_10K0)/R75_6K8=V2*2.47=1.226V
IR74=V1/(R74_0K150)=1.226V/150Ω=8.17ma
IR66_4K99=(V0-V1)/R66_4K99=(5.3V-1.226V)/R66_4K99=0.816ma
I(R75_6K8+R69_10K0)=(V0-V1)/(R75_6K8+R69_10K0)=(5.3V-1.226V)/(R75_6K8+R69_10K0)=0.242ma
Ifl=IR74+I(R75_6K8+R69_10K0)-IR66_4K99=8.17ma+0.242ma-0.816ma=7.6ma
液位百分比P=(I−4)/(20−4)×100%=(7.6−4)/16×100%=22%
四、配置STM32CubeMX
-
启动STM32CubeMX,新建STM32CubeMX项目:
-
选择MCU:在软件中选择你的STM32型号-STM32F407ZGT6。
-
选择时钟源:
-
配置时钟:
-
使能Debug功能:Serial Wire
-
HAL库时基选择:SysTick
-
USART1配置:选择异步模式。
-
开启外部时钟:配置系统时钟,确保ADC和串口的外部时钟已开启。
-
配置ADC:
1)选择ADC2作为采集模块。
2)设置AD2的通道6(对应引脚PA6)为采集通道。
3)配置采样时间和分辨率。通常,采样时间越长,ADC的转换精度越高,但也会增加转换时间。
4)禁用扫描模式,因为我们只采集一个通道。
10.配置工程参数:在Project标签页中,配置项目名称和位置,选择工具链MDK-ARM。 11.生成代码:在Code Generator标签页中,配置工程外设文件与HAL库,勾选头文件.c和.h文件分开,然后点击Project > Generate Code生成代码。
五、代码实现与部署
-
main.c增加代码:main.c的第1行添加printf的头文件#include<stdio.h>,在 while(1)里增加数行代码。ADC电压换算时用到公式:待测电压=(ADC的返回值/4095)∗3.3V.具体参考附件的完整代码。
cpp/* USER CODE BEGIN 0 */ uint16_t adc_value = 0; float adc_voltage_value = 0; float input_voltage_value = 0; char buffer[30]; #define R_0K150 150 //分压电阻值150 #define R_4K99 4990 //分压电阻值4.99K #define R_6K80 6800 //分压电阻值6.80K #define R_10K0 10000 //并联电阻值10.0K #define SENSOR_VDD 5303 //分压输入源 float Rzfl=148.67; //总电阻值 R74和R69、R75并联后的总电阻记为Rzfl float V1; //R74的分压电压 float Ifl; //液位传感器的电流 float percent; /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_ADC1_Init(); MX_ADC3_Init(); MX_ADC2_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_ADC_Start(&hadc2); // 启动ADC采集 // 轮询ADC转换状态 if (HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY) == HAL_OK) { adc_value = HAL_ADC_GetValue(&hadc2); // 获取转换后的数字值 adc_voltage_value = adc_value*1000/ 4095.0f* 3.3; // 获取转换后的adc电压值mv V1 = adc_voltage_value /0.68f; //R74的分压电压 Ifl=V1/R_0K150+(SENSOR_VDD-V1)/(R_6K80+R_10K0)-(SENSOR_VDD-V1)/R_4K99; // 将液位百分比格式化为字符串 percent=(Ifl-4)/16*100; sprintf(buffer, "percent: %.1f%%\r\n",percent); // 发送液位百分比到串口 printf("%s",buffer); } HAL_Delay(500); // 添加延时 } /* USER CODE END 3 */ }
-
usart.c增加代码:usart.c的第1行添加头文件#include <stdio.h>
#include <string.h>,在末尾用户代码区增加如下代码。printf调用"fputc()",fgetc(),该函数会使用HAL_UART_Transmit发送数据。cpp/* * 添加如下代码,可不在工程设置中勾选Use MicroLIB */ #pragma import(__use_no_semihosting) struct __FILE { int a; }; FILE __stdout; FILE __stdin; void _sys_exit(int x) { } /***************************************************** *function: 写字符文件函数 *param1: 输出的字符 *param2: 文件指针 *return: 输出字符的ASCII码 ******************************************************/ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10); return ch; } /***************************************************** *function: 读字符文件函数 *param1: 文件指针 *return: 读取字符的ASCII码 ******************************************************/ int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, (uint8_t*)&ch, 1, 10); return (int)ch; }
-
连接USART1:用USB转TTL工具连接当前硬件USART1的PA9、PA10,GND。
-
打开串口助手:
-
编译代码:Keil编译生成的代码。
-
烧录程序:将编译好的程序用ST-LINK烧录到STM32微控制器中。
六、运行结果
1.液位百分比为0%的测试验证
如果用液位传感器在液位百分比为0%下测试时,此时的电流约4.1ma,ADC口的电压484mv。与上面电阻分压与增益计算和实际温度接近。
2.液位百分比为 22%的测试验证
如果用液位传感器在液位百分比为22%下测试时,此时的电流约7.61ma,ADC口的电压834mv,与上面电阻分压与增益计算和实际温度接近。
七、注意事项
1.确保你的开发环境和工具已经正确安装和配置。
2.确保自己搭建采样电路连接没错,检查传感器连接和电源是否正确,从信号源到单片机引脚检查信号是否争取,接到相应的ADC口。
3.如果没有打印液位百分比值,尝试仿真。
八、总结
通过本文的实践,我们成功实现了基于STM32F407的HAL库进行4-20ma液位传感器信号采集与处理的完整流程。从电路设计到运算放大器LM2904的应用,再到STM32 ADC模块的配置与串口数据传输。如果觉得有帮助,请点赞、收藏并分享!想了解更多技术细节?欢迎在评论区讨论!