STM32 HAL库 + LM2904运算放大器 + ADC + 4-20ma液位传感器:电路设计及代码实现

4-20ma液位传感器在工业自动化和日常应用中非常常见,例如水位监测、液体储罐管理等。本文将结合STM32 HAL库,带你实现一个简单的液位监测demo,从电路设计到代码实现,实现通过单通道ADC采集4-20ma液位传感器的信号,并通过串口将采集到的液位百分比打印输出。具体流程包括:通过分压电阻将获得4-20ma液位传感器的分压电压,再利用运算放大器LM2904对信号进行放大,随后将信号输入STM32的ADC2模块读取通道6(对应引脚PA6)。最终,处理后的液位百分比数据通过串口1发送至串口助手进行实时显示。

目录

一、开发环境

二、4-20ma投入液压式液位传感器

1.设计思路

2.电阻分压与增益计算:

2.1基本公式与定义

2.2不接传感器(开路)时的电压计算

2.3液位百分比为0%的换算

[2.4液位百分比为 22%的换算](#2.4液位百分比为 22%的换算)

五、代码实现与部署

六、运行结果

1.液位百分比为0%的测试验证

[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

  1. 启动STM32CubeMX,新建STM32CubeMX项目:

  2. 选择MCU:在软件中选择你的STM32型号-STM32F407ZGT6。

  3. 选择时钟源:

  4. 配置时钟:

  5. 使能Debug功能:Serial Wire

  6. HAL库时基选择:SysTick

  7. USART1配置:选择异步模式。

  8. 开启外部时钟:配置系统时钟,确保ADC和串口的外部时钟已开启。

  9. 配置ADC:

1)选择ADC2作为采集模块。

2)设置AD2的通道6(对应引脚PA6)为采集通道。

3)配置采样时间和分辨率。通常,采样时间越长,ADC的转换精度越高,但也会增加转换时间。

4)禁用扫描模式,因为我们只采集一个通道。

10.配置工程参数:在Project标签页中,配置项目名称和位置,选择工具链MDK-ARM。 11.生成代码:在Code Generator标签页中,配置工程外设文件与HAL库,勾选头文件.c和.h文件分开,然后点击Project > Generate Code生成代码。

五、代码实现与部署

  1. 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 */
    }
  2. 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;
    }
  3. 连接USART1:用USB转TTL工具连接当前硬件USART1的PA9、PA10,GND。

  4. 打开串口助手:

  5. 编译代码:Keil编译生成的代码。

  6. 烧录程序:将编译好的程序用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模块的配置与串口数据传输。如果觉得有帮助,请点赞、收藏并分享!想了解更多技术细节?欢迎在评论区讨论!

相关推荐
南城花随雪。9 分钟前
单片机:实现多任务处理(附带源码)
单片机·嵌入式硬件
葟雪儿2 小时前
海思芯片 交叉编译curl
linux·运维·服务器·开发语言·c++·嵌入式硬件
嵌入式小强工作室2 小时前
STM32内部flash分区
stm32·单片机·嵌入式硬件
就是太懒3 小时前
开启dev_dbg方法
android·linux·嵌入式硬件
析木不会编程3 小时前
【小白51单片机专用教程】protues仿真流水灯
单片机·嵌入式硬件·51单片机
m0_370565223 小时前
stm32 rtc 详解
stm32·单片机·实时音视频
嵌入式大圣4 小时前
单片机TCP无线数据透传
单片机·嵌入式硬件·tcp/ip
qq_459730035 小时前
1-15 GD32ARM存储器
c语言·arm开发·单片机
奇文怪式5 小时前
VSCode编辑+GCC for ARM交叉编译工具链+CMake构建+OpenOCD调试(基于STM32的标准库/HAL库)
arm开发·vscode·stm32