赞
踩
目录
基于Arduino的智能洗手机,本文详细介绍该项目设计到实现,各个组件及其工作原理,以及组装,并附源码和注释。
本次设计采用ATMEG328P芯片制作Arduino最小系统板,课题主要研究恒温水箱以及通过超声波传感器自动感应出水。智能洗手机的恒温 水箱部分实现实时监测水温度和液位,并在显示屏上显示,当水温度低于阈值时,加热棒对水进行加热,到设定值后停止加热,以保证出水温度恒定。智能洗手机采用两 个超声波模块,两个出口,标明出水口和洗手液出口,当超声波传感器监测距离低于阈值,自动启动继电器模块驱动电机出水或洗手液。采用液位传感器,监测水位,当 水位低于阈值,指示灯闪烁,提示水箱水余量不足。
ATMEGA328P 是一款 8 位具有 AVR 知识产权的微控制器,即 MCU,具有低 功耗,高性能的特性和高级精简指令集架构,ATMEGA328P 主频可以达到 20MHz, 此时它的指令吞吐量可以达到 20MIPS,即每秒可以完成 20 个百万条指令。 ATMEGA328P 采用高耐用性非一时性存储器,即片上可编程的的 32KB Flash,其中 0.5KB 用于 Bootloader,同时还有 2KB 的 SRAM,即静态随机访问存储器。 ATMEGA328P 芯片拥有 14 路数字输入输出口,工作电压为 5V,输入和输出的最大 电流为 40mA,每一路配置了 20-50K 的欧姆内部上拉电阻[8]。ATMEGA328P 芯片具 有内部时钟,可以实现上电复位,对于芯片外部的引线,只需要加上电源就可以工作, 同时具有丰富的外设,外设包含两个 8 位的定时器,一个 16 位的定时器,一路时钟 和 6 路 PWM 通道,8 路 10 位的 ADC 以及通信串口,SPI 口。
ATMEGA328P 芯片的共 28 个引脚,可以工作的电压从 1.8V 到 5.5V 都可以, 工作温度为-40-85 摄氏度其中 2 号和 3 号引脚分别为 RXD 和 TXD 用于串口通信, 在本文制作最小系统板的电路中,也通过这两个引脚连接 CH340 芯片,用于上传程 序部分,当 2 号和 3 号引脚与外部芯片的 RX 和 DX 连接,在没有数据传输的时候为 高电平,有数据传输的时候会出现高低电平交替的脉冲。AREF 引脚和 AVCC 分别为 模拟电源的参考电压和正极,而 VCC 与 GND 是实际电源的正极和负极。整个 ATMEGA328P 芯片集成了 CPU、内存、硬盘、中断系统、电源系统以及总线系统, 实际上已组成了一个独立的嵌入式计算机系统。
本文所用两个22pf的电容,主要作用是过滤掉晶振部分的高频信号,从而使晶振工作的时候更加稳定,而晶振是单片机工作的心脏,为系统提供基准时钟信号,系统内所有的工作都是以这个时钟信号为步调基准来进行的。
看到框架图就会发现这个系统其实很简单,就是通过超声波感应出水,同时用温度传感器去监测和控制水温,以及液位传感器监测水位报警,然后将温度和液位值数据显示在显示屏上就欧克了。
它的组成其实很少,主要有以下几个模块:
(1)HC-SR04超声波测距模块常应用于智能小车或机器狗避障、实物端测距、停车场检测和倒车监视以及雷达等技术领域;该模块性能稳定,测度距离精确,甚至可以与国外的SRF05、SRF02等超声波测距模块相媲美,它的探测距离为2cm-450cm,精度可达0.2cm;使用五伏电压;有四个引脚,除了VCC和GND,还有Trig控制端和Echo接收端。
(2)HC-SR04超声波传感器工作原理及时序图:
HC-SR04时序图
①采用IO口Trig触发测距,给至少10us的高电平脉冲;
②模块自动发送八个40KHz方波,检测是否有信号返回;
③当有信号返回时,通过IO口Echo输出一个高电平,高电平持续时间即超声波从发射到返回的时间;
④可以得到测距公式:距离=(高电平时间*声速)/2;
(3)本文中的HC-SR04超声波传感器接线示意:
表1 HC-SR04模块一接线示意表
HC-SR04 | ATMEGA328P芯片 |
VCC | 5V |
Trig | D8 |
Echo | D9 |
GND | GND |
表2 HC-SR04模块二接线示意表
HC-SR04 | ATMEGA328P芯片 |
VCC | 5V |
Trig | D10 |
Echo | D11 |
GND | GND |
pulseIn(echo,HIGH)/58.0,在写代码的时候有人不理解58的意思,这里做一下解释:
时间差测距法:超声波向某一方向发射超声波,在发射的同时开始计时,在发射途中遇到障碍物返回,收到反射波停止计时,得到时间t,即可得到距离:s=340*t/2;
pulseIn函数是一个测量脉冲宽度的函数,默认单位是us,即此函数得到的是超声波从发射到接收所用的时间。声音的传播速度为340m/s,换算后为29.15us/cm,超声波发射还要返回来,所以声音走过两倍的距离,对应58.3us/cm,每个cm需要58us,用测得的总时间除以58即可得到有多少个cm。
(1)液位指示器有六种基本类型:电阻式、电容式、超声波式、频率式、导波GWR和压力传感器。本文采用简单且性价比较高的Water Sensor for液位传感器,是通过两组双面锡制的平行线线迹测量其位置从而判断液位,完成液位到模拟信号的转换,继而被开发板读取,达到液位报警的功效。暴露出的锡制平行线分为两组,同组的导线相连,通过液体的导电性与另一组相连,如果液位上升,经过导线并回到回路的电流增大,并由三极管转化为相应变化的模拟信号输出,再通过Arduino,即外部系统读取值的变化。Water Sensor for液位传感器有三个引脚,使用5V电源运行,并以模拟格式输出数据。液位传感器VCC引脚是电源引脚,接5V电源即可,GND为电路板的接地引脚,S表示电路板的模拟输出引脚,它将在VCC和GND之间提供模拟信号,引脚模拟信号输出可接AD转换器或单片机的AD转换引脚。
(2)实物示意图及特性:
水位传感器示意图
①工作电压:3-5V;
②工作湿度:10%-90%无凝结;
③工作电流:小于20mA,10-30摄氏度;
(3)工作原理:该模块主要是利用三极管的电流放大原理,当液位高度使三极管的基极与电源正极导通的时候,在三极管的基极和发射极之间就会产生一定大小的电流,此时在三极管的集电极和发射极之间就会产生一个一定放大倍数的电流,该电流经过发射极的电阻产生电压,被AD转换器采集。
(4)接线示意表:
表3 Water Sensor液位传感器接线示意表
Water Sensor水位传感器 | ATMEGA328P芯片 |
+ | 5V |
- | GND |
S | A0 |
(1)OLED,有机发光二极管,又称有机发光半导体,是当下非常受欢迎的显示设备。OLED显示屏与传统LCD显示方式不同,它无需背光,每个像素点自发光,体积更小、更轻薄、更省电,而且能做成柔性屏。因为这些优点,它被越来越多的应用到嵌入式电子设备中。OLED种类不同,显示的颜色也不同,常用的有白色显示、蓝色显示和黄蓝双色显示,屏幕的尺寸和内置驱动芯片也多种多样,常用的驱动接口有SPI和IIC驱动屏,其内置驱动芯片为SSD1306。
(2)本文采用基于SPI协议的0.96寸4针OLED显示屏,其实物如下图所示:
OLED模块示意图
SPI是一种同步串行接口技术,以主从方式工作,采用全双工同步通信,数据可以在两个方向同时进行收发操作。
(3)SPI的四线结构分别是CS、SCK、MISO、MOSI。其中CS称为片选信号线,当有多个从设备时,可以用于选择需要的从设备,拉低片选信号即可开始通信;SCK称为串行时钟,与I2C协议的SCL一样,为SPI通信提供时钟;MISO用于主机向从机发送数据,即主机输出数据,从机接收数据;MOSI与MISO相反,从机输出数据,主机接收数据。下图5为SPI工作原理的时序图,从图中可以看到,由于SPI的全双工通信,所以读写时序可以同时完成,CS片选信号先拉低,开始通信, MISO和MOSI在SCK的每个时钟周期传输一位数据,且同时进行,最后再取消片选引脚。
SPI工作时序图
(4)SPI通过串行时钟(CPOL)和相位(CPHA)的搭配得到四种工作模式,这四种工作模式如下图6所示。当CPOL=0时,串行时钟空闲状态为低电平;CPOL=1时,串行时钟空闲状态为高电平,此时通过配置时钟相位(CPHA)来选择具体的传输协议;当CPHA=0时,串行时钟的第一个跳变沿采集数据;当CPHA=1时,串行时钟的第二个跳变沿采集数据。
SPI四种模式工作时序图
(1)超声波模块:检测人手或物体与超声波传感器距离,当距离低于5cm,启动电机,工作状态;当距离高于5cm,进入待机状态;同时检测距离在串口端显示;
(2)液位传感器模块:监测液位,同时在串口显示;
(3)LED指示灯:当液位低于阈值,指示灯闪烁两次并循环,提示补充水箱的水,当液位正常,指示灯常亮,工作正常;
(4)DS18B20:水温度传感器,实时监测水箱温度,并在串口实时显示;
(5)OLED:显示屏模块,实时显示水箱水的温度以及液位传感器监测的数值;
(6)微型发热器管:用于给水加热;
(7)继电器模块:本文采用三个继电器模块,其中一个控制加热棒的工作状态,当水温低于阈值,继电器开启,加热棒工作,当水温达到阈值,继电器关闭,加热棒待工作状态;另外两个控制电机水泵和泡沫泵,当超声波模块检测到工作区域的值,继电器模块驱动电机成为运行状态。
恒温水箱使水温保持一个设定的恒定值,并实时显示温度;当人手靠近出水口感应区,并低于5cm时,自动出水,人手离开后,感应区5cm内未检测到障碍物,关闭水阀;同理,另一个出口为洗手液的出口,采用另一个超声波模块进行检测。当水箱水余量不足时,指示灯循环闪烁,提示工作人员加水,当水位正常时,指示灯关闭,为正常工作状态。下图为智能洗手机的工作流图:
智能洗手机工作流图
下面为该项目所需主控板及硬件材料:
项目材料表
数量 | 说明 | |
ATMEGA328P芯片 | 1 | 制作Arduino UNO最小系统板 |
Water Sensor for液位传感器 | 1 | 监测水位 |
HC-SR04超声波传感器 | 2 | 监测距离 |
LED指示灯 | 1 | 水位余量的报警显示 |
5V蠕动泵 | 1 | 用于泵水 |
项目材料表(续表)
材料 | 数量 | 说明 |
5V泡沫泵 | 1 | 供洗手液,并将洗手液转化为泡沫 |
16M晶振 | 1 | |
22pf电容 | 2 | |
220欧姆电阻 | 1 | |
330欧姆电阻 | 1 | |
CH340芯片 | 1 | |
OLED显示屏 | 1 | 显示温度和液位值 |
继电器 | 3 | 控制开关 |
微型加热棒 | 1 | 对水加热 |
DS18B20温度传感器 | 1 | 监测水温 |
电阻 | 若干 | |
导线 | 若干 |
(1)下面为智能洗手机从主控板到各个模块的组装和接线图,其中包括了ATMEGA328P芯片连接成为Arduino最小系统板的线路图,本文使用CH340C作为串口芯片,须注意串口芯片的TXD要与ATMEGA328P芯片的RXD连接,串口芯片的RXD与ATMEGA328P芯片的TXD连接,中间的220欧姆电阻用于防止振荡。
系统连接示意图
根据本文整体连线图和组装完成后,可以在串口监视器上看到实时的温度和液位数据显示,如图所示:
串口监视器示意图
在实物图显示屏上也可以看到实时的数据变化
在图中可以看到液位值为0,此时液位低于阈值,所以指示灯亮起。
本文在测试过程中发现CH340芯片在供给整个系统的电源时,出现电压不稳的情况,因此采用外部电源适配器,可以将外部电源转为固定5V输入。
在液位传感器模块的工作过程中,因为水质的不同,例如高碱性水质,会影响液位传感器的读取值,因此需要在用水之前单独根据水质采集水位传感器最高和最低值,将值映射到水位传感器的实际长度值,然后将其转为单位为毫米的值。
以下为本文所采用的Arduino IDE编程软件的程序全文:
- #include <Arduino.h>
- #include <Wire.h>
- #include <SoftwareSerial.h>
- #include <OneWire.h>
- #include <DallasTemperature.h>
- #include <SPI.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- #define OLED_RESET -1//初始化oled屏用的参数
- #define ONE_WIRE_BUS 12 //定义DS18B20数据口
- Adafruit_SSD1306 siran_oled_128_64_display(128, 64, &Wire, OLED_RESET);//初始化oled屏,这个屏幕是128*64大小的,所以对象名称里加了_128_64
- OneWire oneWire(ONE_WIRE_BUS); //声明连接在单总线上的单总线设备DS18B20测温模块
- DallasTemperature sensors(&oneWire); // 声明一个DS18B20对象
- int tempratue_last;//上次温度(OLED屏显示的数字会叠加到一起,所以显示新数字的时候要调用刷屏函数,刷掉上次显示的数字,然后再显示新数字,这个变量存储上次测得的温度,这个数值要同现在测得的数字进行比较,如果不同就刷屏,显示新数字,如果相同,就不刷屏)
- int depth_last;//上次深度
- double tap;//距水龙头超声波距离
- double foam;//距泡沫机超声波距离
- void setup(){
- //Serial.begin(9600);
- sensors.begin(); //DS18B20总线初始化
- siran_oled_128_64_display.begin(SSD1306_SWITCHCAPVCC,0x3C);//初始化OLED屏
- siran_oled_128_64_display.clearDisplay();//OLED屏幕刷屏,刷掉上面已有的数字
- siran_oled_128_64_display.display();//OLED屏开始显示
- siran_oled_128_64_display.fillScreen(0);//参数0表示背景黑色,1表示背景白色
- siran_oled_128_64_display.display();//OLED屏开始显示
- pinMode(2,OUTPUT);//水泵的继电器
- pinMode(3,OUTPUT);//泡沫机继电器
- pinMode(4,OUTPUT);//加热棒继电器
- pinMode(7,OUTPUT);//led
- digitalWrite(2,0);//次继电器是高电平有效,所以,开始是低电平。
- digitalWrite(3,0);//次继电器是高电平有效,所以,开始是低电平。
- digitalWrite(4,0);//次继电器是高电平有效,所以,开始是低电平。
- digitalWrite(7,0);//led灯开始是熄灭状态
- pinMode(A0,INPUT);//深度传感器在A0
- sensors.requestTemperatures(); //向温度模块请求温度值
- tempratue_last=sensors.getTempCByIndex(0);//温度模块返回的单位是摄氏度的温度
- depth_last=analogRead(A0);//获取水深值
- depth_last=map(depth_last,60,670,0,40);
- siran_oled_128_64_display.setTextColor(1);//参数1表示字体白色
- siran_oled_128_64_display.setTextSize(2); //字体大小2像素
- siran_oled_128_64_display.setTextWrap(1);//参数1表示可以自动换行
- siran_oled_128_64_display.setCursor(1, 1);//在位置(1,1)
- siran_oled_128_64_display.println(depth_last);//显示水深
- siran_oled_128_64_display.setCursor(50, 1);//在位置(50,1)
- siran_oled_128_64_display.println("mm");//显示mm
- siran_oled_128_64_display.setCursor(1, 20);//在位置(1,20)
- siran_oled_128_64_display.println(tempratue_last);//显示温度
- siran_oled_128_64_display.setCursor(50, 20);//在位置(50,20)
- siran_oled_128_64_display.println("C");//显示c
- siran_oled_128_64_display.display();//只有加这个函数,前面的设置才生效。
- }
- void loop(){
- sensors.requestTemperatures(); //向温度模块请求温度值
- int tempratue_now=sensors.getTempCByIndex(0);//温度模块返回的单位是摄氏度的温度
- int depth_now=analogRead(A0);//获取水深值
- depth_now=map(depth_now,60,670,0,40);
- if(tempratue_now!=tempratue_last||(abs(depth_last-depth_now)>3)){
- tempratue_last=tempratue_now; // 用本次测得数值保替代上次测得的数值
- depth_last=depth_now;// 用本次测得数值保替代上次测得的数值
- if(depth_last<=0)depth_last=0;//传感器从有水接触变成没有水接触,数值会变成负数,其实负数就表示没有水了,所以是负数的时候,将他设置为0;
- siran_oled_128_64_display.clearDisplay();
- siran_oled_128_64_display.display();
- siran_oled_128_64_display.setCursor(1, 1);
- siran_oled_128_64_display.println(depth_last);
- siran_oled_128_64_display.setCursor(50, 1);
- siran_oled_128_64_display.println("mm");
- siran_oled_128_64_display.setCursor(1, 20);
- siran_oled_128_64_display.println(tempratue_last);
- siran_oled_128_64_display.setCursor(50, 20);
- siran_oled_128_64_display.println("C");
- siran_oled_128_64_display.display();
- }
- if(depth_last<=10)
- {
- digitalWrite(7,1);//如果水位小于或等于10,LED闪烁
- delay(500);
- digitalWrite(7,0);
- delay(500);
- }
- if(depth_last>10)digitalWrite(7,0);//如果水位大于10,LED灭
- if(tempratue_last<30&&depth_last>0)digitalWrite(4,1);//如果温度小于30,深度大于0,加热棒加热
- if(tempratue_last>=30|| depth_last<0)digitalWrite(4,0);//如果温度大于30,或深度小于0,停止加热。
- for(int i=1;i<=5;i++){ //连续测量5次,取平均值
- tap+=getDistance(10,11);
- foam+=getDistance(8,9);
- tap/=5;
- foam/=5;
- }
- if(tap<=5&&tap!=0) {digitalWrite(2,1);delay(3000);}//如果超声波(接口10,接口11)测到距离小于5cm,并且不等于0,控制水龙头的继电器接通
- if(tap>5) digitalWrite(2,0);//如果超声波(接口10,接口11)测到距离大于5cm,控制水龙头的继电器断开
- if(foam<=5&&foam!=0) {digitalWrite(3,1);delay(2000);}//如果超声波(接口8,接口9)测到距离小于5cm,并且不等于0,控制泡沫机的继电器接通
- if(foam>5) digitalWrite(3,0);//如果超声波(接口8,接口9)测到距离大于5cm,控制泡沫机的继电器断开
- }
- //超声波测距函数
- float getDistance(int trig,int echo){
- pinMode(trig,OUTPUT);
- digitalWrite(trig,LOW);
- delayMicroseconds(2);
- digitalWrite(trig,HIGH);
- delayMicroseconds(10);
- pinMode(echo, INPUT);
- return pulseIn(echo,HIGH,30000)/58.0;}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。