这是整体思路,下面写一些踩坑的东西
供电
踩坑:两节纽扣电池
正常来说用两节CR2032供电电压是6v,过一个降压模块降到3.3v,电压是正确的。但是实际上是不可以正常工作,可能是电流不支持吧具体原因我不清楚(sad)又接到5v降压模块上给uno供电,灯能亮但是比较微弱,也不能正常工作,遂放弃。
锂电池
单节锂电池标的是3.7v,实际上电表测出来崭新的电池竟然3.9v,我比较害怕电压不稳常,所以串联了两节锂电池达到7.5v左右之后进行降压到3.3v。单节锂电池过完我的降压模块后只能输出0.3v左右,具体原因可能是降压模块的输入要求。这样串联后接5v降压也可以给uno供电,测试过没问题。
esp32联网
blinker
防止移动位置之后信号不好或者离开范围还得改代码这种麻烦事,直接使用手机热点来作为wifi的局域网。手机和esp32都连接同一个热点就可以了。
使用blinker库里面的例程做简单修改,看不懂的部分不要修改,以及记得回调函数的绑定,不然无法工作,还有手机端按钮数据小组件的名称一定要和程序对应
心跳包&实时数据
心跳包就是1min更新一次,刷新也更新一次
实时数据就是实时变化的,不需要刷新
esp32软串口
softserial库
因为需要蓝牙模块做串口通信,所以定义了一个新的软串口。需要softSerial库,使用方法如下:参考文章链接粘不进来
在 Arduino ESP32 中,可以使用软串口(SoftwareSerial)库来实现串口通信。软串口是通过软件模拟的串口,可以通过任意两个 GPIO 引脚来实现串口通信。
下面是一个示例代码,演示了如何使用软串口在 ESP32 上进行串口通信:
#include <SoftwareSerial.h>
// 设置软串口的引脚
SoftwareSerial mySerial(2, 3); // RX, TX
void setup() {
Serial.begin(9600); // 打开硬串口,用于[调试](https://geek.csdn.net/edu/300981ef51993cfd737d329c71ba77f9?dp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6NDQ0MDg2MiwiZXhwIjoxNzA3MzcxOTM4LCJpYXQiOjE3MDY3NjcxMzgsInVzZXJuYW1lIjoid2VpeGluXzY4NjQ1NjQ1In0.RrTYEnMNYPC7AQdoij4SBb0kKEgHoyvF-bZOG2eGQvc&spm=1055.2569.3001.10083)输出
mySerial.begin(9600); // 打开软串口
}
void loop() {
if (mySerial.available()) { // 如果软串口有数据可读
char c = mySerial.read(); // 读取一个字符
Serial.print(c); // 在硬串口上输出字符
}
if (Serial.available()) { // 如果硬串口有数据可读
char c = Serial.read(); // 读取一个字符
mySerial.write(c); // 在软串口上发送字符
}
}
在上面的代码中,我们使用了引脚 2 和 3 作为软串口的 RX 和 TX 引脚,分别连接到另一个串口设备。在 setup()
函数中,我们打开了硬串口和软串口,分别用于调试输出和串口通信。
在 loop()
函数中,我们使用了 mySerial.available()
和 Serial.available()
函数来检查软串口和硬串口是否有数据可读。如果有数据可读,我们就使用 mySerial.read()
和 Serial.read()
函数来读取数据,并通过 mySerial.write()
和 Serial.print()
函数来发送和输出数据。
需要注意的是,在使用软串口时,需要确保 RX 和 TX 引脚不会被其他设备占用。此外,软串口的波特率需要与另一个串口设备的波特率相同,否则数据可能无法正确传输。
esp32 IIC
踩坑:板载
我使用的时WEMOS LOLIN32 lite
没有找到板载IIC,网上查阅资料发现esp32应该默认的是22 21 引脚,但是这个板子没有引出来21引脚,所以选择自定义IIC引脚
踩坑但大部分适用:自定义引脚
如果是没有用库函数或者例程里用了wire.begin()就可以用这个方法,但是有的库不能用。在 Arduino 中,ESP32 的 I2C 接口可以使用自定义的引脚,可以通过 Wire.begin()来设置。下面是一个简单的例子:
#include <Wire.h>
#define SDA_PIN 21
#define SCL_PIN 22
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
// 其他初始化[代码](https://geek.csdn.net/educolumn/1572ef9b473b4e00f6b2bf6d428b7c27?spm=1055.2569.3001.10083)
}
void loop() {
// I2C 通信[代码](https://geek.csdn.net/educolumn/1572ef9b473b4e00f6b2bf6d428b7c27?spm=1055.2569.3001.10083)
}
在使用自定义引脚时,需要在 Wire.begin ()中指定引脚编号。
库文件的自定义引脚
这个是例程里直接begin的自定义方法,比较麻烦
参考超棒的文章,基本能解决大部分问题
心率血氧模块
踩坑:插电不亮灯
不要信淘宝商家的鬼话,插上不亮灯,必须初始化之后才能亮灯,IIC通信错误也不亮灯,RD角和GND短接会亮的特别明显,但是会发烫,不要接,只接VIN,GND,SDA,SCL这四个
踩坑:选择型号
最开始我用的是MAX30100,资料比较少,后来改用了MAX30102(黑色版本也可以使用)紫板和黑板都可以直接接3.3v,不需要额外修改电路。黑板可以直接接3.3v供电然后uno的逻辑电平,紫板没试。5v供电理论上可以,没试,怕模块烧了又得买。
至于绿色的我没有使用过,好像需要跳线和外界电阻,不推荐。
例程里有实时心率和平均心率,平均心率更稳一点(但实际上并不可靠,偶尔能读出正常80-90的心率,其他时间就是比较乱,刚开始的十几秒钟会抽风,过一会就好了)
注意手指碰到板子上的这几个引脚也会导致抽风,记得做好绝缘
以及esp32不适用这个模块pulse sensor的例程,uno可能可以,我没试。这个模块应该是不需要IIC。
IIC驱动+例程
库的名字叫30105,但是MAX30102也可以使用
OLED屏幕
U8g2库
直接去Arduino IDE下载,这个OLED直接插在uno的板载IIC口就可以了
蓝牙AT主从模式
踩坑:DX BT-18 只有从机模式(改用HC05主从一体)
手里有的模块是DX BT-18,后来查阅数据手册发现只有从机模式,两个模块不能够通信。下单HC05主从一体。两个模块配好主从机之后其实就相当于连了一根数据线,程序上不需要更改任何部分。
进入AT模式 两闪一停
需要给一个配置成主机,一个配置成从机,使用USB-TTL配合串口调试助手就可以,Arduino板也可以,没用过,实际上是一样的功能。
占用串口
注意uno端我直接用的默认串口,所以烧录的时候记得拔下来,配软串口也可以。
项目逻辑
esp32发送指令,uno接收并响应
当心率和体温都低于某个阈值的时候,进入睡眠模式,将温度调高,当心率和体温升高,即快要醒来时,将空调温度调低,光闹钟从暗变亮,唤醒睡眠。
为了方便展示所以直接在手机端新建了两个按钮来代表人体数据的变化。
源码
esp32(手环端)
//找例程?文件》示例》第三方》blinker》blinker-hello里面找找
#define BLINKER_WIFI
//设置软串口引脚为RX和TX
#include <DHT.h>
#define DHTPIN 27
#define DHTTYPE DHT11 // DHT 11//选择自己的型号
//#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
// Download Adafruit DHT-sensor-library library here:
// https://github.com/adafruit/DHT-sensor-library
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
MAX30105 particleSensor;
#include <Blinker.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(32,33);
float beatsPerMinute;
int beatAvg;
float BEAT;
float AVERAGE;
uint32_t read_time = 0;
int mode =1; //0=normal 1=blinker
float humi_read, temp_read;
char auth[] = "你自己的密钥,在手机端";
char ssid[] = "热点名称";
char pswd[] = "热点密码";
BlinkerNumber HUMI("humi");
BlinkerNumber TEMP("temp");
BlinkerNumber INITIALBEAT("beat");
BlinkerNumber AVERAGEBEAT("avg");
BlinkerButton Button1("sleepmode");
BlinkerButton Button2("awakemode");
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
#define I2C_SDA 12
#define I2C_SCL 14
TwoWire I2CBME = TwoWire(0);
void dataRead(const String & data)
{
BLINKER_LOG("Blinker readString: ", data);
Blinker.vibrate();
uint32_t BlinkerTime = millis();
Blinker.print("millis", BlinkerTime);
}
void heartbeat()
{
HUMI.print(humi_read);
TEMP.print(temp_read);
}
void rtData()
{
Blinker.sendRtData("beat", BEAT);
Blinker.sendRtData("avg", AVERAGE);
Blinker.printRtData();
}
void button1_callback(const String & state)
{
if(mode==1){//这个mode==1是方便展示写的,正常使用的时候mode==0,直接检测温度和心率
mySerial.print("1");
}
}
void button2_callback(const String & state)
{
if(mode==1){
mySerial.print("2");
}
}
void setup()
{
Serial.begin(115200);
mySerial.begin(38400);//设置波特率为38400
BLINKER_DEBUG.stream(Serial);
Serial.println("Initializing...");
I2CBME.begin(I2C_SDA, I2C_SCL, 400000ul);
// Initialize sensor
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
if (!particleSensor.begin(I2CBME, 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
Blinker.begin(auth, ssid, pswd);
Blinker.attachRTData(rtData);
Blinker.attachData(dataRead);
Blinker.attachHeartbeat(heartbeat);
Button1.attach(button1_callback);
Button2.attach(button2_callback);
dht.begin();
}
void loop()
{
Blinker.run();
long irValue = particleSensor.getIR();
if(mode==0){//正常工作
if (temp_read<=36 && AVERAGE<=70 )
{
mySerial.println("1");
}
if (temp_read>=36.5 && AVERAGE>=85 )
{
mySerial.println("2");
}
}
if (read_time == 0 || (millis() - read_time) >= 2000)
{
read_time = millis();
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
BLINKER_LOG("Failed to read from DHT sensor!");
return;
}
float hic = dht.computeHeatIndex(t, h, false);
humi_read = h;
temp_read = t;
BLINKER_LOG("Humidity: ", h, " %");
BLINKER_LOG("Temperature: ", t, " *C");
BLINKER_LOG("Heat index: ", hic, " *C");
}
if (checkForBeat(irValue) == true)
{
//We sensed a beat!
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20)
{
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable
//Take average of readings
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
Serial.print("IR=");
Serial.print(irValue);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.print(beatAvg);
BEAT=beatsPerMinute;
AVERAGE=beatAvg;
if (irValue < 50000)
Serial.print(" No finger?");
Serial.println();
}
uno(模拟空调端)
#include <Servo.h>
#include <Arduino.h>
#include <U8g2lib.h>
//去库里找例程修改就行,不要自己手搓
//#ifdef U8X8_HAVE_HW_SPI
//#include <SPI.h>
//#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
//注意这个是一大片注释里面挑出来一个你要用的然后取消注释
Servo SG90;
int pos=0;
int com=0;
int temp=23;
void setup() {
// put your setup code here, to run once:
Serial.begin (38400);
pinMode (3,OUTPUT);
SG90.attach(8);
u8g2.begin();
u8g2.enableUTF8Print();
// pinMode (A0,OUTPUT);
// pinMode (A1,OUTPUT);
// pinMode (A2,OUTPUT);
// pinMode (A3,OUTPUT);
// pinMode (A4,OUTPUT);
// pinMode (A5,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
u8g2.clearBuffer();
if(Serial.available()){
com=Serial.read();
Serial.print(com);
}
u8g2.setFont(u8g2_font_fub42_tr);
u8g2.setFontDirection(0);
u8g2.setCursor(5,60);
u8g2.print(String(temp)+" C");
u8g2.setFont(u8g2_font_profont12_mf);
u8g2.setCursor(88,18);
u8g2.print("o");// write something to the internal memory
//u8g2.drawFrame(20, 20, 50, 40);
u8g2.sendBuffer();
if(com==49)
{
Serial.print ("asleep");
SG90.write(80);
u8g2.setFont(u8g2_font_fub42_tr);
u8g2.setFontDirection(0);
u8g2.setCursor(5,60);
temp=28;
u8g2.print(String(temp)+" C");
u8g2.setFont(u8g2_font_profont12_mf);
u8g2.setCursor(88,18);
u8g2.print("o");
u8g2.sendBuffer(); // transfer internal memory to the display
delay(1000);
com=0;
}
if(com==50)
{
Serial.print ("awake");
//pos=90;
SG90.write(120);
u8g2.setFont(u8g2_font_fub42_tr);
u8g2.setFontDirection(0);
u8g2.setCursor(5,60);
temp=25;
u8g2.print(String(temp)+" C");
u8g2.setFont(u8g2_font_profont12_mf);
u8g2.setCursor(88,18);
u8g2.print("o");// write something to the internal memory
//u8g2.drawFrame(20, 20, 50, 40);
u8g2.sendBuffer();
com=0;
}
}