查看: 45125|回复: 101

我的第一个小制作【便携环境检测器】

  [复制链接]

该用户从未签到

发表于 2014-6-19 17:24 | 显示全部楼层 |阅读模式
本帖最后由 skyhome 于 2014-6-23 15:42 编辑

第一次用arduino做个像样的东东,属于入门级别,高手勿喷。一直在论坛上看别人做的好玩的东东,什么智能小车、机器人、无人机,都是高大上的制作,看的我也手痒痒,但冷静下来做了个自我评估,有难度。还是从简单的起步,做成的话也能给自己点信心。在帝都,最关心的除了PM2.5就是房价了,那就来个便携环境检测器吧。
完成后的样子:
外观.jpg


你只看见了m&m豆?哦,这是我的儿子吃完里面的豆豆准备扔的,被我拿来做了外壳,大小正好。


这才是我的正面:

正面.jpg



内容还挺丰富吧。有温度、湿度,空气颗粒物数据,还有空气颗粒物动态图表,电池电量显示。


我的侧面是这样的:
左边:空气传感器空气入口
kqk.jpg


右边:温湿度传感器开口,这个开口和左边的开口正好让空气形成对流,有助于空气传感器工作
Clipboard01.jpg



内部结构,请无视凌乱的布线。没有用板子焊接,只好将就了。
内部.jpg



内置9v电池,可以带在身边,随时对所处环境进行检测,大大提高了实用性(我用的是可充电的锂电池)。
在家的时候,也可以放在桌子上,是不是有点萌
站立.jpg



材料:
M&M豆外壳1个     免费
5110液晶屏1个     8元
DHT11温湿度传感器   7元
Sharp GP2Y1050AU 空气质量传感器 50元 (新版,比GP2Y10线性度更高
arduino pro mini 5v 16Mhz 12元
9v 780mAh充电锂电池   30元
合计:97元


代码比较简单,花了两天时间从网上找各种教程拼拼凑凑搞定。最让我开心的是学会了在5510液晶上画图标(温度、湿度图标)、显示中文、以及画动态直线图,最最高兴的是找到了一个检测电池电量的代码,这样就不用担心什么时候电池没电了,完美收工。
代码在家里的电脑上,有需要代码的朋友吗?有的话请留言,我会分享给大家。
补充完整:回家整理了一下,不会用画图软件,手工画了一个接线图
提醒:千万注意不要把9v电池的正负极反接到mini上。我接错了一次,mini光荣牺牲了。
jxt.jpg

库文件:
LCD5110的库文件网上有很多版本,功能各不一样,这是我代码中用的,感觉不错
nokia5110.rar (9.54 KB, 下载次数: 869)


代码:
[mw_shl_code=c,true]#include <dht11.h>       //引用温湿度传感器库文件
dht11 DHT11;
#define DHT11PIN 10      //定义温湿度传感器引脚为D10   
#include <nokia5110.h>   //引用5110LCD库文件
int flash=0;
int measurePin = 0;      // 空气传感器模拟输入,模拟口0,
int max_dust;

//以下变量为空气传感器使用
int samplingTime = 280;
int deltaTime = 40;
int sleepTime = 9680;
float voMeasured = 0;
float calcVoltage = 0;
float dustDensity = 0;               

//5510LCD定义(宽84像素,高48像素)...
static const byte LCD_WIDTH = 84;
static const byte LCD_HEIGHT = 48;
static nokia5110 lcd(3,4,5,6,7);

// A custom "degrees" symbol...
static const byte DEGREES_CHAR = 1;
static const byte degrees_glyph[] = { 0x00, 0x07, 0x05, 0x07, 0x00 };

// 定义温度计图标(10x2)
static const byte THERMO_WIDTH = 10;
static const byte THERMO_HEIGHT = 2;
static const byte thermometer[] = { 0x00, 0x00, 0x48, 0xfe, 0x01, 0xfe, 0x00, 0x02, 0x05, 0x02,
                                    0x00, 0x00, 0x62, 0xff, 0xfe, 0xff, 0x60, 0x00, 0x00, 0x00};
                                    
//定义中文字体的宽和高
static const byte chinese_WIDTH = 12;  //定义中文字体宽度(12像素)
static const byte chinese_HEIGHT = 2;  //定义中文字体高度(这个2不是像素,是2个英文字符高度,实际2*8=16像素)


//定义湿度图标      
static const byte shui[] = {0x00,0x00,0x00,0x0E,0x12,0x22,0xBC,0x80,
      0x8E,0x12,0x22,0x3C,0x00,0x00,0x00,0x00,
      0x00,0x03,0x06,0x08,0x08,0x09,0x0E,0x00};

//优
static const byte you[] = {0x20,0x10,0xFC,0x0B,0x08,0x08,0xFF,0x08,
      0xF9,0x0A,0x08,0x08,0x00,0x00,0x0F,0x08,
      0x04,0x03,0x00,0x00,0x07,0x08,0x08,0x0E};
//良      
static const byte liang[] = {0x00,0x00,0xFC,0x54,0xD5,0x56,0x54,0x54,
      0xFE,0x84,0x00,0x00,0x00,0x00,0x0F,0x04,
      0x04,0x03,0x02,0x05,0x04,0x08,0x08,0x08};
//差      
static const byte cha[] = {0x44,0x54,0x54,0xD5,0x76,0x5C,0x54,0x56,
      0x55,0x54,0x64,0x44,0x04,0x0A,0x09,0x09,
      0x09,0x09,0x0F,0x09,0x09,0x09,0x08,0x08};      

//电池电量不同图标     
static const byte vcc_vol_5[] =  {0x00,0x00,0xFE,0xFF,0xFF,0xFE,0x00,0x00}; //电池满
static const byte vcc_vol_4[] =  {0x00,0x00,0xFE,0xFD,0xFD,0xFE,0x00,0x00};
static const byte vcc_vol_3[] =  {0x00,0x00,0xFE,0xF9,0xF9,0xFE,0x00,0x00};
static const byte vcc_vol_2[] =  {0x00,0x00,0xFE,0xE1,0xE1,0xFE,0x00,0x00};
static const byte vcc_vol_1[] =  {0x00,0x00,0xFE,0x81,0x81,0xFE,0x00,0x00};  
static const byte vcc_vol_0[] =  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //电池空

//读取vcc电压
long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void setup() {
  Serial.begin(9600,SERIAL_8N1);   //将串口波特率设为9600,数据位8,无校验,停止位1
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  delay(2000);     //延迟2秒,等待传感器初始化完成
}

void loop() {
    float vcc_vol=readVcc()/1000;                //将读取的vcc电压mv转换为v
   // Serial.println(vcc_vol,2);
    voMeasured = analogRead(measurePin);         // 读取空气传感器模拟值
    calcVoltage = voMeasured * (5.0 / 1024.0);   //将模拟值转换为电压值
    dustDensity = calcVoltage*0.2*1000;          //将电压值转换为粉尘密度输出单位ug/m3

  float temp,humi;
  static byte xChart = LCD_WIDTH;
  int chk = DHT11.read(DHT11PIN);  //检查DHT传感器的状态  
  switch (chk) {     
  case 0:      
   humi = DHT11.humidity;      
   temp = DHT11.temperature;      
    break;     
  case -1:      
    lcd.print("Checksum error");
    break;     
  case -2:      
    lcd.print("Time out error");
    break;     
  default:      
    lcd.print("Unknown error");
    break;   
  }  
  
  //显示温度
  lcd.setCursor(0, 0);     //定位到LCD左上角
  lcd.drawBitmap(thermometer, THERMO_WIDTH, THERMO_HEIGHT);  //画温度计图标
  lcd.print(temp, 1);      //显示温度
  lcd.print("C");          //显示温度单位C
  //显示湿度
  lcd.setCursor(50, 0);    //定位到LCD第50列,0行
  lcd.drawBitmap(shui, chinese_WIDTH, chinese_HEIGHT);   //画湿度图标
  lcd.print(" ");         
  lcd.print(humi, 0);      //显示湿度
  //显示PM值
  lcd.setCursor(10, 2);    //定位到LCD第10列,16行(这里的2指的是2个英文字符高,2*8=16)
  lcd.print("PM:");
  lcd.print(dustDensity, 1); //显示PM值

  lcd.setCursor(72, 2);                //定位到LCD第72列,16行(这里的2指的是2个英文字符高,2*8=16)
  if (xChart >= LCD_WIDTH-13) {        //图形X坐标超过(屏幕宽度-13)的话,重置为1
    xChart = 1;
    if (dustDensity < 50 ){            //根据PM浓度显示不同的汉字
      lcd.drawBitmap(you, chinese_WIDTH, chinese_HEIGHT);     //优
      max_dust=50;                      //根据PM浓度调整图形的Y轴最大值
    }
    if (dustDensity >= 50 && dustDensity <100){
       lcd.drawBitmap(liang, chinese_WIDTH, chinese_HEIGHT);//良
       max_dust=100;
    }
    if (dustDensity >= 100 && dustDensity < 200  ){
       lcd.drawBitmap(cha, chinese_WIDTH, chinese_HEIGHT);//差
       max_dust=200;
    }
    if (dustDensity >= 200 ){
      lcd.drawBitmap(cha, chinese_WIDTH, chinese_HEIGHT);//差
      max_dust=300;
    }
  }

  //画PM实时柱状图  
  lcd.setCursor(xChart, 9);       //定位柱状图的起始位置
  lcd.drawColumn(3, map(dustDensity,0,max_dust, 0, 24));  // 将PM数值映射为数值0~24(24是图形的高度,3行3*8=24)
  lcd.drawColumn(3, 0);           // 将柱状图下一列先清空,避免与新数据混淆
  
  xChart++;

//根据VCC电压判断电池电量,并显示不同图标
lcd.setCursor(74, 5);       //定位电池电量图标的起始位置
if (vcc_vol >=4.5 ){
   lcd.drawBitmap(vcc_vol_5, 8, 8);
}

if (vcc_vol <4.5 && vcc_vol>=4 ){
   lcd.drawBitmap(vcc_vol_4, 8, 8);
}

if (vcc_vol <4 && vcc_vol>=3.5 ){
   lcd.drawBitmap(vcc_vol_3, 8, 8);
}

if (vcc_vol <3.5 && vcc_vol>=3 ){
   lcd.drawBitmap(vcc_vol_2, 8, 8);
}

if (vcc_vol <3 ){                  //当VCC电压小于3v时图标闪烁,电池电量不足警告
  switch (flash){               
    case 0:  
         lcd.drawBitmap(vcc_vol_0, 8, 8);
         flash=1;
         break;
    case 1:
         lcd.drawBitmap(vcc_vol_1, 8, 8);
         flash=0;
         break;
       }     
}

delay(500);
}[/mw_shl_code]




该用户从未签到

发表于 2014-6-19 17:54 | 显示全部楼层
顶,顺求代码,476128890@qq.com,在此谢过

该用户从未签到

发表于 2014-6-19 19:44 | 显示全部楼层
顶楼主,顺求代码,jimmylijiaji@sina.com ,{:soso_e163:}谢

该用户从未签到

发表于 2014-6-19 20:49 | 显示全部楼层
顶,顺求代码和比较详细的制作过程,谢谢!beach104@126.com

该用户从未签到

 楼主| 发表于 2014-6-20 12:07 | 显示全部楼层
yangzq 发表于 2014-6-19 17:54
顶,顺求代码,,在此谢过

已更新,附上代码

该用户从未签到

发表于 2014-6-20 20:24 | 显示全部楼层
skyhome 发表于 2014-6-20 12:07
已更新,附上代码

{:soso_e142:}{:soso_e142:}

该用户从未签到

发表于 2014-6-20 20:43 | 显示全部楼层
不错的样子

该用户从未签到

发表于 2014-6-21 16:44 | 显示全部楼层
{:soso_e179:}不错,要学习

该用户从未签到

发表于 2014-6-22 14:04 | 显示全部楼层
顶,相当萌啊,实用便捷!尤其向楼主的分享精神致敬!

该用户从未签到

发表于 2014-6-23 09:32 | 显示全部楼层
相当萌,DIY的精神杠杠的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门推荐

智能“百味”勺子开发实战营,为你的生活添滋味!
智能“百味”勺子开发实战
想不想拥有一把神奇的“百味”勺子,把索然无味的食物变出酸甜苦辣咸的丰富滋味
20sffactory 三自由度3D打印机械手臂 - 高速移动
20sffactory 三自由度3D打
这款机械臂作者没有给他起名字,用作者的名字来命名. 目前为止,生态最好,做的最完
多位数码管显示项目——以TM1650为例
多位数码管显示项目——以
以下是用搭载TM1650的4位数码管,显示电位器所代表0到1023的模拟信号数值 示意图:
新手小白付费拜师求教:TM1650四位时钟数码管的具体用法
新手小白付费拜师求教:TM
从淘宝购买的TM16504位数码管的时钟模块,卖家给了程序,但是完全不会用。求一位老师
【Arduino】168种传感器模块系列实验(76)---TTL转RS-485模块
【Arduino】168种传感器模
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表