如何用ARDUINO制作一个鸟蛋孵化器
項目背景介紹
經常養寵物的朋友,遇到寵物繁殖很是頭疼,特別是鳥類繁殖,更加需要一個恒溫恒濕的孵化箱。市面上孵化箱種類繁多,從幾十塊的到上千塊的孵化箱都有,性能參差不齊,有些孵化箱的溫度相差3度是常有的事情,有些沒有濕度數據,于是決定用自己多年自學的三腳貓功夫做一個孵化箱,把制作過程分享給大家。
項目開發環境
`
arduino的c語言開發環境,版本1.61
項目硬件設備
| 單片機 | ARDUINO UNO | 1 | 孵化器主要控制芯片 |
| 電源 | 開關電源12V100W | 1 | 給整個孵化箱提供12v供電 |
| 照明 | LED燈帶 | 1 | 孵化箱照明用 |
| 保溫外箱 | 蜥蜴保溫箱40CM | 1 | 保溫 |
| 發熱片 | 12V50W低壓型PTC鋁殼250度恒溫發熱片 | 2 | 給孵化箱提供熱源 |
| CPU風扇 | 寬度6厘米厚度1.5厘米 | 1 | 恒溫箱空氣循環用 |
| CPU散熱片 | 散熱片 | 1 | 把散熱片的熱量散發到恒溫箱空氣中 |
| 魔術板 | EPP發泡板2毫米厚度 | 若干 | 制作發熱片散熱通風管道 |
| 電子開關 | MOS觸發開關12V | 2 | 用于控制散熱片和加濕器 |
| 加濕器 | usb加濕模塊 | 1 | 控制濕度 |
| 溫濕度傳感器 | SHT20 | 1 | 溫濕度傳感器 |
| 塑料袋 | 塑料袋 | 若干 | 用于鋪于鳥蛋底下,恒溫作用 |
| 降壓模塊 | 12V轉5V降壓模塊 | 1 | 用于給usb加濕模塊提供5V電源用 |
| 液晶顯示器 | 0.96寸OLED顯示屏 | 1 | 顯示溫度、濕度、孵化時間和孵化狀態 |
硬件接線圖
代碼
tempadmin.cpp
//#include <SHT1x.h> #include <EEPROM.h> #include <Servo.h> #include <Wire.h> #include "U8glib.h" #include "TempAdmin.h" #include "DFRobot_SHT20.h"//SHT1x sht1x(dataPin, clockPin); DFRobot_SHT20 sht20;void inQueue(QUEUE * pQueue,int value) {pQueue->pBase[pQueue->point]=value;pQueue->point=++pQueue->point%6;//Serial.println(pQueue->point); }int traverseQueue(QUEUE * pQueue) {int n=pQueue->point;int a=0,b=0,nCount=0;do{if(nCount<3){a+=pQueue->pBase[n];}else{b+=pQueue->pBase[n];}n=++n%6;nCount++;}while(n!=pQueue->point);return (b-a); }void TrunEggs(void) {int nAngle=myservo1.read();//Serial.println(nAngle);//Serial.println(nDestAngle);if(abs(nAngle-nDestAngle)<6){nAngle=nDestAngle;myservo1.write(nAngle);return;}if(nDestAngle>nAngle){nAngle+=6;myservo1.write(nAngle);return;}else if(nDestAngle<nAngle){nAngle-=6;myservo1.write(nAngle);return;} }void drawSetting(void) {char chShowStr[100],chTemp[100];float fPre;// graphic commands to redraw the complete screen should be placed here u8g.setColorIndex(1); // pixel onu8g.setFont(u8g_font_unifont);dtostrf(fSetTemp,4,2,chTemp);sprintf(chShowStr,"TEMP: %s C",chTemp);u8g.drawStr( 0, 12, chShowStr);u8g.drawBox( 0, 15, 128,16);u8g.setColorIndex(0); // pixel ondtostrf(fSetTempOff,4,2,chTemp);sprintf(chShowStr,"TEMP OFF: %s C",chTemp);u8g.drawStr( 0, 28, chShowStr);u8g.setColorIndex(1); // pixel ondtostrf(fSetHumi,4,2,chTemp);sprintf(chShowStr,"HUMI: %s %%",chTemp);u8g.drawStr( 0, 44, chShowStr);dtostrf(fSetHumiOff,4,2,chTemp);sprintf(chShowStr,"HUMI OFF: %s C",chTemp);u8g.drawStr( 0, 60, chShowStr);/*if(n_Status){dtostrf(fSetTemp,4,2,chTemp);sprintf(chShowStr,"TEMP: %s C",chTemp);u8g.drawStr( 0, 12, chShowStr);dtostrf(fSetTempOff,4,2,chTemp);sprintf(chShowStr,"TEMP OFF: %s C",chTemp);u8g.drawStr( 0, 28, chShowStr);dtostrf(fSetHumi,4,2,chTemp);sprintf(chShowStr,"HUMI: %s %%",chTemp);u8g.drawStr( 0, 44, chShowStr);dtostrf(fSetHumiOff,4,2,chTemp);sprintf(chShowStr,"HUMI OFF: %s C",chTemp);u8g.drawStr( 0, 60, chShowStr);}else{switch(n_SettingItem){case 0:u8g.drawStr( 0, 12, "TEMP:");break;case 1:u8g.drawStr( 0, 28, "TEMP OFF:");break;case 2:u8g.drawStr( 0, 44, "HUMI:");break;case 3:u8g.drawStr( 0, 60, "HUMI OFF:");break;}dtostrf(fSetTempOff,4,2,chTemp);sprintf(chShowStr,"TEMP OFF: %s C",chTemp);u8g.drawStr( 0, 28, chShowStr);dtostrf(fSetHumi,4,2,chTemp);sprintf(chShowStr,"HUMI: %s %%",chTemp);u8g.drawStr( 0, 44, chShowStr);dtostrf(fSetHumiOff,4,2,chTemp);sprintf(chShowStr,"HUMI OFF: %s C",chTemp);u8g.drawStr( 0, 60, chShowStr);}*///Serial.println(n_Status); }void draw(void) {// graphic commands to redraw the complete screen should be placed here u8g.setFont(u8g_font_unifont);char chShowStr[100],chTemp[100];float fPre;dtostrf(fTemp_c,4,2,chTemp);sprintf(chShowStr,"TEMP: %s C",chTemp);u8g.drawStr( 0, 12, chShowStr);dtostrf(fHumidity,4,2,chTemp);sprintf(chShowStr,"HUMI: %s %%",chTemp);u8g.drawStr( 0, 28, chShowStr);u8g.drawLine(0,32, 108,32);if(digitalRead(nLineHeat)==HIGH)u8g.drawStr( 0, 48, "HEATING");elseu8g.drawStr( 0, 48, " ");sprintf(chShowStr,"%ldDAY %02ld:%02ld:%02ld",nowtime/86400,(nowtime/3600)%24,(nowtime/60)%60,nowtime%60);//sprintf(chShowStr,"%02ld %02ld",nowtime,nowtime%60);u8g.drawStr( 0, 64, chShowStr); }void Process_Temp_Humi(void) {inQueue(&queueTemp,fTemp_c*100);value=traverseQueue(&queueTemp);if(abs(value)<3){//溫度沒有變化if((fSetTemp-fTemp_c)>0.3){digitalWrite(nLineHeat,HIGH);}else{digitalWrite(nLineHeat,LOW);}}else if(value>0){//升溫過程if(fTemp_c<fSetTemp-fSetTempOff){digitalWrite(nLineHeat,HIGH);}else{digitalWrite(nLineHeat,LOW);}}else{//降溫過程if(fTemp_c<fSetTemp+fSetTempOff){digitalWrite(nLineHeat,HIGH);}else{digitalWrite(nLineHeat,LOW);}}inQueue(&queueHumi,fHumidity*100);value=traverseQueue(&queueHumi);if(g_un_count%20==0){if(abs(value)<15){//濕度沒有變化if((fSetHumi-fHumidity)>5){digitalWrite(nLineHumid,HIGH);//Serial.println("code run here!");delaytime=currentMillis+20000;//digitalWrite(nLineHumid,LOW);}}else if(value>0){//加濕過程if(fHumidity<fSetHumi-fSetHumiOff){digitalWrite(nLineHumid,HIGH);delaytime=currentMillis+20000;}}else{//干燥過程if(fHumidity<fSetHumi+fSetHumiOff){digitalWrite(nLineHumid,HIGH);delaytime=currentMillis+20000;}}}g_un_count++; }void setup (void) {Serial.begin(9600); pinMode(nLineHeat, OUTPUT);pinMode(nLineHumid, OUTPUT);pinMode(nTurnEgg, OUTPUT);pinMode(nLineCO2, OUTPUT);pinMode(nSwitch1, INPUT);pinMode(nSwitch2, INPUT);pinMode(nSwitch3, INPUT);// assign default color valueif ( u8g.getMode() == U8G_MODE_R3G3B2 ) {u8g.setColorIndex(255); // white}else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {u8g.setColorIndex(3); // max intensity}else if ( u8g.getMode() == U8G_MODE_BW ) {u8g.setColorIndex(1); // pixel on}else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {u8g.setHiColorByRGB(255,255,255);}queueTemp.point=0;queueHumi.point=0;previousMillis=0;previousMillis2=0;delay2hours=0;nowtime=0;fSetTemp=37.5;fSetHumi=60;fSetTempOff=0.3;fSetHumiOff=6;n_IsSetting=0;myservo1.attach(nTurnEgg);nAngleDirect=0;nDestAngle=20;sht20.initSHT20(); delay(100);sht20.checkSHT20(); }void loop (void) {//read temp and himidity loopcurrentMillis=millis(); //獲取當前的系統運行時間長度if(currentMillis>=previousMillis+DELAY500){previousMillis=currentMillis;//fTemp_c = sht1x.readTemperatureC(); //讀取當前溫度//fHumidity = sht1x.readHumidity(); //讀取濕度fTemp_c = sht20.readTemperature(); //讀取當前溫度fHumidity = sht20.readHumidity(); //讀取當前濕度Serial.println(fTemp_c);Serial.println(fHumidity);if(fTemp_c>0&&fTemp_c<40){//TrunEggs();Process_Temp_Humi();}else{digitalWrite(nLineHeat,LOW);digitalWrite(nLineHumid,HIGH);}// picture loopu8g.firstPage(); do {if(n_IsSetting)drawSetting();elsedraw();} while( u8g.nextPage() );}if(currentMillis-previousMillis2>=ONE_SECOND){previousMillis2=currentMillis;nowtime++;if(nowtime-delay1day>=259200){delay1day=nowtime;fSetTemp-=0.5;}if(nowtime-delay20second>=120){if(digitalRead(nLineCO2)==HIGH){digitalWrite(nLineCO2,LOW);}}if(nowtime-delay2hours>=3600){delay2hours=nowtime;delay20second=nowtime;digitalWrite(nLineCO2,HIGH);if(nAngleDirect){nDestAngle+=35;if(nDestAngle>=160){nDestAngle=160;nAngleDirect=!nAngleDirect;}}else{nDestAngle-=35;if(nDestAngle<=20){nDestAngle=20;nAngleDirect=!nAngleDirect;}}}}//delay fuction//Serial.println(delaytime-currentMillis);if(delaytime<=currentMillis){if(digitalRead(nLineHumid)==HIGH){digitalWrite(nLineHumid,LOW);}}n_IsSetting=0;n_SettingItem=1;//digitalWrite(nLineHumid,HIGH);/*if(digitalRead(nSwitch1)==HIGH){n_IsSetting=1;settingdelay=currentMillis+10000;n_SettingItem=++n_SettingItem&4;}if(settingdelay-currentMillis<=0){n_IsSetting=0;}*/ }tempadmin.h
#ifndef _CPP_TEMPADMIN #define _CPP_TEMPADMIN typedef unsigned char uChar8; typedef unsigned int uInt16; typedef unsigned long int uInt32;//3,5,6,9,10,11對應Pcduino V2單板的PWM引腳 //#define dataPin 10 //溫度傳感器data //#define clockPin 11 //溫度傳感器clock #define nLineHeat 9 //加熱引腳 #define nLineHumid 6 //加濕引腳 #define nLineCO2 12 //換氣引腳 #define nLineBeep 3 //報警接線 #define nTurnEgg 5 //翻蛋接口 #define nSwitch1 4 //switch1 #define nSwitch2 7 //switch2 #define nSwitch3 8 //switch3 #define nTempConst 300 //常量溫度,計算問題的時候要加上這個常量除以10 #define DELAY500 500 #define ONE_SECOND 1000U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI static float fTemp_c; static float fHumidity; int value; uInt32 g_un_count=0; static unsigned long currentMillis; static unsigned long previousMillis; static unsigned long nowtime; static unsigned long previousMillis2; static unsigned long delaytime; static unsigned long settingdelay; static unsigned long delay2hours; static unsigned long delay20second; static unsigned long delay1day=0;static float fSetTemp; static float fSetHumi; static float fSetTempOff; static float fSetHumiOff; static int n_IsSetting; static int n_SettingItem; static int nAngleDirect; //舵機旋轉方向 static int nDestAngle; //舵機目標角度Servo myservo1;/* *循環隊列,用數組實現 */ //隊列結構體定義 typedef struct Queue { int pBase[6]; //用于動態分配內存,pBase保存數組的首地址 int point; //指向最后一個元素的下一結點 } QUEUE; QUEUE queueTemp; QUEUE queueHumi;#endif硬件安裝解讀
`
代碼的下載
`
https://github.com/rabbie-china/incubator
這個網站服務器放在國外,有時候打不開,多試幾次就能打開
文件解讀
DFRobot_SHT20----------------------------溫濕度傳感器SHT20驅動函數
u8glib_arduino_v1.18.1.zip---------------oled顯示驅動
TempAdmin--------------------------------孵化箱主程序程序
函數解讀
為了控制溫度精準性,程序用了隊列的形式處理濕度和溫度數據
void inQueue(QUEUE * pQueue,int value)-------------溫度和濕度壓入隊列等待處理
int traverseQueue(QUEUE * pQueue)------------------出隊列
void TrunEggs(void)--------------------------------翻蛋函數,驅動舵機
void draw(void)------------------------------------OLED顯示溫度和濕度
void Process_Temp_Humi(void)-----------------------處理當前溫度和濕度模塊,程序采用了類似pid的控制原理,精確控制溫度,精度可達到0.01度
溫度和濕度設定寫在setup()函數
fSetTemp=37.5----------------------------------設定37.5度為目標溫度
fSetHumi=60------------------------------------設定60%為目標濕度
fSetTempOff=0.3--------------------------------設定上下0.3度為浮動溫差
fSetHumiOff=6----------------------------------設定上下6%濕度為浮動濕度差
關于孵化器的說明
`
1.為啥不用傳統的繼電器,而改用MOS開關的方式
因為繼電器有壽命太短,通常繼電器只有幾萬次開關觸點。以前也用繼電器方式孵化雞蛋,因為繼電器壽命的問題,導致加熱電路無法斷開,導致雞蛋被烤熟的慘痛教訓,從此改用MOS開關解決了這個問題
2.關于加濕器的維護
我從網上購買的USB加濕器模塊,很便宜,霧化片的壽命很短,建議購買的時候另外購買加濕器的霧化片配件。普通自來水中含有雜質,建議采用純凈水。
3.關于溫濕度
溫濕度都在程序里寫死的,溫度保持在37.5攝氏度,濕度保持在60%左右,如果需要改溫濕度,可以自己修改,代碼在TempAdmin.ino文件,setup函數,fSetTemp=37.5,fSetHumi=60
我將在下一個版本增加控制溫度和濕度的功能
4.孵化器有個自動翻蛋功能,需要自己接舵機。函數模塊 TrunEggs(),只要在代碼里把功能模塊打開就能起作用
5.關于溫濕度傳感器的保養
小雞孵化后,會在孵化箱內到處跑,孵化箱的食物殘渣會污染傳感器,很容易引起傳感器短路,買傳感器保護套來解決這個問題。
6.孵化器工作溫度
由于傳感器或者開關故障,引起溫度過高,程序做了保護模塊,當傳感器的溫度處于1-40度之間,孵化器正常工作。如果孵化器的溫度低于0度或者高于40度,機器沒有任何反應的,這是程序的保護機制。
作者列表
我叫rabbie,是一個熱愛自然的三腳貓程序員
聯系方式
如果你有問題,請聯系我
郵箱:3126614@qq.com
QQ:3126614
總結
以上是生活随笔為你收集整理的如何用ARDUINO制作一个鸟蛋孵化器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信号完整性分析与电源完整性分析学习笔记(
- 下一篇: 排队器拦截_如何绕过浏览器的弹窗拦截机制