极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 68863|回复: 37

攀藤G5+DHT22 温湿度&PM2.5测量器

[复制链接]
发表于 2016-1-7 21:43:32 | 显示全部楼层 |阅读模式
先直接看成品效果吧





用的是Arduino nano,直接焊线焊上,然后3M双面胶粘。
话说这个塑料盒实在难处理,费死劲了,以后有机会搞个3D打印机去。

代码如下,有注释,基本能看明白,有不明白的,直接问
  1. /**
  2. * PM2.5&温湿度显示
  3. * 激光PM2.5传感器:攀藤 G5 PMS5005
  4. * 温湿度传感器:DHT22
  5. * Arduino Nano
  6. * SSD1306
  7. *
  8. * @Author: Coeus <r.anerg at gmail.com>
  9. */
  10. #include <DHT.h>
  11. #include <U8glib.h>
  12. #include <SoftwareSerial.h>

  13. #define DHTPIN 3        //DHT SIG口接PIN3
  14. #define DHTTYPE DHT22   //定义DHT型号

  15. SoftwareSerial mySerial(9, 10);
  16. U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
  17. DHT dht(DHTPIN, DHTTYPE);

  18. struct PARAMS {
  19.   float T;//显示温度
  20.   float H;//显示湿度
  21.   long P;//显示PM2.5
  22.   long _P;//读取PM2.5
  23. } _params;

  24. //G5 相关变量
  25. static unsigned char ucRxBuffer[250];
  26. static unsigned char ucRxCnt = 0;

  27. //循环计数器
  28. unsigned char loopCnt = 0;

  29. void setup() {
  30.   Serial.begin(9600);
  31.   //软串口读取G5
  32.   mySerial.begin(9600);
  33.   delay(500);
  34.   //设置屏幕字体和背景颜色
  35.   u8g.setColorIndex(255);
  36.   u8g.setHiColorByRGB(255, 255, 255);
  37.   delay(800);
  38. }

  39. void showTemperature(void) {
  40.   int x = 30, y = 10;//温度显示位置
  41.   //画LOGO
  42.   u8g.drawRFrame(x, y, 16, 16, 1);
  43.   u8g.drawFrame(x + 5, y + 3, 3, 6);
  44.   u8g.drawDisc(x + 6, y + 10, 2);
  45.   u8g.setFont(u8g_font_04b_03b);
  46.   u8g.setPrintPos(x + 10, y + 8);
  47.   u8g.print("C");

  48.   //设置双倍大小字体显示
  49.   u8g.setScale2x2();
  50.   u8g.setPrintPos(x / 2 + 11, y / 2 + 7);
  51.   u8g.setFont(u8g_font_orgv01);
  52.   u8g.print(_params.T);
  53.   u8g.undoScale();
  54. }

  55. void showPM25(void) {
  56.   int x = 30, y = 28;//PM2.5显示位置
  57.   //画LOGO
  58.   u8g.drawRFrame(x, y, 16, 16, 1);
  59.   u8g.setFont(u8g_font_orgv01);
  60.   u8g.setPrintPos(x + 3, y + 10);
  61.   u8g.print("pm");

  62.   //设置双倍大小字体显示
  63.   u8g.setScale2x2();
  64.   u8g.setPrintPos(x / 2 + 11, y / 2 + 7);
  65.   u8g.setFont(u8g_font_orgv01);
  66.   u8g.print(_params.P);
  67.   u8g.undoScale();
  68. }

  69. void showRH() {
  70.   int x = 30, y = 46;//湿度显示位置
  71.   //画LOGO
  72.   u8g.drawRFrame(x, y, 16, 16, 1);
  73.   u8g.drawFrame(x + 5, y + 3, 3, 6);
  74.   u8g.drawDisc(x + 6, y + 10, 2);
  75.   u8g.setFont(u8g_font_04b_03b);
  76.   u8g.setPrintPos(x + 10, y + 8);
  77.   u8g.print("H");

  78.   //设置双倍大小字体显示
  79.   u8g.setScale2x2();
  80.   u8g.setPrintPos(x / 2 + 11, y / 2 + 7);
  81.   u8g.setFont(u8g_font_orgv01);
  82.   u8g.print(_params.H);
  83.   u8g.undoScale();
  84. }


  85. //画界面
  86. void draw(void) {
  87.   showTemperature();
  88.   showPM25();
  89.   showRH();
  90. }

  91. //获取温湿度
  92. void getDHT22() {
  93.   _params.H = dht.readHumidity();
  94.   _params.T = dht.readTemperature();
  95. }

  96. //获取PM2.5的值
  97. void getPM25(unsigned char ucData) {

  98.   ucRxBuffer[ucRxCnt++] = ucData;

  99.   if (ucRxBuffer[0] != 0x42 && ucRxBuffer[1] != 0x4D)  {
  100.     ucRxCnt = 0;
  101.   }
  102.   if (ucRxCnt > 31) {
  103.     _params._P = (float)ucRxBuffer[6] * 256 + (float)ucRxBuffer[7]; //美国标准
  104.     //    _params._P = (float)ucRxBuffer[12] * 256 + (float)ucRxBuffer[13]; //中国标准
  105.     ucRxCnt = 0;
  106.   }
  107. }

  108. //中位值平均滤波,处理PM2.5的值
  109. #define FILTER_N 5
  110. int Filter() {
  111.   int i;
  112.   int filter_sum = 0;
  113.   int filter_max, filter_min;
  114.   int filter_buf[FILTER_N];
  115.   for (i = 0; i < FILTER_N; i++) {
  116.     filter_buf[i] = _params._P;
  117.     delay(1);
  118.   }
  119.   filter_max = filter_buf[0];
  120.   filter_min = filter_buf[0];
  121.   filter_sum = filter_buf[0];
  122.   for (i = FILTER_N - 1; i > 0; i--) {
  123.     if (filter_buf[i] > filter_max)
  124.       filter_max = filter_buf[i];
  125.     else if (filter_buf[i] < filter_min)
  126.       filter_min = filter_buf[i];
  127.     filter_sum = filter_sum + filter_buf[i];
  128.     filter_buf[i] = filter_buf[i - 1];
  129.   }
  130.   i = FILTER_N - 2;
  131.   filter_sum = filter_sum - filter_max - filter_min + i / 2; // +i/2 的目的是为了四舍五入
  132.   filter_sum = filter_sum / i;
  133.   return filter_sum;
  134. }

  135. void loop() {

  136.   while (mySerial.available())   {
  137.     getPM25(mySerial.read());
  138.   }
  139.   _params.P = Filter();

  140.   //DHT22更新数据速度很慢,所以不要读的那么快
  141.   if (loopCnt % 40 == 0) {
  142.     getDHT22();
  143.   }

  144.   if (++loopCnt > 99) {
  145.     loopCnt = 0;
  146.   }

  147.   u8g.firstPage();
  148.   do {
  149.     draw();
  150.   } while ( u8g.nextPage());
  151. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2016-1-7 23:09:09 | 显示全部楼层
请问下G5的连线方式,谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-1-7 23:10:38 | 显示全部楼层
lovezypj 发表于 2016-1-7 23:09
请问下G5的连线方式,谢谢

vcc必须接5v,tx接软串口的rx即可,只需要3根线
回复 支持 反对

使用道具 举报

发表于 2016-1-7 23:53:27 | 显示全部楼层
废墟 发表于 2016-1-7 23:10
vcc必须接5v,tx接软串口的rx即可,只需要3根线

rx是不是插着传感器的时候无法上传?拔掉后上传成功了,试验也成功
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-1-8 00:15:55 | 显示全部楼层
lovezypj 发表于 2016-1-7 23:53
rx是不是插着传感器的时候无法上传?拔掉后上传成功了,试验也成功

是的,所以我用的软件串口啊,不要用硬件串口
回复 支持 反对

使用道具 举报

发表于 2016-1-8 00:56:49 | 显示全部楼层
废墟 发表于 2016-1-8 00:15
是的,所以我用的软件串口啊,不要用硬件串口

非常感谢,还有个问题,我也有个oled,和你一样是i2c的,sda和scl是不是接模拟口A4和A5呢?

这个屏幕是1306驱动的,用Adafruit_ssd1306可以点亮,u8glib就是点不亮,很奇怪
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-1-8 01:06:52 | 显示全部楼层
lovezypj 发表于 2016-1-8 00:56
非常感谢,还有个问题,我也有个oled,和你一样是i2c的,sda和scl是不是接模拟口A4和A5呢?

这个屏幕是 ...

是的,接A4和A5
另外,如果你是1306,那么看我代码里有这一行,U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
回复 支持 反对

使用道具 举报

发表于 2016-1-8 13:39:27 来自手机 | 显示全部楼层
不错,学习了。
回复 支持 反对

使用道具 举报

发表于 2016-1-12 22:04:04 | 显示全部楼层
请问你的G5有没有出现过数据错误的情况,就是返回开头不是424d?

我5秒读取一次,运行半个小时,其中会有十几次是错误的数据,开头返回的不是42 4d
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-1-13 14:54:24 | 显示全部楼层
lovezypj 发表于 2016-1-12 22:04
请问你的G5有没有出现过数据错误的情况,就是返回开头不是424d?

我5秒读取一次,运行半个小时,其中会有 ...

有啊,直接扔掉,你看我的代码里有判断。
我觉得你5秒才读一次有点慢了,我还计算了下平均值,抛去最高和最低值,然后计算平均值

你5秒可以多读几次有效数据,一次肯定不对
回复 支持 反对

使用道具 举报

发表于 2016-1-28 15:24:44 | 显示全部楼层
LZ你滤波没有效果。中位值平均滤波代码里面的 _params._P不是循环获取的。
回复 支持 反对

使用道具 举报

发表于 2016-2-5 17:41:41 | 显示全部楼层
测试成功,感谢楼主无私分享。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-2-16 00:04:32 | 显示全部楼层
agut 发表于 2016-1-28 15:24
LZ你滤波没有效果。中位值平均滤波代码里面的 _params._P不是循环获取的。

仔细读代码
回复 支持 反对

使用道具 举报

发表于 2016-2-16 00:18:18 | 显示全部楼层
做的不错,_params._P处理没问题,是一次串口信号处理一次
loopCnt 判断两次有点多余了,可以化为一次处理不过区别不大
滤波可以参考http://www.geek-workshop.com/thread-7694-1-1.html个人比较偏好滑动滤波
回复 支持 反对

使用道具 举报

发表于 2016-2-24 21:37:28 | 显示全部楼层
按照搂住的程序成功读数.谢谢 屏幕挺好看,请问是多大尺寸的?
传感器似乎放反了,说明书上写的有螺丝孔是底部.
http://www.one-xin.cn/uploads/soft/160121/PMS5003S.pdf
进风口与出风口所在平面紧贴用户机内壁,并在该侧壁上开孔与外部空气连
通,开孔尺寸应不小于进风口和出风口尺寸。
3. 传感器底部用 2mm 自攻螺钉固定,螺钉进入壳体长度应不大于 5mm。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-20 08:27 , Processed in 0.048870 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表