一、任务目的:
利用NANO-33 BLE的传感器, 搭建一个小型环境监测站用于监测户外环境。待监测的参数包括:
- 周边环境温度(精度:±1°C, ±0.1°F)
- 周边环境湿度(精度:±1%)
- 大气压强(精度:±1kPa, ±0.1psi)
- 日照强度(用于判断白天/夜晚)
- 周边平均噪声(精度:±1dB)
二、功能介绍及实现思路:
1. 支持:Arduino IDE工具开发,安装下面的库:
2. 实现的功能:
Arduino nano 33 ble sense 的BLE连接手机的蓝牙,板卡通过蓝牙发送温度、湿度、压强、颜色光照强度、环境噪声及判断黑天白天的数据,在NRF Connect APP上显示
3. 代码:
3.1 BLE初始化:
Service是服务,Characteristic是特征值,蓝牙里面有多个Service,一个Service里面又包括多个Characteristic。Service和Characteristic的通用16位UUID需要自己在bluetooth官网上下载并查找,找不到就自己定义128位的UUID,然后设置特征值的UUID和properties,这里我用到了BLEread(APP上只读)和BLEnotify(数据修改就会通知)两个功能,详情可参考ArduinoBLE library
BLEService Station_Service("181A"); // BLE LED Service
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("181A", BLERead | BLEWrite);
BLEShortCharacteristic Temperature_BLE("2A6E", BLERead| BLENotify); // short (sint16)
BLEShortCharacteristic Fahrenheit("2A20", BLERead| BLENotify);
BLEShortCharacteristic Humidity("2A6F", BLERead| BLENotify);
BLELongCharacteristic Pressure_BLE("2A6D", BLERead| BLENotify); //pressure
BLEStringCharacteristic Pressure_PSI("A4E649F4-4BE5-11E5-885D-FEFF819CDC9F", BLERead| BLENotify,64); //pressure
BLEStringCharacteristic ColorandLightIntensity("1648A1AE-5A8D-4544-B3CF-6C497D73E772", BLERead| BLENotify, 64); // String, r,g,b
BLEStringCharacteristic DayorNight("1648A1AE-5A8D-4544-B3CF-6C497D73E773", BLERead| BLENotify,64); // int for ambient light
BLEStringCharacteristic microphone_BLE("590d65c7-3a0a-4023-a05a-6aaf2f22441c", BLERead| BLENotify,64);
const int ledPin = LED_BUILTIN; // pin to use for the LED
void setup() {
Serial.begin(9600);
while (!Serial);
// set LED pin to output mode
pinMode(ledPin, OUTPUT);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
if (!BARO.begin()) {
Serial.println("Failed to initialize pressure sensor!");
while (1);
}
if (!APDS.begin()) { // Initialize Colour, Proximity and Gesture sensor
Serial.println("Failed to initialize Colour, Proximity and Gesture Sensor!");
while (1);
}
if (!HTS.begin()) { // Initialize Temperature and Humidity sensor
Serial.println("Failed to initialize Temperature and Humidity Sensor!");
while (1);
}
PDM.onReceive(onPDMdata);
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
BLE.setDeviceName("Environmental Sensing");
BLE.setLocalName("Weather Station");
BLE.setAdvertisedService(Station_Service);
Station_Service.addCharacteristic(switchCharacteristic);
Station_Service.addCharacteristic(Temperature_BLE);
Station_Service.addCharacteristic(Fahrenheit);
Station_Service.addCharacteristic(Pressure_BLE);
Station_Service.addCharacteristic(Pressure_PSI);
Station_Service.addCharacteristic(Humidity);
Station_Service.addCharacteristic(ColorandLightIntensity);
Station_Service.addCharacteristic(DayorNight);
Station_Service.addCharacteristic(microphone_BLE);
// add service
BLE.addService(Station_Service);
// set the initial value for the characeristic:
switchCharacteristic.writeValue(0);
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
// start advertising
BLE.advertise();
Serial.println("Weather Station");
}
3.2 读取温湿度:
温湿度有通用的16位UUID,只需要写入数据的值,NRF Connect自动显示带上单位的数据
void ReadTemperature() {
float temperature = HTS.readTemperature();
short t = convertFloatToShort(temperature);
Temperature_BLE.writeValue(t);
Serial.print("Temperature = "); Serial.print(temperature);Serial.println("°C");
}
void ReadFahrenheit() {
float fahrenheit = HTS.readTemperature(FAHRENHEIT);
// short t = convertFloatToShort(fahrenheit);
Fahrenheit.writeValue(fahrenheit*10);
Serial.print("Fahrenheit = "); Serial.print(fahrenheit);Serial.println("°F");
}
void ReadHumidity() {
float humidity = HTS.readHumidity();
short t = convertFloatToShort(humidity);
Humidity.writeValue(t);
Serial.print("Humidity = "); Serial.print(humidity);Serial.println("%");
}
3.3 读取压强:
单位为PSI的压强查不到16位UUID,自己定义128位的UUID,发送数据先要把数据和单位打印成字符串,通过发送字符串可以显示
void ReadPressure_KPA() {
float pressure = BARO.readPressure();
short p = convertFloatToShort(pressure);
Pressure_BLE.writeValue(p*100);
Serial.print("Pressure = "); Serial.print(pressure);Serial.println(" kPa");
}
void ReadPressure_PSI() {
float pressure_psi = BARO.readPressure(PSI);
char psi[20];
sprintf(psi,"%fpsi",pressure_psi);
Pressure_PSI.writeValue(String(psi));
Serial.print("Pressure = "); Serial.print(pressure_psi);Serial.println(" psi");
}
3.4 读取颜色和光照强度并判断黑天白天:
调用类里面的函数,通过比较光照强度来判断黑天白天
void ReadColor() {
int tries = 50;
while(APDS.colorAvailable() == 0 && tries > 0) {
tries--;
delay(30);
}
int r, g, b, c;
APDS.readColor(r, g, b, c); // read the color and clear light intensity
char buf[32];
char buff[10];
sprintf(buf, "%d,%d,%d,%d", r, g, b,c);
ColorandLightIntensity.writeValue(String(buf));
Serial.print("Color and intensity= "); Serial.println(buf);
if(c>40){
sprintf(buff,"Daylight");
DayorNight.writeValue(String(buff));
Serial.print("DayorNight= "); Serial.println(buff);
}
else{
strcpy(buff,"/0");
sprintf(buff," Night");
DayorNight.writeValue(String(buff));
Serial.print("DayorNight= "); Serial.println(buff);
}
}
3.4 读取环境噪声:
对数据均值滤波,这个不知道该怎么转成分贝,参考了冷月烟的公式,对数字麦克风不会处理,等大家的项目发布以后,再学习学习
void onPDMdata() {
// query the number of bytes available
int bytesAvailable = PDM.available();
// read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}
//均值滤波
int16_t averageFilter(int16_t in_data)
{
int32_t sum = 0;
for(int i=0; i<9; i++)
{
data[i]=data[i+1];
sum = sum + data[i];
}
data[9] = in_data;
sum = sum + data[9];
return(sum/10);
}
三、心得体会:
感觉Arduino真的上手快,生态强大,C++面向对象封装的库,用起来方便快捷,有许多函数不会调用可以参考Arduino的Reference,更重要的是有很多示例,基本上可以教会你使用绝大多数的函数,但也会有许多坑需要自己解决。