项目背景介绍

经常养宠物的朋友,遇到宠物繁殖很是头疼,特别是鸟类繁殖,更加需要一个恒温恒湿的孵化箱。市面上孵化箱种类繁多,从几十块的到上千块的孵化箱都有,性能参差不齐,有些孵化箱的温度相差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制作一个鸟蛋孵化器相关推荐

  1. 怎么用python制作简单的程序-神级程序员教你如何用python制作一个牛逼的外挂!...

    玩过电脑游戏的同学对于外挂肯定不陌生,但是你在用外挂的时候有没有想过如何做一个外挂呢?(当然用外挂不是那么道义哈,呵呵),那我们就来看一下如何用python来制作一个外挂.... 我打开了4399小游 ...

  2. 手把手教你如何用Python制作一个电子相册?末附python教程

    这里简单介绍一下python制作电子相册的过程,主要用到tkinter和pillow这2个库,tkinter用于窗口显示照片,pillow用来处理照片,照片切换分为2种方式,一种是自动切换(每隔5秒) ...

  3. python可视化迷宫求解_如何用 Python 制作一个迷宫游戏

    相信大家都玩过迷宫的游戏,对于简单的迷宫,我们可以一眼就看出通路,但是对于复杂的迷宫,可能要仔细寻找好久,甚至耗费数天,然后可能还要分别从入口和出口两头寻找才能找的到通路,甚至也可能找不到通路. 虽然 ...

  4. 如何用JAVA制作一个漂亮的表格

    如何用JAVA制作一个漂亮的表格 表格图片: 选中一行时高亮显示,且字体变为红色: 在表格中添加数据: 代码如下: import java.awt.BorderLayout; import java. ...

  5. 如何用matlab制作一个小软件

    转:https://www.ttin.top/2018/03/29/TT0012/ 制作一个小软件的方法很多,比如说c++的MFC,本站在之前的第一个MFC文章里就提到过:matlab的GUIDE,在 ...

  6. 基于Arduino制作一个实时示波器

    示波器是电子工程师或制造商的工作台上可以找到的最重要的工具之一.它主要用于查看波形并确定其输入端可能随时间变化的信号的电压电平.频率.噪声和其他参数.嵌入式软件开发人员还使用它进行代码调试,技术人员在 ...

  7. html手抄报怎么制作软件,如何用word制作一个精美的电子板报

    使用word完全可以制作出一个精美的电子板报.何使用microsoft office word制作电子板报,喜欢的朋友可以过来学习一下 工具:板报素材.板报文字.word软件[此处使用MS offic ...

  8. 如何用css3制作一个旋转的立方体

    css3增加的动画效果使得前端制作某些动画更加方便,流畅,如何制作一个最简单的会旋转的立方体呢?话不多说,直接上代码! html代码如下,需要一个大的div包裹六个div作为立方体的六个表面 < ...

  9. 如何用MindManager制作一个sop流程

    一.简介 sop流程的意思是:标准事件流程,在策划某一活动的时候很有作用.有了sop流程我们就可以根据流程表上的时间节点来准备事情.我之前在一家房地产公司做人力资源,经常需要准备人员的培训,那时候制作 ...

最新文章

  1. 从软件思想抽象出几条做事原则
  2. 苹果回应 XcodeGhost:暂未发现个人信息受影响
  3. Hadoop源码阅读-HDFS-day2
  4. centos rsyslog mysql_centos7+rsyslog+loganalyzer+mysql 搭建rsyslog日志服务器
  5. 将自己可能存放库文件的路径都加入到/etc/ld.so.conf中是明智的选择
  6. 解决浏览器下载excel文件时显示“文件已损坏”
  7. 开发者新春回血大礼包助你2021畅行无压力!
  8. CGCKD2021大会报告整理(4)--风格迁移
  9. miui游戏驱动程序偏好设置_米粉必看:小米官方教你如何关闭 MIUI 广告 - 小米,MIUI...
  10. js实现excel块拖拉数据_小程序导出数据到excel表,借助云开发云函数实现excel数据的保存...
  11. 车辆违章演示示例代码
  12. java基础 泛型类的定义
  13. Java之HTTP长连接
  14. python数组冒号使用_python矩阵冒号
  15. 抛不开我执的老罗,长不大的周伯通
  16. UE4引擎源码学习笔记(一):源码整体文件结构
  17. wsl2使用vscode无法写入文件permission denied解决方法
  18. 一个字节8位,无符号类型,最大值为什么是2的8次方-1,范围0-255
  19. 挑选适合自己的乒乓球拍【转】
  20. webpack 简单使用

热门文章

  1. CF1740F Conditional Mix
  2. 互联网「病人」:不加班,就很慌
  3. Same $h*t Different Day
  4. Windows下安装EISeg交互式分割标注软件
  5. 计算机在体育教育中的作用,浅谈计算机在体育教学中的应用
  6. 结构化数据与非结构化数据的区别(转载)
  7. 老男孩Linux运维培训计划书
  8. 出现这个错误: No converter found for return value of ..
  9. A. 这是一道简单的水题~
  10. 煮完饺子,汤用不用留?- 从小事看应用开发的细节