Day01_水质水位监测项目

01水质水位监测项目整体介绍和架构设计

项目背景与需求

大家好,今天我们要聊的是水质水位监测项目。这个项目其实挺贴近我们日常生活的,你有没有见过那种像笔一样的水质检测小工具?对,就是把它放进水里,就能快速知道水质好坏的那款。我们这个项目,核心目的就是检测和评估特定水体的质量,主要用在环保领域,当然日常生活中也挺实用的。

说到水质,大家可能会想到一些物理化学方面的常识。我们一般用TDS(总溶解固体量)这个指标来反映水质。TDS的单位是毫克/升,意思就是一升水里溶解了多少毫克的溶解性固体。这些溶解性固体主要是盐类物质,像钙盐、镁盐等。TDS值越高,说明水里可溶解的盐类物质越多,水相对就越不洁净。不过,也不能一概而论,毕竟水里的钙盐、镁盐等矿物质也是人体所需的。像纯净水TDS值就很低,但长期喝可能对身体微量元素平衡不利;而矿泉水TDS值相对高一些,却富含对人体有益的矿物质。

功能描述与系统架构

功能描述这块儿,咱们可以分成三大块:数据采集、数据处理和数据显示。首先,数据采集就是收集环境中的数据。水质监测用TDS模块,通过探针检测TDS数值;水位监测则用气压模块,检测气压值。这些数据采集到后,就交给嵌入式系统(STM32)处理。STM32就像个计算机,有输入有输出。它把采集到的数据进行处理,最后输出到液晶屏(LCD)上展示。

系统架构方面,我们主要分为两大模块:水质监测模块和水位监测模块。水质监测模块里,探针连接水体,检测到的模拟数据先经过ADC(模数转换)模块转换成数字信号,再传给STM32。这里用到的ADC模块是外置的ADS1115,它有16位精度,比STM32自带的12位ADC精度更高。水位监测模块相对简单些,气压传感器模块自带24位ADC,直接把检测到的气压值转换成数字信号传给STM32。STM32收到数据后,进行计算处理,再通过FSMC控制LCD显示输出。

项目细节与注意事项

在项目实施过程中,有几个细节和注意事项需要大家留意:

  1. TDS模块:TDS模块检测到的是模拟信号,所以我们需要外接ADS1115 ADC模块进行模数转换。ADS1115与STM32之间通过I2C通信,大家要熟悉I2C通信协议,确保数据准确传输。
  2. 气压传感器模块:这个模块自带24位ADC,精度很高,但与STM32的连接方式比较特殊,类似于串口但又不完全一样。它通过通用输入输出引脚连接到STM32的GPIO端口,所以需要我们自己编程控制时序,像之前软件模拟I2C那样。
  3. 数据处理:STM32收到数据后,要进行计算处理。水质数据需要根据TDS值评估水质好坏;水位数据则要根据气压值和水的密度、重力加速度等参数,通过公式计算出水位高度。
  4. 显示输出:最后,通过FSMC控制LCD显示输出。LCD显示屏上要清晰展示水质和水位的实时数据,可能还要设计一些友好的界面,比如不同水质等级用不同颜色显示,水位过高或过低时有报警提示等。

补充内容与建议

为了让大家更好地理解和学习这个项目,我再补充几点建议:

  1. 理论学习:在动手实践之前,建议大家先复习一下相关的物理化学知识,比如溶解度、盐类水解等,以及电子电路方面的知识,如模数转换原理、I2C通信协议等。这样在遇到问题时,能更快地找到原因并解决。
  2. 实践操作:多动手实践,从搭建硬件电路开始,到编写程序代码,再到调试整个系统。实践过程中可能会遇到各种问题,但这也是积累经验、提升技能的好机会。
  3. 查阅资料:在学习过程中,如果遇到不懂的知识点或技术难题,可以查阅相关书籍、技术手册、在线教程等资料。网络上有很多优秀的学习资源,大家可以充分利用。
  4. 交流讨论:加入一些技术交流群或论坛,与其他学习者或工程师交流心得、分享经验。在讨论中,不仅能学到新知识,还能激发自己的思考,对项目有更深的理解。

希望这个博客能帮助大家更好地学习水质水位监测项目,如果有任何问题或建议,欢迎在评论区留言,我们一起探讨。加油!

02_水质水位监测项目_硬件选型

硬件选型思路与需求分析

在硬件选型之前,我们首先要明确项目的需求。这个水质水位监测项目主要分为两大模块:水质监测和水位监测。水质监测需要用到TDS传感器模块,水位监测则准备采用压力传感器模块。至于是否需要外接ADC模块,就要看当前传感器模块是否已经集成了ADC,以及其位数是否满足我们的需求。同时,我们还要考虑STM32自带的ADC位数是否足够。通过这样的需求分析,我们就能初步画出硬件架构的框图,为后续的选型提供依据。

水位监测模块硬件选型

模块外观与连接方式

水位监测模块的外观大家应该已经有所了解,它有一个凸起的部分用于连接水管,直接焊在红色电路板上。这个电路板上,核心芯片周围有四个焊盘,分别是VCC、GND、OUT和SCK。VCC和GND分别接电源正和地,一般为3.3V;OUT是数据输出引脚;SCK则是时钟信号线。

通信协议分析

这个模块的连接方式有点特殊,虽然有时钟信号和数据线,但并不是标准的I2C通信。从手册描述来看,它更像是简化版的USART通信,只有发送功能,没有接收。也就是说,压力传感器检测到的数据会主动发送给STM32,而STM32不需要给传感器发送控制信息。这种设计简化了通信过程,上电后模块就能直接工作,STM32只需等待接收数据即可。当然,在接收数据前,对时钟信号的时序还是有一定要求的,具体细节我们后续再详细讲解。

连接水管与排针

在实际连接时,水管直接接在模块凸起的插头上。焊接时,四个焊盘最好直接接竖起来的排针,因为模块的高度无法降低,竖直排针可以方便后续的连接和包装。

TDS水质监测模块硬件选型

模块外观与接口

TDS水质监测模块的板子上元件相对较多。左边有两个接口,上面的两针接口是TDS探针接口,直接插上探针即可;下面的三针接口是温度传感器接口,虽然我们项目没用到,但它用于检测温度以校正溶解度,因为不同温度下固体在水里的溶解度是不同的。核心芯片包括放大器和计数器,共同实现TDS检测功能。右边有四个焊盘,标准接法是接弯的引角,以适应包装高度,但也可以接直的引角。

引脚功能与连接

四个焊盘中,AO是模拟输出引脚,相当于之前提到的OUT;T1是温度值输出引脚,但我们项目没用到温度检测,所以可以省略;剩下的两个是电源正和地,直接接上供电即可。由于TDS模块输出的是模拟信号,而STM32自带的ADC是12位的,精度不够,所以我们需要外接一个ADC芯片。

外置ADC模块选型与连接

选型原因与芯片介绍

之所以选用外置ADC模块,是因为TDS模块是模拟输出,而我们需要数字信号进行处理。STM32自带的12位ADC无法满足精度要求,所以选择了ADS1115这款16位的ADC芯片。ADS1115是TI公司生产的,业内口碑很好,质量有保障。我们选用的板子是国产的,以TI的核心芯片为基础,添加了一些外围电路。

连接方式与引脚功能

ADS1115模块有十个焊盘。VDD和GND接电源和地;SCL和SDA是I2C通信的时钟线和数据线;ADDR是地址线,用于指定设备地址,虽然只有一个引脚,但通过特定定义可以实现多个设备的地址选择;ALRT是报警信号引脚,但我们项目不准备接。剩下的A0、A1、A2、A3是模拟信号输入引脚,ADS1115可以有四路模拟信号输入,还可以配置成差分信号输入,检测两根信号线之间的差值。

硬件选型总结与建议

通过以上分析,我们完成了水质水位监测项目的硬件选型。水位监测模块自带24位ADC,直接与STM32连接;TDS水质监测模块外接ADS1115 ADC模块,实现高精度的模数转换。在实际操作中,要注意各模块的连接方式和通信协议,确保数据准确传输。希望这个硬件选型的介绍能帮助大家更好地理解项目,在实际操作中遇到问题时,可以查阅相关资料或寻求帮助,不断积累经验,提升自己的硬件设计和调试能力。

03_水质水位监测项目_水位模块使用方法

水位模块概述与芯片介绍

在我们的水质水位监测项目中,水位测量模块扮演着至关重要的角色。这个模块的核心芯片是HX710,它分为A和B两种型号。HX710A除了能测量压力,还能进行温度测量;而HX710B则能测量数字电压和模拟电压的差值。虽然我们项目主要关注压力测量,但了解这两种型号的区别有助于我们更全面地认识这个芯片。

HX710芯片最初是为高精度电子秤设计的24位AD转换器。它具有集成度高、响应速度快、抗干扰性强等优点,能够有效降低电子秤的整机成本。在我们的项目中,我们巧妙地将它用于测量空气气压,进而推算出水位深度。相较于直接接触式的压力传感器,气压传感器的损耗更小,测量结果也更稳定可靠。

模块手册与应用电路

模块手册为我们提供了丰富的信息。它详细介绍了芯片的基本信息、引脚功能、主要电气参数等。虽然手册只有八页,但内容涵盖了我们使用这个模块所需的关键知识点。手册中还给出了一个标准的应用参考电路,包括传感器、MCU(单片机)、LCD(液晶显示器)、稳压电路、LED灯以及充电电路等。这个参考电路为我们搭建整个监测系统提供了清晰的思路,让我们知道除了水位模块,还需要哪些外围电路来实现完整的功能。

通信协议与时序图解析

水位模块与STM32之间的通信方式比较特殊,它类似于串口通信,但又不完全相同。模块手册中的时序图详细描述了数据传输的过程。首先,数据线(DOUT)默认为高电平。当我们准备传输数据时,需要先将DOUT拉低,同时保持时钟线(SCK)也为低电平,维持一段时间(t1)。接着,我们开始输出时钟信号,第一个时钟周期上升沿到来后,t2时间过后,DOUT上的数据就有效了。时钟信号的高电平时间(t3)和低电平时间(t4)都有一定的范围,我们可以根据需要选择合适的延时。

在实际的数据采样过程中,我们通常选择在时钟信号高电平变为低电平的下降沿时刻进行采样,因为这个时刻数据已经稳定。整个数据传输过程需要24个时钟周期来完成24位的AD转换数据输出。此外,第25个时钟周期用于控制输出模式,例如差分输入、温度测量或电压差测量等。

物理连线与测量原理

在物理连线方面,我们将水位模块的VCC接3.3V电源,GND接地,OUT和SCK分别连接到STM32的通用输入输出引脚。为了避免与后续可能使用的串口功能冲突,建议不要使用PA2和PA3这两个引脚,可以选择其他空闲的引脚,如PB12和PB13。

至于测量原理,虽然HX710本质上是压力传感器,但我们可以通过物理公式将其与水位联系起来。水的压强公式为p=ρgh,其中p是压强,ρ是液体密度,g是重力加速度,h是水深。传感器检测到的压力值实际上是水深造成的压强与大气压强之和。因此,我们需要通过校准来确定大气压强对应的ADC读数值(b),以及水深与ADC读数值之间的线性关系系数(a)。在校准过程中,我们先将水管置于空气中,读取ADC值作为b;然后将水管放入已知深度(如10厘米)的水中,读取ADC值,结合已知深度计算出a。有了这两个系数,我们就可以根据实时测量的ADC值反推出水深。

校准过程与计算公式

校准是确保水位测量准确的关键步骤。首先,我们将水管置于空气中,读取此时的ADC值,记为y1,这个值对应的就是大气压强。接着,我们将水管放入10厘米深的水中,读取此时的ADC值,记为y2。根据两点确定一条直线的原理,我们可以得到直线方程y=ax+b中的两个系数:a=(y2-y1)/10,b=y1。在校准完成后,我们就可以利用这个公式来计算任意水深对应的ADC值,或者反过来,根据ADC值求解水深:x=(y-b)/a。

这个过程虽然稍显复杂,但只要我们理解了压力与水深之间的物理关系,以及如何通过校准确定线性关系的系数,就能够准确地进行水位测量。希望这个详细的讲解能帮助大家更好地掌握水位模块的使用方法,在实际项目中顺利实现水位监测功能。

04_水质水位监测项目_TDS采集模块使用方法

TDS模块概述与用户手册

在水质监测项目中,TDS模块是关键的一环。它能够检测水中溶解的固体物质含量,帮助我们了解水质的好坏。TDS模块也有自己的用户手册,虽然相对简单,只有六页,但内容涵盖了模块的基本信息、引脚说明、技术指标等。手册中提到,TDS检测设备通常是一个TDS笔,但TDS笔无法将数据传输给控制系统,无法实现长时间的在线监测。而我们的TDS模块则可以连接到STM32,实现长时间的在线监测,并将数据实时显示在LCD液晶屏上。

TDS检测原理与电压值关系

TDS模块的核心是检测水中溶解的盐类物质。这些盐类物质在水中以离子的形式存在,具有导电性。TDS探针由两根针组成,当探针插入水中时,两根针与水体构成一个回路。模块通过检测这个回路的导电性能,即电阻的大小,来判断水中的TDS含量。最终,模块会输出一个模拟电压值来表示当前的TDS。电压值越大,说明水的导电性越好,对应的TDS值也就越大。但这个关系并不是简单的线性关系,而是通过实验数据得出的一个曲线关系。手册中给出了这个曲线的计算公式,是一个三次方程。有了这个公式,我们就不需要像水位测量那样手动校准,可以直接根据检测到的电压值计算出TDS值。

TDS值的计算与单位

计算TDS值时,首先需要将STM32接收到的数字信号转换回原始的模拟电压值。然后,将模拟电压值代入手册中给出的三次方程公式,计算出当前的TDS值。TDS值的单位是PPM(parts per million),即百万分比浓度。这个单位表示在一百万份水中,溶解的固体物质占多少份。例如,饮用水的TDS值一般在几到几十PPM之间,而自来水的TDS值可能会有一两百甚至三百PPM,具体数值取决于水的硬度和纯净度。

温度校正系数与物理连线

由于不同温度下水的溶解度不同,手册中还提到了温度校正系数。如果同时能检测到当前的温度,可以对TDS值进行校正。校正公式中,温度修正值乘以一个系数0.02。当温度为25摄氏度时,相当于室温,不需要校正。温度高于25摄氏度时,修正值为正数;低于25摄氏度时,修正值为负数。不过,在日常室内环境中,温度变化不大,通常可以忽略校正。

在物理连线方面,将TDS探针插入水中,另一端接到模块的白色接口上。模块上有四个引脚,正负极接电源和地,温度检测接口不用接。最重要的AO模拟输出引脚,需要连接到外置ADC模块ADS1115的A0引脚。ADS1115模块有四路模拟信号输入,我们使用第一路模拟信号输入。

总结与后续步骤

通过以上介绍,我们了解了TDS模块的使用方法。它能够将检测到的水质数据转换成电压值,再通过公式计算出TDS值。虽然计算公式相对复杂,但有了公式,计算过程反而比水位测量更简单。接下来,我们需要关注的是如何将模拟电压值准确地转换为数字信号,并传输给STM32进行处理。这涉及到外置ADC模块ADS1115的使用方法,我们将在后续内容中详细讲解。

05_水质水位监测项目_ADS1115使用方法

为什么选择ADS1115

在水质监测项目中,我们使用TDS模块采集到的是模拟信号,需要将其转换为数字信号以便STM32处理。虽然STM32自带ADC模块,但其精度为12位,可能无法满足我们对数据精度的要求。因此,我们选择了16位精度的外置ADC模块ADS1115。ADS1115不仅精度更高,还支持四路电压转换,并且具备单端和差分输入的功能,功能丰富,能够满足我们项目的需求.

ADS1115的物理连线

ADS1115模块有多个引脚,其中VDD和GND分别接3.3V电源和地。SCL和SDA引脚用于I2C通信,连接到STM32的I2C2接口,即PB10和PB11引脚。ADDR引脚用于设置I2C从设备地址,我们将其直接接地,这样ADS1115的地址就为0x48。ALERT引脚是警告信号,我们暂时不使用,可以不接线。剩下的A0、A1、A2、A3是模拟信号输入引脚,我们目前只使用A0引脚,将TDS模块的模拟输出连接到A0上.

ADS1115的寄存器配置

ADS1115内部有多个寄存器,我们需要对其进行配置以实现正确的功能。首先是指针寄存器(Pointer Register),它决定了我们接下来要操作的寄存器。指针寄存器只能写入,且只有低两位有效,通过写入不同的值,我们可以选择操作转换寄存器(Conversion Register)、配置寄存器(Config Register)等.

转换寄存器存放的是ADC转换后的数字值,是一个16位的只读寄存器,以补码形式存储,可以表示正负电压值.配置寄存器是一个16位的寄存器,我们主要配置其中的几个参数:

  • OS(Operating State):控制ADC的运行状态,写入1时启动单次转换,读取时0表示正在进行转换,1表示转换结束.
  • MUX(Multiplexer):选择输入通道,我们选择单端输入模式,将AINP设为A0,AINN设为GND.
  • PGA(Programmable Gain Amplifier):可编程增益放大器,设置满量程电压范围,我们选择4.096V,以匹配外部电源电压.
  • MODE:设置转换模式,我们选择连续转换模式(Continuous Conversion Mode),将MODE设为0.

其他寄存器如低阈值寄存器(Low Threshold)和高阈值寄存器(High Threshold)用于比较器功能,我们暂时不使用,所以不需要配置.

ADS1115的读写时序

ADS1115与STM32通过I2C通信,读写操作遵循一定的时序.写入操作时,首先发送起始信号,然后发送设备地址和写入命令,ADS1115应答后,发送指针寄存器的值以选择要写入的寄存器,ADS1115再次应答,接着发送要写入的数据,ADS1115应答后,发送停止信号结束通信.

读取操作时,同样先发送起始信号,然后发送设备地址和写入命令,ADS1115应答后,发送指针寄存器的值以选择要读取的寄存器,ADS1115应答后,发送停止信号结束当前通信.然后再次发送起始信号,发送设备地址和读取命令,ADS1115应答后,开始发送数据,STM32接收数据后发送应答信号,最后发送停止信号结束通信.

通过以上步骤,我们可以成功地配置ADS1115,并读取其转换后的数字值,为水质监测项目提供准确的数据支持.

06_水质水位监测项目_软件架构

软件架构概述

在嵌入式开发中,软件架构的设计同样重要,它决定了项目的可扩展性、可维护性和稳定性。对于我们的水质水位监测项目,软件架构从下到上可以划分为驱动层、接口层、应用层和公共层。驱动层主要负责与硬件芯片的直接通信,如读取数据、发送指令等;接口层对驱动层进行封装,提供简洁明了的函数供上层调用;应用层实现了项目的具体功能模块,如水质监测、水位测量和数据显示等;公共层则包含一些通用的功能模块,如调试模块和延时模块,供各层级调用.

驱动层设计

驱动层是软件架构的基石,它直接与硬件芯片打交道。在我们的项目中,驱动层涉及多个芯片和通信协议。例如,使用USART进行串口打印输出,方便调试时查看程序执行状态;FSMC用于控制液晶屏,实现数据显示;I2C协议与外置ADC模块ADS1115通信,获取水质采集模块转换后的数字信号;GPIO用于水位测量模块的自定义通信协议,通过时钟线和数据线与STM32交互;SPI协议则连接外置存储器W25Q32,用于保存水位校准参数等数据.

接口层封装

接口层对驱动层进行封装,为应用层提供简洁的调用接口。以ADS1115为例,在接口层定义一个函数,如read_ads1115() ,该函数内部调用I2C通信相关函数,从ADS1115的转换寄存器中读取数据,然后返回给应用层。这样,应用层只需调用read_ads1115()即可获取水质数据,无需关心底层的I2C通信细节.同样地,水位测量模块的HX710B芯片,接口层也会定义一个函数,如read_hx710b() ,用于读取水位测量结果.

应用层实现

应用层是软件架构中实现项目具体功能的部分。在水质水位监测项目中,应用层可以划分为水质监测模块、水位测量模块和显示模块.水质监测模块主要负责通过ADS1115获取水质数据,并进行必要的数据处理,如单位换算等;水位测量模块则涉及HX710B芯片的数据读取和校准参数的处理,实现准确的水位测量;显示模块则负责将监测到的水质和水位数据在液晶屏上进行直观展示,方便用户查看.

公共层功能

公共层包含一些通用的功能模块,供整个软件架构中的各个层级调用。调试模块就是一个典型的例子,它封装了串口打印输出的相关函数,如debug_print() ,可以在程序的任何地方调用,用于输出调试信息,帮助开发者快速定位问题.延时模块也属于公共层,它提供了延时功能,如delay_ms()函数,可以用于实现时序控制或在特定场景下延时等待.

软件架构搭建流程

在实际开发过程中,我们通常按照从下到上的顺序搭建软件架构。首先,根据硬件设计和芯片手册,实现驱动层的各个函数,确保能够与硬件芯片正确通信;接着,在接口层对驱动层进行封装,定义简洁明了的函数接口;然后,在应用层实现项目的具体功能模块,调用接口层提供的函数,完成数据采集、处理和展示等任务;最后,根据需要在公共层添加通用的功能模块,如调试模块和延时模块,以提高开发效率和程序的可读性.

通过以上软件架构的设计和搭建,我们的水质水位监测项目能够实现高效、稳定的数据采集和处理,为用户提供准确的水质和水位监测结果.

07_水质水位监测项目_工程创建和整体架构搭建

工程创建准备

在开始敲代码之前,我们需要为项目创建一个整洁的工程目录结构。我的工程都放在D盘,有一个专门的project文件夹,里面再根据项目类型细分。比如嵌入式项目就放在embedded文件夹下。为了方便后续管理,我给当前的水质水位监测项目取名为project_01_water_tds_and_level_register,其中project_01表示这是第一个项目,water_tds_and_level表明项目内容与水质、水位和TDS相关,register后缀说明我们是用寄存器方式实现的模块.

复制底层代码

接下来,我们需要准备一些底层代码。首先复制启动代码,这是每个工程都必不可少的。我从之前的基础篇和进阶篇代码中找到一个合适的启动文件夹,里面包含了启动文件、一些头文件以及汇编文件。然后,考虑到项目中要用到液晶显示,我就从之前的液晶项目中找到相关代码,将其底层驱动文件夹命名为driver,以保持与后续help库目录的一致性.

创建工程目录结构

在工程目录下,我创建了几个关键的子目录: common用于存放公共模块,如调试模块debug和延时模块delay; driver存放硬件驱动层代码; interface是接口层,封装驱动层函数; application或简写为APP是应用层,实现项目具体功能模块.这样,我们就搭建起了工程的基本框架.

在Keil中创建工程

打开Keil uVision5,选择新建工程,定位到我们刚才创建的工程目录,输入工程名称,选择芯片型号为STM32F103ZE。创建过程中,可以跳过中间件支持的选项,因为我们暂时不需要.工程创建成功后,会看到一个空的工程结构,我们需要手动添加文件和配置.

配置工程

首先,在工程中创建几个文件组,分别对应我们的目录结构:startupuserdriverinterfaceAPP。然后,将之前准备好的启动文件、main.c以及common目录下的文件添加到对应的组中.接下来,进行编译选项配置,将编辑器版本改为默认的AC6,勾选"Use MicroLIB"以便重写printf函数,并配置包含路径,将startupusercommon等目录添加进去.此外,还需要勾选"C99 Mode"以支持更多C语言特性,如在for循环中直接定义变量.

调试器配置

在调试器配置中,选择SDLink作为调试器,勾选"Reset and Run"选项,让代码烧录后自动运行,提高测试效率.同时,取消勾选"Enable Pack"选项,避免后续烧录时还需要手动复位.

使用VSCode编写代码

最后,我们通过VSCode打开这个Keil工程,在VSCode中可以更方便地编写和管理代码.至此,我们的工程创建和整体架构搭建就完成了,后续就可以在各个模块中逐步实现具体功能了.

08_水质水位监测项目_延时模块

延时模块概述

在嵌入式开发中,延时模块是不可或缺的公共功能模块之一。它为系统提供精确的时间控制,使得我们能够在特定的时间间隔内执行某些操作或等待某个事件的发生。在我们的水质水位监测项目中,延时模块将被广泛应用于各个功能模块中,如在数据采集、处理和显示等环节中,都需要用到延时来控制执行节奏或等待硬件响应.

延时函数实现

微秒级延时函数

微秒级延时函数是延时模块中最基本的函数,它利用系统滴答定时器(SysTick)来实现精确的微秒级延时。具体实现步骤如下:

  1. 设置定时器装载值:根据延时的微秒数,计算出定时器的装载值。由于系统时钟频率为72MHz,每个时钟周期为1/72微秒,因此装载值为72 * 微秒数.
  2. 清零计数器:将定时器的计数器值清零,使其从装载值开始向下递减计数.
  3. 配置定时器:设置定时器的控制寄存器,使其使用系统时钟作为时钟源,并开启定时器.
  4. 等待延时结束:通过轮询定时器的计数标志位,等待计数器值变为零,表示延时结束.

毫秒级延时函数

在微秒级延时函数的基础上,我们可以通过循环调用微秒级延时函数来实现毫秒级延时。具体实现方法为:

  1. 循环调用微秒级延时:将毫秒数转换为微秒数(1毫秒 = 1000微秒),然后循环调用微秒级延时函数delay_us(1000).
  2. 循环变量递减:每次调用微秒级延时函数后,将毫秒数减一,直到毫秒数为零,表示延时结束.

秒级延时函数

秒级延时函数的实现与毫秒级延时函数类似,只是将秒数转换为毫秒数(1秒 = 1000毫秒),然后调用毫秒级延时函数即可.

延时模块测试

虽然延时模块的实现相对简单,但我们仍需对其进行测试以确保其准确性。在测试过程中,我们可以编写一个简单的测试程序,在程序中调用不同级别的延时函数,并通过串口打印或LED闪烁等方式来观察延时效果是否符合预期.例如,可以先调用100毫秒的延时函数,然后打印一条信息或点亮一个LED,再调用1秒的延时函数,打印另一条信息或熄灭LED,以此来验证延时的准确性.

延时模块注意事项

  1. 数据类型范围:在实现毫秒级和秒级延时函数时,要注意数据类型的选择,避免因数据溢出导致延时错误.例如,在计算微秒级延时时,如果直接将毫秒数乘以1000,可能会超出uint16_t数据类型的范围,因此需要使用循环递减的方式来实现.
  2. 定时器配置:在配置定时器时,要确保其时钟源、装载值和控制寄存器等参数设置正确,以保证延时的精度和稳定性.
  3. 系统时钟频率:延时模块的实现依赖于系统时钟频率,因此在不同频率的系统中,需要根据实际情况调整定时器的装载值,以保证延时的准确性.

通过以上内容,我们完成了水质水位监测项目中延时模块的实现和测试,为后续各功能模块的开发奠定了基础.

09_水质水位监测项目_调试模块_驱动层

调试模块概述

在嵌入式开发中,调试模块是至关重要的公共功能模块之一。它为开发者提供了丰富的调试信息输出功能,方便我们在开发过程中快速定位问题和优化代码。在我们的水质水位监测项目中,调试模块主要依赖于USART串口通信,将调试信息发送到电脑或其他串口设备上,以便实时查看程序的执行状态和变量值等信息.

USART驱动层实现

复制USART底层代码

由于USART的底层实现相对复杂,我们可以直接复制之前已经写好的USART驱动代码。在之前的项目中,USART的底层实现通常放在hardware文件夹下,文件名为usart.cusart.h。我们将这两个文件复制到当前项目的driver文件夹下,以便在调试模块中使用.

添加USART到工程

在Keil工程中,我们需要将复制过来的usart.c添加到对应的文件组中。打开工程,找到driver文件组,将usart.c拖入其中。同时,不要忘记在C/C++编译选项中添加usart.h的包含路径,确保编译时能够找到头文件.

USART功能函数分析

usart.h中,我们定义了几个主要的USART功能函数:

  • usart_init(): 初始化USART,配置波特率、工作模式等参数.
  • usart_send_char(): 发送一个字符.
  • usart_send_string(): 发送一个字符串.

由于调试模块主要用于发送调试信息,我们不需要接收功能,因此可以将接收相关的函数删除,简化代码.

USART初始化配置

usart_init()函数中,我们需要进行以下配置:

  1. 打开USART时钟: 使能USART模块的时钟,以便其正常工作.
  2. 配置GPIO: 将USART的TX引脚配置为复用推挽输出模式,RX引脚配置为浮空输入模式.
  3. 设置波特率: 根据实际需求设置USART的波特率,例如115200.
  4. 使能USART和收发模块: 打开USART模块以及TX和RX功能.
  5. 配置数据帧格式: 设置数据帧长度为8位,无校验位,停止位为1位.

USART发送函数实现

  • usart_send_char(): 判断USART的发送缓冲区是否为空,如果为空,则将要发送的字符写入数据寄存器DR.
  • usart_send_string(): 通过循环调用usart_send_char()函数,逐个发送字符串中的字符.

调试模块测试

为了测试调试模块的功能,我们可以在主函数中进行简单的测试。首先调用usart_init()初始化USART,然后使用printf函数输出调试信息。例如,可以先输出项目名称,然后调用延时函数delay_ms(2000)延时2秒,再输出“开始”等信息。通过串口调试助手等工具,我们可以观察到这些调试信息是否能够正确输出,从而验证调试模块的准确性.

调试模块注意事项

  1. 波特率匹配: 确保USART的波特率与串口调试助手等接收工具的波特率一致,否则可能导致接收数据错误.
  2. 发送缓冲区判断: 在发送字符之前,一定要判断发送缓冲区是否为空,避免数据丢失.
  3. 代码简化: 根据实际需求,可以对USART驱动代码进行适当的简化,删除不必要的功能,提高代码的可读性和维护性.

通过以上步骤,我们成功实现了水质水位监测项目中的调试模块驱动层,为后续的调试工作打下了坚实的基础.

10_水质水位监测项目_调试模块_包装实现

调试模块的重要性

在嵌入式开发过程中,调试模块是不可或缺的工具之一。它能够帮助我们实时输出程序的运行状态、变量值等关键信息,从而快速定位问题并优化代码。在我们的水质水位监测项目中,调试模块将发挥重要作用,方便我们在开发过程中进行调试和测试.

调试模块的实现思路

条件编译的应用

为了在调试和发布模式下灵活控制调试信息的输出,我们可以利用 C 语言中的条件编译功能。通过定义一个宏DEBUG,我们可以根据是否定义这个宏来决定是否输出调试信息。具体来说:

  • 调试模式:定义DEBUG宏,此时调试模块正常工作,输出调试信息。
  • 发布模式:不定义DEBUG宏,此时调试模块中的相关代码会被编译器忽略,不会输出调试信息,从而减少程序体积和提高运行效率。

调试模块的包装

我们将调试模块包装成一个独立的模块,包含初始化函数和调试输出函数。初始化函数负责初始化 USART 等底层硬件,调试输出函数则用于输出调试信息。通过这种方式,我们可以将调试相关的代码集中管理,提高代码的可读性和可维护性.

调试模块的具体实现

头文件定义

debug.h头文件中,我们首先使用条件编译防止重复定义,然后引入 USART 的头文件usart.h,因为调试模块底层依赖于 USART 进行串口通信.接着,我们定义调试模块的初始化函数debug_init(),用于初始化调试模块.

初始化函数实现

debug.c文件中,实现debug_init()函数。根据是否定义DEBUG宏,决定是否调用 USART 的初始化函数usart_init()。如果定义了DEBUG宏,则调用usart_init()初始化 USART,使调试模块正常工作;否则,不执行任何操作,相当于空函数.

调试输出函数实现

定义一个调试输出函数debug_printf(),用于输出调试信息。同样根据是否定义DEBUG宏,决定函数的具体实现:

  • 调试模式:定义DEBUG宏时,debug_printf()函数内部调用printf()函数,输出调试信息。为了获取当前文件名和行号,我们使用__FILE____LINE__宏,并通过strrchr()函数截取文件名,去除路径信息.最终,将文件名、行号和调试信息拼接成一个完整的字符串输出.
  • 发布模式:不定义DEBUG宏时,debug_printf()函数为空实现,不输出任何调试信息.

自动换行函数实现

为了方便调试输出,我们还可以定义一个自动换行的调试输出函数printf_ln()。在debug_printf()的基础上,自动在输出内容的末尾添加换行符\r\n(Windows 格式),简化调试信息的输出操作.

调试模块的测试

在主函数中,我们可以通过调用debug_init()初始化调试模块,然后使用debug_printf()printf_ln()输出调试信息。例如,在程序开始时输出项目名称,延时一段时间后再输出“开始”等信息。通过串口调试助手等工具,我们可以观察到调试信息是否能够正确输出,从而验证调试模块的准确性.

调试模块的优势

  1. 灵活控制:通过条件编译,我们可以在调试和发布模式下灵活控制调试信息的输出,无需手动注释或取消注释调试代码.
  2. 集中管理:将调试相关的代码集中在一个模块中,提高了代码的可读性和可维护性,方便后续的修改和扩展.
  3. 信息丰富:调试输出包含当前文件名和行号等信息,有助于快速定位问题来源,提高调试效率.

通过以上步骤,我们成功实现了水质水位监测项目中的调试模块,并对其进行了包装和优化,为后续的开发和调试工作提供了有力支持.

11_水质水位监测项目_显示模块

显示模块概述

在我们的水质水位监测项目中,显示模块扮演着至关重要的角色。它负责将监测到的水质和水位数据直观地展示给用户,让用户能够实时了解当前的水质状况和水位高度。显示模块底层使用的是液晶LCD,通过FSMC进行驱动。我们将FSMC和液晶的具体调用代码迁移过来,并在上层封装一个显示模块,实现对显示功能的统一管理。

工程配置与文件添加

首先,我们需要在工程中添加相关文件。将FSMC的代码复制到driver文件夹下,将LCD的代码放入interface文件夹中。在应用层APP下创建显示模块的文件display.cdisplay.h。然后,在Keil工程中配置文件路径,将FSMC、LCD和display文件添加到对应的文件组中,确保编译时能够找到这些文件。

显示模块的实现

底层FSMC与LCD初始化

在FSMC的代码中,我们主要进行初始化操作,包括时钟配置和GPIO引脚配置。由于液晶连接的是Bank4,我们需要配置BCR4和BTR4寄存器,设置控制寄存器和时序寄存器。LCD的代码中,我们定义了一些基本操作函数,如开关背光、读ID等。由于读ID在项目中用不到,可以将其删除。另外,我们有一个清屏函数clear,可以将其简化为直接设置背景颜色。

应用层显示功能封装

在应用层的display.c文件中,我们首先引入display.h头文件,然后定义一些宏,进行条件编译。接着,我们实现显示模块的初始化函数display_init(),调用LCD的初始化函数进行初始化。为了方便使用,我们封装了一个清屏函数display_clear(),默认使用白色清屏。

接下来,我们实现显示信息的函数display_string(),传入坐标和要显示的字符串。在底层调用LCD的显示函数LCD_display_string(),设置字体大小为24x24,字体颜色为蓝色,背景颜色为白色。这样,在上层调用时,只需传入坐标和字符串即可。

最后,我们实现显示标题的函数display_title()。首先显示上硅谷的logo,然后显示标题汉字“上硅谷水质水位监测”。我们使用循环遍历的方式,调用LCD的中文显示函数LCD_display_chinese(),传入每个汉字的索引位置、坐标、字体大小、字体颜色和背景颜色。为了使标题居中显示,我们计算了起始位置的坐标,确保标题在屏幕上居中对齐。

显示模块测试

在主函数中,我们先初始化调试模块和显示模块,然后调用display_title()显示标题。为了测试显示信息的功能,我们还可以调用display_string()显示一些测试信息,如“helloworld”。通过观察液晶屏的显示效果,我们可以验证显示模块的正确性。

显示模块的优势

  1. 封装性:将显示相关的代码封装在独立的模块中,提高了代码的可读性和可维护性,方便后续的修改和扩展。
  2. 易用性:在应用层调用显示函数时,只需传入简单的参数,如坐标和字符串,无需关注底层的复杂实现细节,简化了上层代码的编写。
  3. 灵活性:可以根据实际需求灵活调整显示内容和布局,如修改标题、添加新的显示信息等,满足不同场景下的显示需求.

通过以上步骤,我们成功实现了水质水位监测项目中的显示模块,为用户提供了直观、友好的显示界面,方便实时了解水质和水位信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值