本文记录开发Arduino Nicla Vision的详细过程。
项目目标是设计一个简易的健康装置,具体功能:
可以测量心率,测量结果要通过OLED进行显示并通过Wi-Fi发送到MQTT云平台ThingSpeak。
可以检测摔倒,并通过屏幕进行提示。
一、OLED驱动
本次使用的屏幕是之前参加MAX78000智能手环时候购买的Seeed的SSD1315屏幕。
产品链接:https://wiki.seeedstudio.com/Grove-OLED-Yellow&Blue-Display-0.96-SSD1315_V1.0/

驱动使用的是Adafruit的SSD1306:

包含头文件:
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h>
要留意器件的真实地址:
#define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
显示测试:
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.println(F("Hello, world!"));
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
display.println(3.141592);
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.print(F("0x"));
display.println(0xDEADBEEF, HEX);
display.display();显示效果:

二、MAX30102驱动
驱动采用SPAKFUN的max3010x库,由于这个模块也是IIC接口,所以可以与OLED共用一组IIC。

包含头文件:
#include "MAX30105.h" #include "heartRate.h"
定义相关参数:
MAX30105 particleSensor; const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good. byte rates[RATE_SIZE]; //Array of heart rates byte rateSpot = 0; long lastBeat = 0; //Time at which the last beat occurred float beatsPerMinute; int beatAvg;
初始化传感器:
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1)
;
}
Serial.println("Place your index finger on the sensor with steady pressure.");
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED结果测试:

三、Wi-Fi驱动与ThingSpeak云平台连接
这块开发板开机自带Micropython的固件,要使用Arduino开发其Wi-Fi组件,需要一些特殊操作。
首先打开例程:

然后编译,烧录:

然后烧录后,重启。查看串口输出:

WiFi初始化:
if (WiFi.status() != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(SECRET_SSID);
while (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network
Serial.print(".");
delay(5000);
}
Serial.println("\nConnected.");
}
Serial.println("You're connected to the network");
Serial.println(ssid);
printWifiStatus();
Serial.println();然后安装ThingSpeak库。

之后在头文件中包含如下头文件:
#include <WiFi.h> #include "secrets.h" #include "ThingSpeak.h" // always include thingspeak header file after other header files and custom macros #include <PubSubClient.h>
其中secrets.h中有WiFi名称与密码。还有ThingSpeak的channel的api key。
ThingSpeak初始化与PubSubClient库的初始化:
ThingSpeak.begin(client); // Initialize ThingSpeak MqttClient.setServer(mqtt_server, mqtt_server_port); //设定MQTT服务器与使用的端口,1883是默认的MQTT端口
上传数据到thingSpeak云平台:
// set the fields with the values
ThingSpeak.setField(1, beatAvg);
ThingSpeak.setField(2, irValue);
ThingSpeak.setStatus("HeartBeat_SpO2");
int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
if (x == 200) {
Serial.print("------------Channel update successful----Value: ");
//Serial.print(tempValtoIOT);
Serial.println(" -------------------.");
} else {
Serial.println("Problem updating channel. HTTP error code " + String(x));
}测试结果:本周日12月28日下午5点的数据被实时上传到ThingSpeak云平台。

本次OLED屏幕显示:

关于摔倒的检测,记录开发板正常放置时候的三轴数据,然后模拟开发板坠落,获取此时的三轴数据,然后在代码中对比进行输出。
开发板自带了三轴加速度计,需要包含如下头文件:
#include <Arduino_LSM6DSOX.h>
初始化IMU:
//Init IMU:
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1)
;
}
Serial.print("Accelerometer sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println(" Hz");
Serial.println();
Serial.println("Acceleration in g's");
Serial.println("X\tY\tZ");检测代码:
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z);
if (fabs(x) >= 0.2) {
Serial.println("***********Falling Down. Warning!****************");
Serial.print(x);
Serial.print('\t');
Serial.print(y);
Serial.print('\t');
Serial.println(z);
//Write to OLED:
display.clearDisplay();
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 20); // Start at top-left corner
display.print(F("Fall Down"));
display.display();
}
}测试结果:当开发板下落时候,串口检测到异常,通过串口输出。
开发过程中也遇到了一些错误,记录如下:

解决办法:使用itoa代替ltoa。
itoa(value, valueString, 10);
我要赚赏金
