自制空气检测仪
题外话
受今年的疫情影响,才闲下来有点空搞点小东西玩玩,有些年头没有去接触硬件了,这次重新做点小东西,给自己回忆回忆,同时也能体现一下动手的乐趣。
制作前的准备
制作需要的材料
这个小的空气检测仪使用的材料分为4部分也就是主控、传感器还有显示器件,以及部分元器件:
- 主控 :Arduino nano (ATmega 328P);
- 元器件 150欧姆的电阻;
- 元器件 220uF的电容;
- 传感器 BME280 温湿度气压传感器;
- 传感器 GP2Y1014AU粉尘传感器模块(PM8);
- 显示器件 LCD12864 液晶屏(中文字库带背光,串/并口);
主控的选择是基于本项目所需要的性能,BME280是通过I2C协议传输数据的,GP2Y1014AU传感器是模拟量,需要使用单片机的AD(模数转换器)来采集数据。屏幕是单片机通过SPI协议进行驱动的,其实也可以使用4/8口的并口来通信,不过在I/O口不是很充足的情况下,SPI也是很好的选择。
硬件接线
屏幕
LCD12864 | 引脚 |
---|---|
VDD | VCC(5V) |
VSS | GND |
BLK | GND |
BLA | VCC(5V) |
PSB | GND |
RS | D8 |
R/W | D9 |
E | D3 |
如图就是SPI的接法,比较推荐,比较节约I/O资源。图中D/I是RS,CS1是PSB。
值得一提的是PSB是用来做串/并模式选择的,我们采用的SPI串行通信,所以这里PSB接低电平(GND),RS是串行片选信号。
温湿度气压传感器
传感器端口 | 引脚 |
---|---|
VCC | 3.3V / 5V(看具体的模块说明) |
GND | gnd |
SCL | A5 |
SDA | A4 |
GP2Y1014AU粉尘传感器模块
https://blog.csdn.net/acktomas/article/details/88350817
这位作者的讲解比较详细,我就不作赘述。简单的说一下接线吧。
传感器端口 | 引脚 |
---|---|
V-LED | VCC(5V) |
LED-GND | GND |
LED | D13 |
S-GND | GND |
V0 | A0 |
VCC | VCC(5V) |
https://blog.csdn.net/acktomas/article/details/88350817
程序驱动
LCD12864 显示驱动
使用LCD12864RSPI的库,用来驱动。
#include <LCD12864RSPI.h>
void setup()
{
LCDA.Initialise(); // 屏幕初始化
}
void LcdDisplay()
{
LCDA.CLEAR();
LCDA.DisplayString(0,0,show1,AR_SIZE(show1)); //0行0列开始显示
LCDA.DisplayString(0,3,AirQulity,strlen(AirQulity)); //0行3列开始显示
}
温湿度气压 GY-BME 280
简单一些的话,可以考虑使用Adafruit_BME280的库,这个库相当好用。但是,因为和中断有冲突,所以方法不可以直接写在中断定时器里,程序会直接跑飞。
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
void setup()
{
bme.begin();
}
void get_BME_Value()
{
int tempratureValue = (int)(bme.readTemperature()*100);
int humidityValue = (int)(bme.readHumidity()*100);
int pressureValue = (int)(bme.readPressure()/100.0F);
//TODO 写对这些数据的格式化
}
GP2Y1014AU粉尘传感器模块(PM8)
这个需要使用Arduino NANO的AD(模数转换器)来采集数据,采集到数据后通过公式(公式需要进行一定的校准)。大体是基于官方的一张图。
V0产生有效电压的前提是,在第一个脉冲信号0.28ms后,待电平稳定后进行采集。
/**********************************************/
// SHARP 1014 空气传感器(0.8)
//入口函数 无
//出口函 无
/***********************************************/
void get_AirQulity()
{
digitalWrite(ledPower, LOW);
delayMicroseconds(delayTime);
dustVal = analogRead(dustPin);
delayMicroseconds(delayTime2);
digitalWrite(ledPower, HIGH);
delayMicroseconds(offTime);
if (dustVal > 36.455)
{
result = (int)((float(dustVal / 1024) * 737.7) - 16.4); //个人总结
}
memset(AirQulity, 0, sizeof(AirQulity));
sprintf(AirQulity,"%d",result);
strcat(AirQulity," ug/m3");
strcat(AirQulity,'\0');
}
系统结构
在设计这个小系统的时候,我秉持在主循环尽可能少放方法,多使用定时器去驱动事件的运行,一方面是将方法都放在主循环中无法保证实时性,主要原因是有些方法使用**Delay()**做延时,浪费性能且阻塞进程。
Arduino Nano和Arduino UNO一致,使用MsTimer2库来开启TIME2的中端定时器。
#include <MsTimer2.h>
void setup()
{
MsTimer2::set(1000, LcdDisplay); // 1000ms 触发 LcdDisplay()
MsTimer2::start(); //定时2
}
void loop()
{
get_BME_Value();
delay(100);
}
总结
一个简单的小产品,希望可以带更多的人,学习嵌入式,了解软硬件间的联系。设计或许还有一些不合理的,有些做法和说明不对的地方,请留言指正。代码整理后,上传CSDN。