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%的换算

五、代码实现与部署

六、运行结果

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

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​.具体参考附件的完整代码。

    /* 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发送数据。
    /*
    * 添加如下代码,可不在工程设置中勾选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模块的配置与串口数据传输。如果觉得有帮助,请点赞、收藏并分享!想了解更多技术细节?欢迎在评论区讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/936433.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB-固定集合(Capped Collection)

在 MongoDB 中&#xff0c;固定集合&#xff08;Capped Collection&#xff09;是一种具有特殊属性的集合。固定集合具有一个固定的最大大小&#xff0c;并且一旦达到该大小时&#xff0c;最早插入的文档将会被自动删除&#xff0c;以便为新的文档腾出空间。固定集合的这种特性…

Vue2 基础

Vue 2 是 Vue.js 的第二个主要版本&#xff0c;于 2016 年发布。它是一个渐进式的 JavaScript 框架&#xff0c;以其简单、灵活、易用性高而广受欢迎。Vue 2 主要专注于构建用户界面&#xff08;UI&#xff09;&#xff0c;并且非常适合用于构建单页应用&#xff08;SPA&#x…

2450.学习周刊-2024年50周

封面 人生五个球 ✍优秀博文 面对老板安排的工作&#xff0c;事事有回应&#xff0c;有必要吗&#xff1f; 职场精英进阶手册&#xff1a;工作推进五原则&#xff0c;让你合理高效地利用时间 上个班而已&#xff0c;千万别畏手畏脚 理解了雷军说的SU7要守正出奇&#xff0…

基于Llamaindex的网页内容爬取实战

目的 本文不关注如何解析网页 html 元素和各种 python 爬虫技术&#xff0c;仅作为一种网页数据的预处理手段进行研究。Llamaindex 也并不是爬虫技术的集大成者&#xff0c;使用它是为了后续的存查一体化。 安装依赖 pip install llama-index-readers-web # pip install llam…

Excel拆分脚本

Excel拆分 工作表按行拆分为工作薄 工作表按行拆分为工作薄 打开要拆分的Excel文件&#xff0c;使用快捷键&#xff08;AltF11&#xff09;打开脚本界面&#xff0c;选择要拆分的sheet&#xff0c;打开Module&#xff0c;在Module中输入脚本代码&#xff0c;然后运行脚本 Su…

go语言zero项目通过Supervisor启动与停用的管理

为了让Go项目通过 Supervisor 启动与重启&#xff0c;您需要确保已经正确安装和配置了 Supervisor。接下来是详细的步骤来配置您的 Go 项目&#xff0c;使其可以通过 Supervisor 管理。 ### 配置 Go 项目 首先&#xff0c;确保您的 Go 项目可以编译成一个可执行文件&#xff…

【ABAP SAP】开发-BUG修补记录_采购申请打印时品名规格品牌为空

项目场景&#xff1a; TCODE:自开发程序ZMMF004 采购申请打印 问题描述 ZMMF004打印的时候&#xff0c;有的采购申请的品名、规格、品牌为空 原因分析&#xff1a; 1、首先我通过写SQL语句查底表来看这几条采购申请本身有无品名、规格、品牌 SQL语句如下&#xff0c;只需修…

汽车租赁系统数据库 E-R 图设计

文章目录 汽车租赁系统数据库 E-R 图设计一、实体&#xff08;Entities&#xff09;二、实体间关系&#xff08;Relationships&#xff09;三、数据表&#xff08;Tables&#xff09; 汽车租赁系统数据库 E-R 图设计 一、实体&#xff08;Entities&#xff09; 用户&#xff0…

【小沐学GIS】基于C++绘制三维数字地球Earth(OpenGL、glfw、glut、QT)第三期

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第二期3【小沐…

Vizcom:AI驱动的草图到3D设计革命

Vizcom是一家领先的AI技术公司,专注于为工业设计师提供工具,将手绘草图快速转化为可制造的3D模型,从而加速产品迭代和创新。 公司背景与愿景 成立于2021年的Vizcom由前Nvidia工业设计师Jordan Taylor创立。Taylor凭借其深厚的创意设计背景和技术敏锐度,看到了生成对抗网络…

【开源免费】基于SpringBoot+Vue.JS课程智能组卷系统(JAVA毕业设计)

本文项目编号 T 009 &#xff0c;文末自助获取源码 \color{red}{T009&#xff0c;文末自助获取源码} T009&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 老…

Linux常用指令-----下

Linux常用指令------上 Linux常用指令------中 Linux系列 文章目录 Linux系列前言一、more指令二、less指令三、head指令和tail指令四、grep指令五、zip指令和unzip指令六、tar指令1、打包压缩2. 预览3. 解压解包 前言 在上一篇博客中&#xff0c;我給大家介绍了cat指令&#…

【安全研究】某黑产网站后台滲透与逆向分析

文章目录 x01. 前言x02. 分析 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与…

【Linux SH脚本】LinuxCheck 应急检查信息脚本

LinuxCheck 1.下载地址 【Linux SH脚本】LinuxCheck 应急检查信息脚本 2.简介 LinuxCheck 是一个开源的自动化检查脚本&#xff0c;旨在快速检测 Linux 系统的安全配置和潜在问题。它支持多种发行版&#xff0c;能够扫描并生成详细的报告&#xff0c;涵盖用户管理、权限配置…

JaxaFx学习(一)

目录&#xff1a; &#xff08;1&#xff09;基本结构 &#xff08;2&#xff09;Application &#xff08;3&#xff09;Stage窗口显示 &#xff08;4&#xff09;Scene场景切换 &#xff08;5&#xff09;UI控件通用属性 &#xff08;6&#xff09;UI控件属性绑定很属性…

悬赏任务源码(悬赏发布web+APP+小程序)开发附源码

悬赏任务源码是指一个软件或网站的源代码&#xff0c;用于实现悬赏任务的功能。悬赏任务是指发布方提供一定的奖励&#xff0c;希望能够找到解决特定问题或完成特定任务的人。悬赏任务源码通常包括任务发布、任务接受、任务完成和奖励发放等功能的实现。搭建悬赏任务源码是一个…

Java集合操作中的包含性判断:深入探讨List.contains()方法

文章目录 Java集合操作中的包含性判断&#xff1a;深入探讨List.contains()方法问题分析与解答1. 为什么list.contains(filterValueList)返回false&#xff1f;2. 正确的实现方法方法一&#xff1a;使用containsAll()方法二&#xff1a;Stream流操作方法三&#xff1a;传统循环…

帆软的无数据展示方案

文章目录 需求描述第一步、设置控件第二步、设置数据集优化改进 在日常工作中&#xff0c;使用到帆软报表工具&#xff0c;以下记录日常使用的过程&#xff0c; 需求描述 用帆软报表展示销量的信息&#xff0c;选择不同的订单状态&#xff0c;展示其订单数和总金额。 第一步、…

ubuntu20.04安装qt creator

以上三种&#xff0c;选择其一安装即可 回答1&#xff1a; 您可以按照以下步骤在ubuntu 20.04上安装Qt Creator&#xff1a; 打开终端并输入以下命令以更新软件包列表&#xff1a; sudo apt update 安装Qt Creator和Qt库&#xff1a; sudo apt install qtcreator qt5-def…

MySQL系列之数据类型(String)

导览 前言一、字符串类型知多少1. 类型说明2. 字符和字节的转换 二、字符串类型的异同1. CHAR & VARCHAR2. BINARY & VARBINARY3. BLOB & TEXT4. ENUM & SET 结语精彩回放 前言 MySQL数据类型第三弹闪亮登场&#xff0c;欢迎关注O。 本篇博主开始谈谈MySQL是如…