之前我们介绍了esp32本地端的相关配置,为了实现与手机的远程交互,还需要Blynk软件。
Blynk APP
关于Blynk的下载和初始配置,在这里就不过多介绍了,详细的教程见下面的文章:【FireBeetle Board-ESP32教程之一】Blynk—控制LED灯
我们将BLynk的手机端配置成如下的样子:
图中的V8、V10、V11等为虚拟引脚,即Virtual Pin,引脚的分配需要在arduino上进行。
ESP32 配置
首先需要引用Blynk的库函数:
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
之后配置令牌和wifi相关的内容
//Blynk的令牌,各个账户不同
char auth[] = "******************";//从手机端上复制
//wifi名称以及密码
char ssid[] = "wifi_name";
char pass[] = "password";
配置虚端口:
//Blynk端的虚端口
int vPin=10;
int vPin2=8;
int vPinChart=9;//这个引脚是给图表使用的
一个获取当前互联网时间的网站配置:
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
struct tm timeinfo;
//画wifi图标
const uint8_t frame0 [] = {
0x00,0x00,0x00,0x00,0x07,0xE0,0x08,0x10,0x13,0xC8,0x24,0x24,0x09,0x90,0x02,0x40,
0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
//显示当前时间需要的函数
void printLocalTime()
{
if (!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
return;
}
Serial.println(timeinfo.tm_hour); // 格式化输出
}
按键虚引脚的配置和回调函数,其中BLYNK_WRITE的参数V11即是我们Blynk端的按钮的引脚,我们通过这个引脚来实现手机端控制ESP32的功能。
int state=1;
BLYNK_WRITE(V11)
{
int pinValue=param.asInt();
state=pinValue;
//Serial.println(pinValue);
}
setup里也要进行相关修改:
void setup() {
Serial.begin(9600);
//SSD1306配置
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
display.clearDisplay();
//MLX90614配置
mlx.begin();
for(int i=0;i<128;i++)
{
Y[i]=0;
}
pinMode( pin, INPUT);//设置管脚为输入
Blynk.begin(auth, ssid, pass);//Blynk的初始化
}
之后就是在主函数体里进行配置了,完整的代码如下:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MLX90614.h>
#include "stdlib.h"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
//Blynk的令牌,各个账户不同
char auth[] = "JbFznocQk7C8mkvWUdA4eXUJz_j3vqyz";
//wifi名称以及密码
char ssid[] = "HUAWEI P30";
char pass[] = "0987654321";
//心跳传感器引脚
int pin =35;
//后面用到的参数
int counter = 0;
int Y[128];
int maxid=0;
int second=0;
double bpm;
double Data[50];
double temperature;
//Blynk端的虚端口
int vPin=10;
int vPin2=8;
int vPinChart=9;
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
struct tm timeinfo;
//画wifi图标
const uint8_t frame0 [] = {
0x00,0x00,0x00,0x00,0x07,0xE0,0x08,0x10,0x13,0xC8,0x24,0x24,0x09,0x90,0x02,0x40,
0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
#define SCREEN_WIDTH 128 // OLED 屏幕宽, 单位像素点数
#define SCREEN_HEIGHT 64 // OLED 屏幕长, 单位像素点数
#define OLED_RESET -1 // 重置引脚
//实例化SSD1306显示屏
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//实例化MLX90614传感器
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
int state=1;
BLYNK_WRITE(V11)
{
int pinValue=param.asInt();
state=pinValue;
//Serial.println(pinValue);
}
void printLocalTime()
{
if (!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
return;
}
Serial.println(timeinfo.tm_hour); // 格式化输出
}
void setup() {
Serial.begin(9600);
//SSD1306配置
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
display.clearDisplay();
//MLX90614配置
mlx.begin();
for(int i=0;i<128;i++)
{
Y[i]=0;
}
pinMode( pin, INPUT);//设置管脚为输入
Blynk.begin(auth, ssid, pass);
}
void loop() {
//串口打印温度传感器值
//Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempC());
//Serial.print("*C\tObject = "); Serial.print(mlx.readObjectTempC()); Serial.println("*C");
//Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempF());
//Serial.print("*F\tObject = "); Serial.print(mlx.readObjectTempF()); Serial.println("*F");
//Serial.println();
temperature=mlx.readObjectTempC();
for(int j=0;j<50;j++)
{
Data[j]=analogRead(pin);
delay(10);
}
for(int j=0;j<50;j++)
{
if(Data[j]>Data[maxid])
{
maxid=j;
}
}
for(int j=0;j<50;j++)
{
if(Data[j]>Data[second]&&Data[j]<=Data[maxid]&&abs(j-maxid)>5)
{
second=j;
}
}
if((maxid-second!=0)&&(3000/abs(maxid-second)<200))
bpm=3000/abs(maxid-second);
else
bpm=bpm;
Serial.println(Data[0]);
for(int i=31;i>0;i--)
{
Y[i]=Y[i-1];
Y[0]=bpm-70;//64*(Data[0]-2700)/(100);
}
if(temperature>30&&state==1)
{
display.clearDisplay();
//display.drawString(0,0, "Counter: " + String(counter));
display.drawLine(96,0,96,64,SSD1306_WHITE);//y
display.drawLine(0,32,96,32,SSD1306_WHITE);
display.drawLine(96,45,128,45,SSD1306_WHITE);
//x坐标轴绘制
for(int i=0;i<96;i++)
{
int count=i/4;
int res=i%4;
if(res==0)
{
display.drawLine(i,Y[count],i+4,Y[count+1],SSD1306_WHITE);//画线
}
else
{
}
}
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(100,5);
display.println(int(temperature));
display.setCursor(115,1);
display.println("o");
display.setCursor(120,5);
display.println("C");
display.setCursor(100,22);
display.println(int(bpm));
display.setCursor(100,30);
display.println("BPM");
if (Blynk.getstate())
{
display.drawBitmap(105,48,frame0,16,16,SSD1306_WHITE);
}
display.fillCircle(counter,32,2,SSD1306_WHITE);
display.display();
}
else
{
WiFi.begin(ssid, pass);
//while (WiFi.status() != WL_CONNECTED)
//{
//delay(500);
// Serial.print(".");
//}
Serial.println("WiFi connected!");
// 从网络时间服务器上获取并设置时间
// 获取成功后芯片会使用RTC时钟保持时间的更新
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
//WiFi.disconnect(true);
//WiFi.mode(WIFI_OFF);
//Serial.println("WiFi disconnected!");
display.clearDisplay();
display.drawCircle(20,32,16,SSD1306_WHITE);
display.drawLine(20,32,26,32,SSD1306_WHITE);
display.drawLine(20,32,20,16,SSD1306_WHITE);
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(40,32);
display.println(timeinfo.tm_hour);
display.setCursor(70,32);
display.println(":");
display.setCursor(90,32);
display.println(timeinfo.tm_min);
display.display();
printLocalTime();
delay(970);
//state=1;
}
if(counter<96)
{
counter=counter+4;
}
else
{
counter=0;
}
delay(200);
Serial.println(state);
if(state==0)
{
Blynk.begin(auth, ssid, pass);
Blynk.run();
delay(2000);
}
else
{
Blynk.run();
}
//向blynk发送数据
Blynk.virtualWrite(vPin,bpm);
Blynk.virtualWrite(vPin2,temperature);
Blynk.virtualWrite(vPinChart,Y[0]);
}
上面的代码中有几个部分需要讲解一下:
这一部分是显示时间的相关代码,在读取到当前的温度值时,若大于30度,说明此刻是有人使用的,那么OLED屏幕将显示心跳体温数据。而If语句中的state,是由Blynk端控制的,这样就可以实现Blynk控制ESP32的显示模式。
else中,将会显示当前的网络时间。
if(temperature>30&&state==1)
{
//这里是之前我们写好的代码
}
else
{
WiFi.begin(ssid, pass);
//while (WiFi.status() != WL_CONNECTED)
//{
//delay(500);
// Serial.print(".");
//}
Serial.println("WiFi connected!");
// 从网络时间服务器上获取并设置时间
// 获取成功后芯片会使用RTC时钟保持时间的更新
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
//WiFi.disconnect(true);
//WiFi.mode(WIFI_OFF);
//Serial.println("WiFi disconnected!");
display.clearDisplay();
display.drawCircle(20,32,16,SSD1306_WHITE);
display.drawLine(20,32,26,32,SSD1306_WHITE);
display.drawLine(20,32,20,16,SSD1306_WHITE);
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(40,32);
display.println(timeinfo.tm_hour);
display.setCursor(70,32);
display.println(":");
display.setCursor(90,32);
display.println(timeinfo.tm_min);
display.display();
printLocalTime();
delay(970);
//state=1;
}
由于显示时间使用的是另一个网站,所以在切换模式的时候,也需要进行网站的切换:
if(state==0)
{
Blynk.begin(auth, ssid, pass);
Blynk.run();
delay(2000);
}
else
{
Blynk.run();
}
之后就是向Blynk服务器发送数据:
//向blynk发送数据
Blynk.virtualWrite(vPin,bpm);
Blynk.virtualWrite(vPin2,temperature);
Blynk.virtualWrite(vPinChart,Y[0]);
主函数里有一个小If语句:
if (Blynk.getstate())
{
display.drawBitmap(105,48,frame0,16,16,SSD1306_WHITE);
}
这句话的效果是如果连上了WIFI,则会在屏幕上显示一个小的WIFI图标,表示已连接。要实现这个效果需要对Blynk库函数进行更改:
首先找到 blynk-library-master库文件夹,进入src子目录里,找到
BlynkSimpleEsp32.h文件,在class BlynkWifi中添加如下函数:
int getstate()
{
if(WiFi.status() == WL_CONNECTED)
{
return 1;
}
else
{
return 0;
}
}
效果如图
使用上面的代码,我们可以实现从手机Blynk APP上读取ESP3采集到的数据,并且绘制成表格的形式。在离开人体3秒后OLED显示屏进入待机模式,显示当前的时间。Blynk APP上的按钮也可以控制待机模式的转换。
具体的代码讲解见:基于ESP32和arduino实现的心跳体温检测系统
至此,我们的项目就完成了,希望能给学弟学妹们带来一定的帮助。