废墟 发表于 2016-1-7 21:43:32

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

先直接看成品效果吧





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

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

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

SoftwareSerial mySerial(9, 10);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
DHT dht(DHTPIN, DHTTYPE);

struct PARAMS {
float T;//显示温度
float H;//显示湿度
long P;//显示PM2.5
long _P;//读取PM2.5
} _params;

//G5 相关变量
static unsigned char ucRxBuffer;
static unsigned char ucRxCnt = 0;

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

void setup() {
Serial.begin(9600);
//软串口读取G5
mySerial.begin(9600);
delay(500);
//设置屏幕字体和背景颜色
u8g.setColorIndex(255);
u8g.setHiColorByRGB(255, 255, 255);
delay(800);
}

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

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

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

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

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

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


//画界面
void draw(void) {
showTemperature();
showPM25();
showRH();
}

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

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

ucRxBuffer = ucData;

if (ucRxBuffer != 0x42 && ucRxBuffer != 0x4D){
    ucRxCnt = 0;
}
if (ucRxCnt > 31) {
    _params._P = (float)ucRxBuffer * 256 + (float)ucRxBuffer; //美国标准
    //    _params._P = (float)ucRxBuffer * 256 + (float)ucRxBuffer; //中国标准
    ucRxCnt = 0;
}
}

//中位值平均滤波,处理PM2.5的值
#define FILTER_N 5
int Filter() {
int i;
int filter_sum = 0;
int filter_max, filter_min;
int filter_buf;
for (i = 0; i < FILTER_N; i++) {
    filter_buf = _params._P;
    delay(1);
}
filter_max = filter_buf;
filter_min = filter_buf;
filter_sum = filter_buf;
for (i = FILTER_N - 1; i > 0; i--) {
    if (filter_buf > filter_max)
      filter_max = filter_buf;
    else if (filter_buf < filter_min)
      filter_min = filter_buf;
    filter_sum = filter_sum + filter_buf;
    filter_buf = filter_buf;
}
i = FILTER_N - 2;
filter_sum = filter_sum - filter_max - filter_min + i / 2; // +i/2 的目的是为了四舍五入
filter_sum = filter_sum / i;
return filter_sum;
}

void loop() {

while (mySerial.available())   {
    getPM25(mySerial.read());
}
_params.P = Filter();

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

if (++loopCnt > 99) {
    loopCnt = 0;
}

u8g.firstPage();
do {
    draw();
} while ( u8g.nextPage());
}

lovezypj 发表于 2016-1-7 23:09:09

请问下G5的连线方式,谢谢

废墟 发表于 2016-1-7 23:10:38

lovezypj 发表于 2016-1-7 23:09 static/image/common/back.gif
请问下G5的连线方式,谢谢

vcc必须接5v,tx接软串口的rx即可,只需要3根线

lovezypj 发表于 2016-1-7 23:53:27

废墟 发表于 2016-1-7 23:10 static/image/common/back.gif
vcc必须接5v,tx接软串口的rx即可,只需要3根线

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

废墟 发表于 2016-1-8 00:15:55

lovezypj 发表于 2016-1-7 23:53 static/image/common/back.gif
rx是不是插着传感器的时候无法上传?拔掉后上传成功了,试验也成功

是的,所以我用的软件串口啊,不要用硬件串口

lovezypj 发表于 2016-1-8 00:56:49

废墟 发表于 2016-1-8 00:15 static/image/common/back.gif
是的,所以我用的软件串口啊,不要用硬件串口

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

这个屏幕是1306驱动的,用Adafruit_ssd1306可以点亮,u8glib就是点不亮,很奇怪

废墟 发表于 2016-1-8 01:06:52

lovezypj 发表于 2016-1-8 00:56 static/image/common/back.gif
非常感谢,还有个问题,我也有个oled,和你一样是i2c的,sda和scl是不是接模拟口A4和A5呢?

这个屏幕是 ...

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

老胖熊 发表于 2016-1-8 13:39:27

不错,学习了。

lovezypj 发表于 2016-1-12 22:04:04

请问你的G5有没有出现过数据错误的情况,就是返回开头不是424d?

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

废墟 发表于 2016-1-13 14:54:24

lovezypj 发表于 2016-1-12 22:04 static/image/common/back.gif
请问你的G5有没有出现过数据错误的情况,就是返回开头不是424d?

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

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

你5秒可以多读几次有效数据,一次肯定不对

agut 发表于 2016-1-28 15:24:44

LZ你滤波没有效果。中位值平均滤波代码里面的 _params._P不是循环获取的。

limp 发表于 2016-2-5 17:41:41

测试成功,感谢楼主无私分享。

废墟 发表于 2016-2-16 00:04:32

agut 发表于 2016-1-28 15:24 static/image/common/back.gif
LZ你滤波没有效果。中位值平均滤波代码里面的 _params._P不是循环获取的。

仔细读代码

Ansifa 发表于 2016-2-16 00:18:18

做的不错,_params._P处理没问题,是一次串口信号处理一次
loopCnt 判断两次有点多余了,可以化为一次处理不过区别不大
滤波可以参考http://www.geek-workshop.com/thread-7694-1-1.html个人比较偏好滑动滤波:lol

rockorange 发表于 2016-2-24 21:37:28

按照搂住的程序成功读数.谢谢 屏幕挺好看,请问是多大尺寸的?
传感器似乎放反了,说明书上写的有螺丝孔是底部.
http://www.one-xin.cn/uploads/soft/160121/PMS5003S.pdf
进风口与出风口所在平面紧贴用户机内壁,并在该侧壁上开孔与外部空气连
通,开孔尺寸应不小于进风口和出风口尺寸。
3. 传感器底部用 2mm 自攻螺钉固定,螺钉进入壳体长度应不大于 5mm。
页: [1] 2 3
查看完整版本: 攀藤G5+DHT22 温湿度&PM2.5测量器