基于arduino的智能水温监控器

来源:互联网 发布:dota2和lol的区别 知乎 编辑:程序博客网 时间:2024/04/28 05:28

首先需要声明的是,这个东西很久之前已经有人做了,我只是自己做出来一个然后
写写经验教训。

它的用途:在很多时候我们需要喝温水,然而刚接出来的开水往往很烫,不适合饮用。所以我们会选择把它晾在一边,忙别的事,忙着忙着就把水忘了,等到喝水的时候,它已经不是我们想要的温度了。这个水温监控器就是用来防止这样的现象,用户可以自己来设定温度,当水温比这个温度低的时候,它的蜂鸣器就会响,也就是提醒用户喝水。

它主要由四部分组成:
这里写图片描述

首先arduino uno不必赘述。

然后lcd1602液晶屏也很好在arduino上操作,具体可以参考arduino
官方例程,就是arduino ide里的文件/示例/LiquidCrystal/hello world
,那个例程会教你怎么让lcd1602显示且不滚屏。
它的硬件电路如图:
这里写图片描述
值得说明的是,电位计是非常重要的,我一开始也用电阻,但是总是不显示,因为背光率没法比较准确的调节。

重点就在于如何实现温度传感器测温,这里我选择的是DS18B20,达拉斯公司推出的单总线温度传感器,易于操作而且经典。
它的硬件电路很简单:
这里写图片描述

但是写程序不太简单。当然不简单也是相对的,至少比51单片机简单多了。写程序伊始,我参考的是一本讲arduino的教程,上面用到了两个头文件,分别是OneWire.h和DallasTemperature.h,结果就是,最初的尝试都没有成功。在编译的时候,DallasTemperature.c里的内容就会出错,然后根据网上的指点,把Wprogram.h改成arduino.h或者在其下面加一段关于arduino.h的代码,嗯,编译不会出错了,但是测温会显示一个神奇的数字,127度。这说明DS18B20根本没有测温。然后我怀疑会不会是IDE的版本太新了,换一个旧版本会不会好,于是兴致勃勃地去下载了一个0022版本,结果仍是失望。那就不得不走一条新路了。

那时我一直纠结于是像给51写程序一样,各种时序、指令,还是利用现成的库函数,直到我打开了Onewire的文件夹,发现了一个例程,它有一个美丽的名字,DS18x20_Temperature。它是用来串口显示温度的,拿它来试了一下,在串口监视器成功地出现了摄氏温度和华氏温度,跟空调的温度一样的哦。于是希望重燃,既然它可以在串口上显示温度,那么稍加更改,不也就能在LCD上显示温度了吗?

然而命运总是喜欢开玩笑,在proteus里,仿真的结果仍是127度,让人心灰意冷,但是我抱着试一试的想法,在面包板上试了一下,居然在LCD显示出了实时温度。可见,proteus其实还有待改进,而且有些事不去试试永远不会知道结果。

以下是目前为止的原理图:
这里写图片描述
事实上,arduino在proteus里有专门的库,只不过收费而已,但是总有大佬有资源,下载频道就有,我就不分享了。

最难的已经克服了,只剩下蜂鸣器和按键控制了。原理图如图:这里写图片描述
这里写图片描述

它们就容易很控制了,需要注意的就是按键控制时,电路用了硬件消抖,程序里就不要再有软件消抖了,我过去试过这样做,按键会不起作用的。

至此,这个智能水温监控器就基本做完了,以下是代码:

#include <LiquidCrystal.h>#include <OneWire.h>LiquidCrystal lcd(12,11,5,4,3,2);OneWire  ds(10);  // on pin 10int beep = 9;int add = 7;int minus = 6;float controline = 25;void setup() {  // put your setup code here, to run once:  Serial.begin(9600);  lcd.begin(16,2);  lcd.print("Hello world");    pinMode(beep, OUTPUT);  pinMode(add,INPUT);  pinMode(minus,INPUT);}void loop() {  byte i;  byte present = 0;  byte type_s;  byte data[12];  byte addr[8];  float celsius, fahrenheit;  if ( !ds.search(addr)) {    ds.reset_search();    delay(250);    return;  }  for( i = 0; i < 8; i++) {    Serial.write(' ');    Serial.print(addr[i], HEX);  }  if (OneWire::crc8(addr, 7) != addr[7]) {      return;  }  ds.reset();  ds.select(addr);  ds.write(0x44,1);         // start conversion, with parasite power on at the end  delay(1000);     // maybe 750ms is enough, maybe not  // we might do a ds.depower() here, but the reset will take care of it.  present = ds.reset();  ds.select(addr);      ds.write(0xBE);         // Read Scratchpad  for ( i = 0; i < 9; i++) {           // we need 9 bytes    data[i] = ds.read();  }  // convert the data to actual temperature  unsigned int raw = (data[1] << 8) | data[0];  if (type_s) {    raw = raw << 3; // 9 bit resolution default    if (data[7] == 0x10) {      // count remain gives full 12 bit resolution      raw = (raw & 0xFFF0) + 12 - data[6];    }  } else {    byte cfg = (data[4] & 0x60);    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms    else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms    else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms    // default is 12 bit resolution, 750 ms conversion time  }  celsius = (float)raw / 16.0;  if(digitalRead(add) == HIGH) controline += 1;  if(digitalRead(minus)==HIGH) controline -= 1;  if(celsius < controline) digitalWrite(beep,LOW);  else digitalWrite(beep,HIGH);  lcd.setCursor(0,0);  lcd.print("Temp = ");  lcd.print(celsius);  lcd.print(" C");  lcd.setCursor(0,1);  lcd.print("Setting: ");  lcd.print(controline);}

我很不喜欢硬件实物图,尤其是比较复杂的东西的,因为看起来很乱,没有美感,所以就只上原理图喽。(虽然我画的原理图也难看)
这里写图片描述

原创粉丝点击