内容介绍
【项目简介】
科技的不断进步,促进物联网蓬勃发展,做为物联网的关键部分就是传感器,好像我们的五官可以感知外部的环境,又通过网络把采集的相关数据反馈给最终用户。我本次选择的是Funpack第八期活动的主题任务之二环境监测站,顺便回顾以下任务要求
任务二:环境监测站
利用NANO-33 BLE的传感器,搭建一个小型环境监测站用于监测户外环境。待监测的参数包括:
任务二 | 传感器 |
· 周边环境温度(精度:±0.1°C, ±0.1°F) |
HTS221datasheet |
· 周边环境湿度(精度:±1%) | |
· 大气压强(精度:±0.1kPa, ±0.1psi) | LPS22HB |
· 日照强度(用于判断白天/夜晚) | APDS9960 |
· 周边平均噪声(精度:±1dB) | MP34DT05 |
-通过tftlcd展示上边的数据 | st7789v 240x240 |
【软件】
- os ubuntu20.04
- arduino ide 1.8.13
- 若干库文件
【硬件】
- Arduino Nano 33 BLE Sense x1
- 240x240 st7789 1.44" x1
- 杜邦线若干
关于开发板的介绍请参考官方的文档,非常详细也包括库的介绍
【步骤】
- 驱动tftLCD,型号st7789v,接口标准4线SPI,
开发板 | st7789 |
gnd | gnd |
vcc3.3v | vcc |
D13 | TFT_SCK |
D11 | TFT_MOSI |
D10 | TFT_CS |
D9 | TFT_DC |
D8 | TFT_RESET |
查找st7789v的库文件,非常多,但是能用的很少,运气不错,找到一个直接可以用的,代码如下所示
2.在上一步的基础上,驱动传感器并采集数据显示到LCD上 ,推荐使用官方的库,代码如下
- 首先是温湿度传感器HTS221
主要特征:
0至100%相对湿度范围
电源电压:1.7至3.6 V
低功耗:ODR为1 Hz时为2μA
从1 Hz到12.5 Hz的可选ODR
高rH灵敏度:0.004%rH / LSB
湿度精度:±3.5%rH,20至+ 80%rH
温度精度:±0.5°C,15至+40°C
嵌入式16位ADC
16位湿度和温度输出数据
SPI和I²C接口
示例代码
#include <Arduino_HTS221.h>
void setup() {
Serial.begin(9600);
while (!Serial);
if (!HTS.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while (1);
}
}
void loop() {
// read all the sensor values
float temperature = HTS.readTemperature();
float humidity = HTS.readHumidity();
// print each of the sensor values
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" %");
// print an empty line
Serial.println();
// wait 1 second to print again
delay(1000);
}
输出显示
Temperature = 36.76 °C
Temperature = 36.85 °C
Temperature = 36.83 °C
Detected RIGHT gesture
2
Humidity = 64.82 %
Humidity = 64.76 %
Humidity = 64.65 %
- LPS22HB-MEMS纳米压力传感器:260-1260 hPa绝对数字输出气压计
主要特征:
260至1260 hPa绝对压力范围
电流消耗低至3μA
高超压能力:20倍满量程
嵌入式温度补偿
24位压力数据输出
16位温度数据输出
ODR从1 Hz到75 Hz
SPI和I²C接口
嵌入式FIFO
中断功能:数据就绪,FIFO标志,压力阈值
电源电压:1.7至3.6 V
高冲击寿命:22,000 g
示例代码
#include <Arduino_LPS22HB.h>
void setup() {
Serial.begin(9600);
while (!Serial);
if (!BARO.begin()) {
Serial.println("Failed to initialize pressure sensor!");
while (1);
}
}
void loop() {
// read the sensor value
float pressure = BARO.readPressure();
// print the sensor value
Serial.print("Pressure = ");
Serial.print(pressure);
Serial.println(" kPa");
// print an empty line
Serial.println();
// wait 1 second to print again
delay(1000);
}
输出
Pressure = 100.42 kPa
Pressure = 100.42 kPa
Pressure = 100.42 kPa
Pressure = 100.42 kPa
Pressure = 100.41 kPa
Pressure = 100.41 kPa
- APDS-9960-数字接近,环境光,RGB和手势传感器
主要特征:
微型封装尺寸:长3.94 x宽2.36 x高1.35毫米
与专用中断引脚兼容的I2C接口
深色玻璃后面的高灵敏度支持操作
集成UV-IR块滤光片的RGBC光感测
几何排列的RGBC光电二极管提供均匀的角响应
校准至100mm的检测距离,消除了客户终端产品的校准
四个独立的光电二极管,对不同的方向敏感
集成可见块滤波器的接近度和手势感测
获得专利的屏蔽设计,最大限度地减少了串扰
集成光学透镜,可准直IR LED光束并提高光电二极管灵敏度。
低功耗:睡眠模式下典型值为1.0 µA
示例代码
include <Arduino_APDS9960.h>
void setup() {
Serial.begin(9600);
while (!Serial); // Wait for serial monitor to open
if (!APDS.begin()) {
Serial.println("Error initializing APDS9960 sensor.");
while (true); // Stop forever
}
}
int proximity = 0;
int r = 0, g = 0, b = 0;
unsigned long lastUpdate = 0;
void loop() {
// Check if a proximity reading is available.
if (APDS.proximityAvailable()) {
proximity = APDS.readProximity();
}
// check if a gesture reading is available
if (APDS.gestureAvailable()) {
int gesture = APDS.readGesture();
switch (gesture) {
case GESTURE_UP:
Serial.println("Detected UP gesture");
break;
case GESTURE_DOWN:
Serial.println("Detected DOWN gesture");
break;
case GESTURE_LEFT:
Serial.println("Detected LEFT gesture");
break;
case GESTURE_RIGHT:
Serial.println("Detected RIGHT gesture");
break;
default:
// ignore
break;
}
}
// check if a color reading is available
if (APDS.colorAvailable()) {
APDS.readColor(r, g, b);
}
// Print updates every 100ms
if (millis() - lastUpdate > 100) {
lastUpdate = millis();
Serial.print("PR=");
Serial.print(proximity);
Serial.print(" rgb=");
Serial.print(r);
Serial.print(",");
Serial.print(g);
Serial.print(",");
Serial.println(b);
}
}
我这里使用了手势来切换不同的菜单显示传感器的数据。
if (APDS.gestureAvailable()) {
// a gesture was detected, read and print to serial monitor
int gesture = APDS.readGesture();
switch (gesture) {
case GESTURE_UP:
Serial.println("Detected UP gesture");
menu++;
if(menu>5)
menu=1;
Serial.println(menu);
break;
case GESTURE_DOWN:
Serial.println("Detected DOWN gesture");
menu--;
if(menu==0||menu>6)
menu=5;
Serial.println(menu);
break;
case GESTURE_LEFT:
Serial.println("Detected LEFT gesture");
menu--;
if(menu==0||menu>6)
menu=5;
Serial.println(menu);
break;
case GESTURE_RIGHT:
Serial.println("Detected RIGHT gesture");
menu++;
if(menu>5)
menu=1;
Serial.println(menu);
break;
default:
// ignore
break;
}
输出仅仅使用了光强检测部分
Night!
ALS:16
ALS:16
ALS:16
ALS:16
ALS:12
ALS:12
ALS:13
ALS:13
ALS:14
ALS:14
Day!
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
ALS:138
- MP34DT05-A-MEMS音频传感器全向数字麦克风
主要特征:
单电源电压
低功耗
AOP = 122.5 dBSPL
64 dB信噪比
全向灵敏度
–26 dBFS±3 dB灵敏度
PDM输出
示例代码
#include <PDM.h>
// buffer to read samples into, each sample is 16-bits
short sampleBuffer[256];
// number of samples read
volatile int samplesRead;
void setup() {
Serial.begin(9600);
while (!Serial);
// configure the data receive callback
PDM.onReceive(onPDMdata);
// optionally set the gain, defaults to 20
// PDM.setGain(30);
// initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate
if (!PDM.begin(1, 16000)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
// wait for samples to be read
if (samplesRead) {
// print samples to the serial monitor or plotter
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer[i]);
}
// clear the read count
samplesRead = 0;
}
}
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;
}
输出
-22
-14
-22
-18
-15
-10
-25
-14
-9
-5
采集到的数据转换为分贝(db)代码
void pdm_computeRMSValue(void)
{
for(int i = 0; i < samplesRead; i++){
PDM_RMSValue+= sampleBuffer[i]*sampleBuffer[i];//平方和
}
PDM_RMSValue=PDM_RMSValue/samplesRead;
PDM_RMSValue=sqrt(PDM_RMSValue);//均方根
PDM_RMSValue=20*log10(PDM_RMSValue)+20;//根据升压公式转化为db,+20是修正值
samplesRead=0;
}
3. 简单的菜单实现,主要用手势功能来实现几个传感器的切换
代码
uint8_t p =0 ; //局部刷新
uint8_t menu=0;//0-欢迎界面 1-温度 2-湿度 3-气压 4-环境光强判断黑夜/白天 5-环境噪音
Scheduler.startLoop(switch_sensor);//多菜单切换
//Scheduler.startLoop(tftPrintWelcome);//发现用多任务非常慢
//Scheduler.startLoop(tftPrintTemp);
//Scheduler.startLoop(tftPrintHum);
//Scheduler.startLoop(tftPrintPressure);
//Scheduler.startLoop(tftPrintPDM);
//Scheduler.startLoop(tftPrintALS);
void loop() {
if (APDS.gestureAvailable()) {
// a gesture was detected, read and print to serial monitor
int gesture = APDS.readGesture();
switch (gesture) { //通过检测手势切换菜单
case GESTURE_UP:
Serial.println("Detected UP gesture");
menu++;
if(menu>5)
menu=1;
Serial.println(menu);
break;
case GESTURE_DOWN:
Serial.println("Detected DOWN gesture");
menu--;
if(menu==0||menu>6)
menu=5;
Serial.println(menu);
break;
case GESTURE_LEFT:
Serial.println("Detected LEFT gesture");
menu--;
if(menu==0||menu>6)
menu=5;
Serial.println(menu);
break;
case GESTURE_RIGHT:
Serial.println("Detected RIGHT gesture");
menu++;
if(menu>5)
menu=1;
Serial.println(menu);
break;
default:
// ignore
break;
}
}
// Check if a proximity reading is available.
// tftPrintTest();
delay(500);
}
在程序里进行判断是否当前的菜单,仅举一个例子,其余类似
if(menu==1){ //如果==1显示当前菜单
// read all the sensor values
float temperature = HTS.readTemperature();
//float humidity = HTS.readHumidity();
// print each of the sensor values
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" °C");
if(p!=1)
{p=1;//局部刷新
tft.fillRect(0,80,240,100,BLACK);
【作品图片展示】
简单展示2张,有兴趣可以看视频
温度:
湿度:
【项目总结】
本项目依托两大开源组织(arduino,mbed)的支持,以及丰富的资源库,为我们快速高效的开发提供了可能,nano 33 ble这块小小的开发板集成了众多的传感器,令人惊讶和敬佩。本次活动主要在官方给定的例程的基础之上来完成众多的功能,最后致谢硬禾学堂和得捷提供参加本次活动的机会。