一、项目介绍
项目名称为基于Arduino Nano Matter实现空气质量检测
通过Nano Matter的ADC读取气体传感器输出的原始模拟量数据,将数据转化为ppm浓度格式的数据,同时可以通过IIC对OLED屏幕进行操作来显示当前气体浓度。Nano Matter板载一颗用户按键,通过按键可以实现CO、乙醇、NH3、H2、CH4五种气体类型的切换,还可以通过BLE切换气体类型,并实现BLE读取当前气体浓度数据。
二、硬件介绍
1.来自Arduino官方的Arduino Nano Matter开发板
2.来自Seeed的0.96寸OLED屏幕
3.来自DFRobot的MiCS-5524 MEMS气体传感器
4.整体硬件连接图
三、方案框图和项目设计思路介绍
使用Arduino Nano Matter板载的ADC功能读取气体传感器输出的模拟量,将该数据通过公式转换为正常的ppm浓度值,然后通过IIC操作OLED屏幕,实时显示当前浓度数据。并且可以通过GPIO读取板载按键状态,实现检测气体类型的切换,当气体浓度超过一定阈值时,RGB LED显示红灯,在正常范围内,RGB LED显示绿灯。最后,使用Silicon Labs提供的BLE协议栈实现与手机蓝牙的连接,并在APP内发送和显示数据。在APP内发送指令,可以切换检测气体类型,同样也可以在APP内实时读取到当前的气体浓度。
四、软件流程图和关键代码介绍
setup函数主要实现:
1.串口初始化、初始化GPIO并将RGB LED设置为高电平输出、按键配置为内部上拉,低电平触发中断
Serial.begin(115200);
while(!Serial);
Serial.println("Silicon Labs BLE Air Quality Monitor");
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
digitalWrite(LEDR, LED_BUILTIN_INACTIVE);
digitalWrite(LEDG, LED_BUILTIN_INACTIVE);
digitalWrite(LEDB, LED_BUILTIN_INACTIVE);
// If the board has a built-in button configure it for usage
pinMode(BTN_BUILTIN, INPUT_PULLUP);
attachInterrupt(BTN_BUILTIN, btn_state_change_callback, FALLING);
2.使用硬件IIC初始化OLED屏幕
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // High speed I2C
u8g2.begin();
3.初始化MiCS-5524气体传感器
#define CALIBRATION_TIME 3 // Default calibration time is three minutes
#define ADC_PIN A0
#define POWER_PIN 10
DFRobot_MICS_ADC mics(/*adcPin*/ADC_PIN, /*powerPin*/POWER_PIN);
while(!mics.begin()){
Serial.println("NO Deivces !");
delay(1000);
}
Serial.println("Device connected successfully !");
uint8_t mode = mics.getPowerState();
if(mode == SLEEP_MODE){
mics.wakeUpMode();
Serial.println("wake up sensor success!");
}else{
Serial.println("The sensor is wake up mode");
}
while(!mics.warmUpTime(CALIBRATION_TIME)){
Serial.println("Please wait until the warm-up time is over!");
delay(1000);
}
首先初始化气体传感器,然后判断其当前状态,如果处于睡眠模式将其唤醒,接着由于气体传感器的特性,需要先预热才能保证后续得到的数据尽可能精准,推荐的预热时间至少3分钟。
4.初始化BLE协议栈
项目中使用的BLE协议栈不是Arduino提供的,而是来自Silicon Labs官方的,但是翻遍所有例程也没看见通过哪句代码对BLE协议栈初始化,可能是当开始使用Silicon Labs官方BLE协议栈时,库内部就已经初始化了。具体设置步骤如下
实测这样设置,虽然没有看见任何函数调用BLE协议栈的语句,但是BLE协议栈已经可以使用。
loop函数主要实现:
1.获取气体传感器转换出的ppm浓度数据,并将其显示在OLED屏幕上
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.drawStr(0,10,"M-Design");
u8g2.sendBuffer();
if(gas_type == 0x00)
{
return;
}
gasdata = mics.getGasData(gas_type);
Serial.print(" Current gas type is ");
Serial.print(gas_type);
Serial.print(" | ");
Serial.print(gasdata,1);
Serial.println(" PPM");
u8g2.setCursor(0,32);
u8g2.print("Current Gas Type : ");
u8g2.print(gas_type);
u8g2.sendBuffer();
u8g2.setCursor(0,50);
u8g2.print("Current Gas Concen:");
u8g2.print(gasdata);
u8g2.sendBuffer();
获取气体浓度数据前,必须先判断当前检测的气体类型是否有效
2.判断当前气体浓度是否超出阈值,如果超出,RGB LED显示红灯,并且通过BLE传输当前数据,当气体浓度在安全范围内,RGB LED显示绿灯
if(gasdata>200)
{
digitalWrite(LEDG, LED_BUILTIN_INACTIVE);
digitalWrite(LEDB, LED_BUILTIN_INACTIVE);
digitalWrite(LEDR, LED_BUILTIN_ACTIVE);
send_button_state_notification();
}
else
{
digitalWrite(LEDR, LED_BUILTIN_INACTIVE);
digitalWrite(LEDB, LED_BUILTIN_INACTIVE);
digitalWrite(LEDG, LED_BUILTIN_ACTIVE);
}
delay(2000);
static void send_button_state_notification()
{
if (!gas_notification_enabled) {
return;
}
sl_status_t sc = sl_bt_gatt_server_notify_all(btn_report_characteristic_handle,
sizeof(gasdata),
(const uint8_t*)&gasdata);
if (sc == SL_STATUS_OK) {
// Serial.print("Notification sent, button state: ");
// Serial.println(btn_state);
}
}
按键中断函数实现:通过判断当前按键按下的次数,实现气体检测类型的切换
static void btn_state_change_callback()
{
// If the board has a built-in button
#ifdef BTN_BUILTIN
// The real button state is inverted - most boards have an active low button configuration
// btn_state = !digitalRead(BTN_BUILTIN);
// btn_state_changed = true;
//uint8_t current_type, last_type;
static uint8_t cnt=0;
if(digitalRead(BTN_BUILTIN) == 0)
{
cnt++;
if(cnt > 5)
{
cnt = 0;
}
}
switch(cnt)
{
case 1:gas_type=CO;break;
case 2:gas_type=C2H5OH;break;
case 3:gas_type=H2;break;
case 4:gas_type=NH3;break;
case 5:gas_type=CH4;break;
deafult:break;
}
#endif // BTN_BUILTIN
}
通过BLE给开发板传输设置气体检测类型指令的相关代码
// This event indicates that the value of an attribute in the local GATT
// database was changed by a remote GATT client
case sl_bt_evt_gatt_server_attribute_value_id:
// Check if the changed characteristic is the LED control
if (gas_type_control_characteristic_handle == evt->data.evt_gatt_server_attribute_value.attribute) {
Serial.println("Gas Type control characteristic data received");
// Check the length of the received data
if (evt->data.evt_gatt_server_attribute_value.value.len == 0) {
break;
}
// Get the received byte
uint8_t received_data = evt->data.evt_gatt_server_attribute_value.value.data[0];
// Turn the LED on/off according to the received data
if (received_data == 0x01) {
// set_led_on(false);
// Serial.println("LED off");
gas_type=CO;
} else if (received_data == 0x02) {
// set_led_on(true);
// Serial.println("LED on");
gas_type=C2H5OH;
} else if (received_data == 0x03) {
// set_led_on(true);
// Serial.println("LED on");
gas_type=H2;
} else if (received_data == 0x04) {
// set_led_on(true);
// Serial.println("LED on");
gas_type=NH3;
} else if (received_data == 0x05) {
// set_led_on(true);
// Serial.println("LED on");
gas_type=CH4;
}
}
break;
五、功能展示图及说明
乙醇易挥发,空气中乙醇含量很低,当前传感器下限检测不到默认为0,亮绿灯。
使用医用酒精在手指上喷一下,靠近气体传感器,随着距离的远近,ppm浓度数据有变化,并且亮红灯。
关于BLE指令控制气体检测类型请看视频。
六、设计中遇到的难题和解决方法
设计中使用了来自DFRobot的MICS-5524 MEMS气体传感器,针对这个传感器DFRobot官方已经编写好了相对应的lib,但是当用起来的时候,发现ADC读取到的原始模拟量总是负值,并且获取到的ppm浓度也总是为0。反复验证查询发现与硬件无关,最后发现官方lib的cpp源码中有一个问题
通过ADC读取数据,但是其ADC分辨率只有10位,对应1023,当读取到的ADC原始模拟量数据稍大点,超过1023后,原始模拟量数据就会是负值,并且ppm浓度总是为0。因此目前官方lib支持的ADC是10bit,对应于UNO R3此类板子。但是Nano Matter的ADC是12bit的,且不支持修改分辨率。
因此将此处的1023更换为4095后即可正常使用该传感器,目前使用中暂未出现异常。
七、心得体会
感谢贸泽电子和硬禾学堂联合举办的活动,让更多的国外优秀板卡走进大家的视野,拓宽大家的眼界。希望此类活动以后可以层出不穷。