行业资讯
📅 2026/9/9 1:43:03
基于STM32的智能流量计与水泵报警系统设计实战解析
简介基于STM32F103C8的智能流量计与水泵控制系统通过信号发生器模拟流量传感器实时监测流速流量并依据阈值区间控制步进电机低于区间正转等于区间停止超过区间反转同时触发蜂鸣器和LED报警。系统支持自动与手动双模式自动模式按设定流速范围执行正转/反转/停止手动模式可控制正转、反转、加速、减速、启动和停止并具备LCD1602显示和上位机输出可模拟Wi-Fi/蓝牙或RS232/RS485通信。资源共207个文件包含STM32源码.c/.h、Proteus仿真工程.pdsprj、原理图.schdoc、编译中间文件.d/.o/.axf及烧录文件.hex压缩包约11.17MB结构清晰。目前已有584人学习下载。对于嵌入式课程设计、毕业设计或流量计项目开发者这套资源提供了完整代码框架、仿真模型和硬件设计参考能帮助理解阈值控制逻辑、双模式切换及上位机通信实现省去从零搭建的繁琐过程。1. 项目整体拆解这个系统的真正难点在哪先说结论这个项目的核心价值不在于“把元件搭起来”的那一层而在于流量采集的实时性、阈值报警的响应联动、步进电机双模式控制的逻辑清晰度以及上位机通信的稳定性。我见过太多人做着做着就成了“只亮了个屏幕、只转了半圈电机”的半成品原因不是某一块难上天而是没有把系统的功能边界拆清楚一上来就写代码最后改到怀疑人生。就标题“基于STM32的智能流量计流速流量监测水泵报警系统”而言它至少包含了四条并行的功能线一是用STM32采集流量传感器的脉冲信号把频率换算成流速和累计流量二是通过LCD1602把瞬时流量、累计流量、当前模式、阈值状态实时显示出来三是根据用户设定的阈值联动水泵报警蜂鸣器或指示灯并控制步进电机在手动和自动双模式之间平滑切换四是把数据通过串口上发给上位机并且允许上位机反向设置参数。一条线断了整套系统看起来就是不完整的。所以我的建议非常明确先别急着碰Proteus里的连线先把系统的功能边界和状态切换关系画出来。你要清楚“哪个按键切模式”“哪个参数能内部设定”“哪个参数来自上位机”“报警后电机是停还是降速”。这些逻辑如果在脑子里是模糊的仿真图画得再漂亮也没用调试的时候照样一头雾水。方案选了STM32这个平台抛开“课程设计标配”这个因素单从技术层面讲STM32丰富的定时器资源输入捕获、PWM输出、外部时钟模式和中断机制天然适合做“脉冲计数多任务控制”这类应用。换成51当然也能做个简化版但你要做上位机交互、阈值实时比较、双模式步进电机控制51的资源会紧巴巴的代码可读性也会很差。Proteus仿真则解决了“没板子也能调逻辑”的最大痛点先把功能在仿真里跑通后续板子回来了再烧写验证效率会高很多。1.1 系统功能需求结构化把标题拆开之后我用表格把整个系统的需求整理成最小单元每一条都对应到后续的硬件接口和代码模块。这个表在做之前花十分钟列出来能直接决定你后面写代码的心情强烈建议照做。功能模块需求描述依赖硬件/接口对应动作流量采集测量管道内流速累计流量流量计脉冲输出引脚→STM32定时器输入捕获引脚定时器捕获频率→换算瞬时流速/累计流量数据显示LCD1602实时显示瞬时流量、累计量、模式、阈值状态LCD1602数据引脚控制引脚定时刷新显示字段阈值报警超过上下限触发水泵报警蜂鸣器/报警LED/水泵继电器流量越限→报警引脚电平翻转手动模式人为控制步进电机启停、正反转、调速步进电机驱动ULN2003按键输入按键中断/轮询→控制GPIO脉冲输出自动模式根据流量偏差自动调节电机转速步进电机驱动阈值状态PID或分段控制→PWM/脉冲频率调整上位机通信实时上报数据支持阈值设置UART串口→虚拟串口→上位机串口发送/接收协议解析双模式切换手动/自动切换且切换平滑模式切换按键状态机处理1.2 为什么这样选型Proteus仿真的优势与坑选STM32F103C8T6这颗芯片基本是这类设计里性价比最高的方案。它有两个高级定时器和四个通用定时器我可以用TIM2做输入捕获测流量用TIM3输出PWM驱动步进电机调速完全不会互相抢资源。Proteus 8以上的版本对STM32库支持已经比较成熟ST官方外设库和HAL库的工程都能仿真编译通过后直接把hex文件烧进虚拟芯片里就能跑调试波形和逻辑状态比实板还直观。不过Proteus有两个很实际的坑提前说出来帮你避雷。一个是它没有真实的流量传感器模型你得用信号源或波形发生器去模拟传感器输出的脉冲也就是在仿真里用一个VPULSE或方波发生器代替传感器接到STM32的输入捕获引脚。另一个坑是步进电机的驱动芯片模型在Proteus里有但默认的减速比和你手里的实物不一定一致仿真里转10圈可能实物只转1圈所以仿真验证的是逻辑参数最终要以实物为准。2. 硬件设计核心传感器接口与显示单元硬件设计这块我习惯从“信号流”的角度去捋而不是按照原理图的元件顺序。这个系统的信号流是流量传感器输出脉冲到STM32的输入捕获引脚STM32内部运算后把结果写到LCD1602和串口同时根据阈值状态控制蜂鸣器和步进电机驱动。显示单元和传感器接口是整个系统的入口和出口先搞懂它们的工作原理后面的代码才写得顺手。2.1 流量传感器采集原理与定时器配置市面上常见的流量计比如涡轮流量计或者霍尔式流量计输出都是一个频率与流速成正比的脉冲信号。频率越高流速越快。所以测量流量的本质就是测频率。频率换算流速的公式一般由传感器厂家给出Q f / K其中K是仪表常数单位是脉冲数/升或脉冲数/立方米不同管径和量程的传感器K值差异很大。我在仿真里用信号发生器模拟脉冲实际项目中需要根据自己手上的流量计铭牌去设定K值。STM32测频率有几种做法我强烈推荐用定时器输入捕获模式而不是简单的外部中断计数配合定时器计算。原因很简单输入捕获模式由硬件完成边沿检测和时间戳记录误差小CPU在做其他事情的时候也不丢脉冲。具体配置上把TIM2的CH1引脚PA0配置为输入捕获上升沿触发在捕获中断里读取CCR寄存器配合定时器的时基频率计算两次捕获之间的间隔就能得到脉冲周期频率就是周期的倒数。// TIM2输入捕获初始化基于标准外设库HAL库思路一致 void TIM2_Capture_Init(void) { TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_ICInitStructure.TIM_Channel TIM_Channel_1; TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter 0x0; TIM_ICInit(TIM2, TIM_ICInitStructure); TIM_Cmd(TIM2, ENABLE); }这里有个特别重要的细节TIM2的时基时钟一定要根据你的主频仔细算。如果你用STM32F103C8T6经内部8MHz晶振倍频到72MHz主频TIM2挂在APB1总线上APB1分频系数为2时TIM2的时钟是72MHz而不是36MHz因为APB1预分频不为1时定时器时钟倍频。很多人在这里栽跟头明明信号频率是对的测出来数据偏一倍多半就是定时器时钟没算对。提示测量流量脉冲时最好加上数字滤波比如连续采3次频率求平均或者用滑动窗口滤波。水流本身就存在脉动如果直接拿单次捕获结果去刷新LCD和判断阈值显示值会跳来跳去报警也可能频繁误触。2.2 LCD1602显示方案与刷新策略LCD1602是这类项目最经典的显示器件16列2行每个字符5×8点阵。它在Proteus里的仿真模型非常成熟时序和真实器件几乎一致所以你完全可以在仿真里把驱动代码调好烧到实物上大概率直接能跑。显示驱动我建议用4线模式只占D4-D7四个数据引脚加RS、EN两个控制引脚总共6个IO就能搞定给其他功能留下充足的引脚余量。初始化时序要注意上电后必须等40ms以上然后依次发送3次0x03再设置成4线模式这组“祖传时序”缺一不可少一步就出现经典的花屏现象。显示内容布局上我的习惯是第一行显示瞬时流量和模式比如“F:12.34 L/H M-AU”第二行显示累计流量和阈值状态比如“V:123.4L AL:H”。刷新策略不要每次更新都整屏重写那样会有明显的闪烁感最好是只更新变化的字段比如用光标定位到对应位置先写空格再写新数字——别小看这个处理在步进电机同时运行的状态下LCD刷新太频繁会导致显示异常因为两个任务在抢CPU时间优化一下刷新逻辑能省很多事。2.3 步进电机驱动脉冲控制与转向逻辑步进电机的本质是“给一个脉冲走一步”。标题里用的是普通四相五线步进电机最常见的是25BYJ-48配合ULN2003驱动板。Proteus里有对应的ULN2003A模型直接用即可。不要试图用STM32的GPIO直接驱动电机灌电流不够必须通过ULN2003或者A4988这类驱动芯片这是个常识性的坑。四相步进电机的驱动时序有两种四拍和八拍。四拍是A-B-C-D循环每步走90度电角度八拍是A-AB-B-BC-C-CD-D-DA循环每步45度电角度。八拍的优势是运转更平滑扭矩更大代价是同样的转速需要2倍的脉冲频率。我建议项目里用八拍方式仿真和实物效果都更好。调速的核心就是控制脉冲频率可以用定时器中断或者延时函数实现中断方式更精准系统在跑其他任务时电机也不会卡顿。转向切换有个容易忽略的地方反转时只需要把脉冲序列倒过来但最好在切换方向的瞬间先停止脉冲输出延时几毫秒再反向否则电机容易丢步。如果你用TIM3产生PWM脉冲驱动电机那调速就变成改PWM的频率如果你用延时翻转GPIO那就要注意高频时延时的准确性。3. 控制逻辑与双模式实现双模式控制是这套系统的“灵魂”也是评判代码是否成熟的分水岭。很多人的实现方式是“手动模式和自动模式各写一套独立代码”然后通过if-else切换这样也能跑但逻辑混乱到后期自己都维护不了。我的做法是引入一个简单的状态机用“模式状态”和“电机动作”两个维度去组织代码整个系统的结构会清晰很多。3.1 手动模式按键控制与转速调节手动模式下用户通过按键直接控制电机的启停、正反转和转速。我设计了三个按键一个启停键、一个方向键、一个加速键再加一个减速键的话需要4个按键。按键处理建议做成非阻塞扫描消抖不要用delay消抖因为delay会阻塞整个系统流量采集和LCD刷新都会卡住。正确的做法是每隔10ms扫描一次按键连续两次读到同一状态就确认按键有效。电机的转速调节我建议设置4~8个档位而不是无级调速这样对用户更友好显示也更直观。每个档位对应一个脉冲频率比如1档10Hz、2档30Hz、3档60Hz、4档100Hz频率值在切换档位时写入定时器的预装载寄存器即可。// 手动/自动模式状态机框架 typedef enum { MODE_MANUAL, MODE_AUTO } SystemMode; typedef enum { MOTOR_STOP, MOTOR_RUN } MotorState; void System_Control_Loop(void) { Key_Scan(); // 非阻塞按键扫描 if (mode MODE_MANUAL) { // 手动直接根据按键操作更新电机状态 if (key_start_stop.pressed) motor.state !motor.state; if (key_speed_up.pressed motor.gear 8) motor.gear; if (key_speed_down.pressed motor.gear 1) motor.gear--; } else { // 自动根据流量偏差自动调节档位 Auto_Control(flow_data, motor); } }3.2 自动模式的阈值比较与水泵报警联动自动模式的核心是“流量异常时自动做出响应”。这里需要先定义什么算异常。我一般设置两个阈值低速报警阈值比如低于2L/min认为管路堵塞或水泵抽空和高速报警阈值比如高于10L/min认为超负荷。当瞬时流量低于下限或高于上限时蜂鸣器鸣叫同时LCD上的阈值状态闪烁并且电机做出保护动作——低于下限时电机增速补偿高于上限时电机降速甚至停机。阈值设置有两种途径一是板上按键设定二是上位机通过串口下发。两种途径最终写入同一个全局变量互不冲突。这个问题看起来简单实际上很多人在“上位机设置的阈值怎么生效”上卡壳核心是搞清楚参数的存储位置——STM32内部的一个变量无论来自按键还是串口最终都统一更新到这个变量然后所有使用阈值的模块都读这个变量。自动模式的控制策略最简单可行的是分段控制也叫位式控制实测流量落在哪个区间电机就转到对应的档位。追求效果更好的可以引入PID控制输入是流量的目标值与实际值的偏差输出直接控制电机的脉冲频率。Proteus仿真里做PID有天然优势你能通过调节信号源频率模拟流量变化直观地看到电机转速是否跟随。不过第一次做的时候个人建议先用分段控制跑通流程PID留作进阶。3.3 双模式切换的平滑过渡细节模式切换最怕的是什么是切换瞬间电机的“抽搐”。比如手动模式下电机正以5档全速运转切到自动模式的瞬间自动控制逻辑发现当前流量低于下限立刻命令电机降到2档——转速突变轻则丢步重则损坏电机连杆机构。我的经验是在状态机里加一个“切换过渡”的子状态检测到模式切换后先读取当前电机档位然后以每200ms降/升一档的速度向目标档位逼近。这样电机转速变化是斜坡式的物理冲击小视觉上也舒服。这个处理在仿真里看不出多大区别但实物上区别明显属于“仿真通过却实物翻车”的高发区。注意切换模式时蜂鸣器也可以做一个短暂的“滴”声表示切换成功同时把模式字符串在LCD上更新。这个小细节能明显提升交互体验不是炫技是实用。4. 上位机与通信链路上位机这块很多课设新手怕得不行觉得“上位机写一个复杂的软件界面”。其实在这类系统里上位机的作用就两个接收数据、下发参数。实现方式没你想的那么玄乎先串口助手调通再考虑界面是我一直推荐的路径。4.1 串口通信协议设计别用裸数据STM32和上位机之间的通信我强烈建议设计一个简单的协议帧不要直接往串口丢裸的“12.34 56.78”这种数据。裸数据的解析是个灾难数据长度不定、小数点位不一样、上位机不知道一帧数据的边界在哪。一个最精简的协议帧格式可以这样定字节序号内容说明0帧头0xAA固定帧头1功能码0x010x01表示上报数据0x02表示下发阈值2数据长度4后面有效数据字节数3-6数据域例如4字节float瞬时流量7校验和前面字节累加取低8位协议帧解析的核心是“状态机超时判断”上位机或单片机逐字节接收状态机的状态依次为“等待帧头→检查功能码→接收长度→接收数据→校验”。任何一个环节失败就重置状态机等待新帧头。这个模式看着简单却是所有通信系统的基础掌握了一次能用在所有串口项目里。4.2 上位机开发从串口助手到简单界面第一步用现成的串口助手比如XCOM直接把STM32发送的帧数据打印出来验证协议帧是否正确。能通过这个测试整个通信链路就成功了一半。很多人跳过这一步直接去写上位机结果通信没通却以为是上位机问题浪费时间还打击信心。第二步再写一个简单的上位机界面。语言选择上C#的SerialPort控件或Python的pyserial库都行。如果是毕设或者要展示给别人看C#的Windows窗体程序看起来更“像样”如果只是自己调试用Python加一个Tkinter界面半小时就能搞定。下面的代码是C#串口接收并解析帧的核心逻辑和STM32端的状态机思路完全对应。private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] buffer new byte[serialPort1.BytesToRead]; serialPort1.Read(buffer, 0, buffer.Length); foreach (byte b in buffer) { // 协议状态机解析 switch (rxState) { case RxState.WaitHeader: if (b 0xAA) rxState RxState.GotHeader; break; case RxState.GotHeader: if (b 0x01) rxState RxState.ReadLen; else rxState RxState.WaitHeader; break; case RxState.ReadLen: bytesRemain b; rxState RxState.ReadData; break; case RxState.ReadData: recvBuf[recvIndex] b; bytesRemain--; if (bytesRemain 0) rxState RxState.CheckSum; break; case RxState.CheckSum: // 校验通过后解析数据触发界面更新 ParseFrame(recvBuf, recvIndex); rxState RxState.WaitHeader; break; } } }这里提醒一个特别容易踩的坑C#的SerialPort.DataReceived事件是在后台线程触发的直接在这个事件里更新Windows窗体的控件会报线程间操作错误。解决办法是使用Invoke或BeginInvoke把UI更新操作切回主线程。这个坑几乎每个初写C#上位机的人都会遇到提前了解能省一晚上查资料的时间。4.3 Proteus虚拟串口与上位机的联调方式这是这个项目最“神奇”也最容易卡住的一步。Proteus里的STM32芯片如何和电脑上运行的上位机通信答案是使用虚拟串口。Proteus的COMPIM组件可以连接到物理串口或者虚拟串口配合VSPD这类免费的虚拟串口软件成对创建COM0和COM1一头连Proteus的COMPIM一头连上位机使用的串口号数据就能实时流通。具体配置流程是先用VSPD创建一对虚拟串口比如COM3和COM4然后在Proteus里放置COMPIM组件设置物理串口为COM3波特率改为和STM32程序一致比如9600或115200最后上位机打开COM4就能收到数据。这套流程本质上就是“串口透传”在仿真阶段完全够用。提示VSPD创建虚拟串口对时端口号不要跟电脑上实际存在的串口冲突。如果仿真时发现上位机收不到数据先检查Proteus的COMPIM是否选择了正确的虚拟串口再检查波特率是否一致这两个原因占了九成。5. 常见问题与排查技巧实录这个项目做到最后基本上大家遇到的问题都出在几个“经典位置”上。我把这些年带学生和自己调试中高频出现的问题整理成一份速查表配合排查思路讲透你遇到对应现象时直接对号入座。现象直接原因排查方法STM32仿真“不跑”程序烧进去没反应晶振配置或PLL配置错误检查SystemInit中的RCC配置确认系统时钟为72MHzLCD1602无显示或黑影一块初始化时序不完整或数据线接错对照数据手册检查RS/EN时序确认上下拉电平LCD显示乱码4线模式初始化序列不对严格按“40ms → 0x03×3 → 0x02 → 0x28 → 0x0C”顺序初始化频率测量值偏大或偏小定时器时钟频率计算错误检查APB1分频是否导致TIM2时钟倍频步进电机只振动不转脉冲频率太高或时序不对降低脉冲频率确认四相时序顺序正确电机转向反了相序反了调换D组和C组任意一组接线或交换软件里相序编码上位机收不到数据COMPIM设置错误或串口被占用检查虚拟串口是否配对关闭占用串口的程序数据乱码波特率不一致统一STM32串口初始化和上位机的波特率5.1 STM32仿真“不跑”的最常见原因Proteus仿真STM32时最典型的症状是芯片供电正常程序烧进去了但IO口没有任何反应。这个问题的元凶绝大多数情况是时钟配置不对。Proteus的虚拟STM32芯片对晶振仿真是比较“严格”的你需要在Proteus里给芯片加上8MHz晶振电路同时STM32程序内部的RCC配置也要正确。如果你在代码里开了HSE外部高速时钟但Proteus里没接外部晶振仿真就卡死在启动阶段。解决办法是确认Proteus原理图里STM32的OSC_IN和OSC_OUT引脚接上了8MHz晶振和两个匹配电容比如20pF并且程序里SystemInit函数正确配置了PLL。如果实在排查不出来可以在仿真的芯片属性里把HSE参数改为仿真默认值也可以临时改用HSI内部晶振跑一下先把其他模块调通回头再解决外部晶振问题。5.2 LCD1602的玄学不显示排查LCD1602不显示我总结了一个“三板斧”排查法一查电源确认仿真里LCD的VSS接地、VDD接5VV0对比度脚接合适的分压仿真里可以直接接地或接一个2k电阻到地二查初始化时序LCD1602要求上电延时40ms以上之后RS保持低电平命令模式所有控制时序必须严格满足建立时间和保持时间的下限三查数据线4线模式下确认D4-D7对应关系没错位。一个非常隐蔽的坑Proteus里LCD1602的V0脚如果不接地显示器上可能什么都看不到或者只有一个黑块。如果你在实物上习惯了V0接电位器调对比度仿真里很容易忽略这个引脚。接错对比度哪怕程序完全正确屏幕也是“罢工”状态这个经验分享给所有第一次在Proteus里用LCD的新手。5.3 步进电机的“死机”式抖动前面提到过步进电机只振动不转多数是脉冲频率太高电机跟不上驱动时序也就是俗称的“丢步”。25BYJ-48在12V驱动下的空载启动频率大约在500Hz左右超过这个频率就可能失步。放在这个项目里如果上位机下发了一个很高的转速指令或者自动模式PID计算输出一个过高的PWM频率电机就会卡在“抖动”状态看起来像是系统死机了其实是脉冲太快。处理方式有两个层面一是在软件上做“限幅”即无论手动档位还是自动输出都限制最大脉冲频率不超过失步临界值二是在硬件驱动上提高电机供电电压能显著提高启动频率上限。在仿真里你可以直接检查PWM输出的频率数值和波形看看是不是跑到几千赫兹了。5.4 流量数据跳变与单位换算混乱流量数据的显示问题经常是单位换算搞得人心态崩溃。传感器的K值、频率测量周期、时间基准这三者的单位不统一计算结果必然错乱。我习惯用固定时间闸门法测量频率每秒钟统计一次脉冲个数这样频率数值直接等于脉冲个数然后根据K值换算出流速和流量整个计算链路就不会乱。举个例子假设K100脉冲/升1秒内计到350个脉冲频率就是350Hz一秒内的流量就是350/1003.5升。要注意的是如果采样周期不是1秒流量计算时一定要乘上时间系数比如500ms的采样窗口每秒流量就得把窗口内脉冲数乘以2再除以K。很多人漏掉这个系数导致累计流量越差越大回头怀疑公式有问题——不是公式的问题是时间基准没统一。还有一点如果你用的是“输入捕获算周期”测频率要注意在流量很小、脉冲间隔很长时测量周期会拉得很长导致瞬时流量刷新非常滞后。实际项目中可以考虑低频时切换为“外部中断计数固定时间窗口”的方式让测量节奏更均匀。这类细节属于“做产品”才需要的优化做课设可能无所谓但我个人建议至少要知道有这种问题存在将来面试被问到流量计原理时能讲出这个深度会让面试官眼前一亮。6. 从仿真到实物的几个关键提醒仿真跑通之后很多人兴冲冲去打板或者买开发板结果实物的坑比仿真多得多。第一Proteus的元件模型都是理想化的实际传感器输出可能有毛刺、电平不匹配最好在STM32的输入捕获引脚前加一个RC滤波和施密特触发器整形避免毛刺造成误计数。第二步进电机驱动芯片要加续流二极管ULN2003内部自带续流但用其他驱动芯片时千万别漏掉这个保护。第三蜂鸣器如果是有源蜂鸣器记得在驱动管上加上吸收二极管否则断电瞬间的反向电动势容易搞坏MCU引脚。另外实测的K值校准是实物调试里躲不开的一关。把传感器装好用标准容器接水让流量计转起来记录实际水量和脉冲数算出真实的K值再回填到程序里。不要迷信铭牌参数每一只传感器的个体差异都可能让流量误差大到不可接受。我个人在实际操作中的体会是这个项目的成败不在哪一块技术特别高级而在于模块之间的“咬合”是否严丝合缝。流量数据出来之后显示、报警、电机控制、上位机通信全都依赖同一份数据的正确性。把时间花在捋清楚数据流和控制流上比闷头多写几百行代码管用得多。做这个系统的时候我建议你把“模块化”刻在脑子里把采集、控制、显示、通信四块代码的接口提前定义清楚后面无论怎么改需求都不会伤筋动骨。最后再分享一个锦上添花的扩展方向把流量数据的实时记录功能加上去也就是每分钟或每小时在EEPROM或Flash里存一条历史数据然后通过上位机读取历史数据画成曲线。这不算什么高深的技术但它能让你从“搞出一个能亮能转的系统”进化到“搞出一个能用的系统”面试聊项目时聊到历史数据存储和趋势分析会比你只会说“我用了LCD1602显示”高一整个段位。本文还有配套的精品资源点击获取