#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include "DHT.h"
#include <Fonts/FreeSansBold18pt7b.h>
#include <Fonts/FreeSans9pt7b.h>
// TFT显示屏引脚定义
#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 23
#define TFT_CLK 18
#define TFT_RST 4
#define TFT_MISO 19
// DHT22引脚定义
#define DHTPIN 13
#define DHTTYPE DHT22
// 电位器引脚
#define POT_PIN 34
// 创建对象
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
DHT dht(DHTPIN, DHTTYPE);
// 变量定义
unsigned long lastBeatTime = 0;
int bpm = 72; // 当前心率
int beatCount = 0; // 心跳次数
int threshold = 2500; // 心跳检测阈值
bool beatDetected = false;
unsigned long lastUpdateTime = 0;
int ecgValue = 0;
int wavePeriod = 1000; // 波形周期(ms)
float temperature = 36.6; // 体温
float humidity = 50.0; // 湿度
// 显示缓冲区
int displayBuffer[320]; // 存储波形数据点
int bufferIndex = 0;
// 健康状态
String healthStatus = "Normal";
// 生成模拟心电波形
int generateECGWave() {
int t = millis() % wavePeriod; // 当前波形位置
int amplitude = 0;
// P波 (0-150ms)
if (t < 150) {
amplitude = map(t, 0, 150, 0, 800);
}
// PR段 (150-200ms)
else if (t < 200) {
amplitude = 800;
}
// QRS波群 (200-300ms)
else if (t < 300) {
amplitude = 3000 - map(t-200, 0, 100, 0, 2500);
}
// ST段 (300-400ms)
else if (t < 400) {
amplitude = 500;
}
// T波 (400-600ms)
else if (t < 600) {
amplitude = map(t-400, 0, 200, 500, 2000);
}
// TP段 (600-1000ms)
else {
amplitude = 0;
}
return amplitude;
}
// 更新健康状态
void updateHealthStatus() {
if (bpm < 50 || bpm > 120 || temperature > 38.0) {
healthStatus = "Warning!";
} else if (bpm < 60 || bpm > 100 || temperature > 37.5) {
healthStatus = "Caution";
} else {
healthStatus = "Normal";
}
}
// 绘制界面框架
void drawUI() {
// 绘制标题
tft.fillScreen(ILI9341_BLACK);
tft.drawRect(0, 0, 320, 240, ILI9341_WHITE);
// 标题
tft.setFont(&FreeSans9pt7b);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(90, 25);
tft.print("ECG HEALTH MONITOR");
// 分割线
tft.drawFastHLine(0, 30, 320, ILI9341_DARKGREY);
// 绘制信息区域
tft.fillRect(5, 35, 310, 45, ILI9341_DARKGREY);
tft.fillRect(5, 85, 310, 45, ILI9341_DARKGREY);
// 波形区域
tft.fillRect(5, 135, 310, 100, ILI9341_BLACK);
tft.drawRect(5, 135, 310, 100, ILI9341_WHITE);
// 状态区域
tft.fillRect(5, 240-40, 310, 35, ILI9341_BLACK);
tft.drawRect(5, 240-40, 310, 35, ILI9341_WHITE);
// 初始化波形缓冲区
for(int i=0; i<320; i++) {
displayBuffer[i] = 100; // 中间位置
}
}
void setup() {
Serial.begin(115200);
// 初始化TFT显示屏
tft.begin();
tft.setRotation(3);
drawUI();
// 初始化DHT传感器
dht.begin();
// 设置引脚
pinMode(POT_PIN, INPUT);
// 显示初始信息
tft.setFont(&FreeSans9pt7b);
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(100, 65);
tft.print("Initializing...");
tft.setCursor(100, 110);
tft.print("Please wait...");
delay(2000);
drawUI();
}
void loop() {
unsigned long currentTime = millis();
// 读取电位器值控制心率 (0-4095)
int potValue = analogRead(POT_PIN);
// 根据电位器值调整心率 (40-180 BPM)
bpm = map(potValue, 0, 4095, 40, 180);
// 根据心率调整波形周期
wavePeriod = 60000 / bpm;
// 生成模拟心电波形
ecgValue = generateECGWave();
// 读取温湿度
temperature = dht.readTemperature();
humidity = dht.readHumidity();
// 如果读取失败,使用默认值
if (isnan(temperature)) temperature = 36.6;
if (isnan(humidity)) humidity = 50.0;
// 添加体温变化模拟
temperature = 36.0 + (bpm - 60) * 0.02;
// 发送数据到串口绘图器
Serial.println(ecgValue);
// 更新波形显示缓冲区
displayBuffer[bufferIndex] = map(ecgValue, 0, 3000, 135+100, 135); // 反转Y轴
bufferIndex = (bufferIndex + 1) % 310;
// 检测心跳 (在QRS波群期间)
if (ecgValue > threshold && !beatDetected) {
beatDetected = true;
beatCount++;
// 计算实际心率
if (lastBeatTime > 0) {
int beatInterval = currentTime - lastBeatTime;
bpm = 60000 / beatInterval; // 每分钟心跳次数
}
lastBeatTime = currentTime;
// 更新健康状态
updateHealthStatus();
}
// 重置心跳检测
if (ecgValue < threshold) {
beatDetected = false;
}
// 每100ms更新一次显示
if (currentTime - lastUpdateTime > 100) {
updateDisplay();
lastUpdateTime = currentTime;
}
delay(10); // 控制循环速度
}
// 更新显示
void updateDisplay() {
// 清除信息区域
tft.fillRect(10, 40, 300, 35, ILI9341_DARKGREY);
tft.fillRect(10, 90, 300, 35, ILI9341_DARKGREY);
// 设置字体和颜色
tft.setFont(&FreeSans9pt7b);
// 显示心率和心跳次数
tft.setTextColor(ILI9341_CYAN);
tft.setCursor(15, 65);
tft.print("HR: ");
tft.print(bpm);
tft.print(" BPM");
tft.setCursor(170, 65);
tft.print("Beats: ");
tft.print(beatCount);
// 显示体温和湿度
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(15, 115);
tft.print("Temp: ");
tft.print(temperature, 1);
tft.print(" C");
tft.setCursor(170, 115);
tft.print("Hum: ");
tft.print(humidity, 0);
tft.print("%");
// 清除波形区域
tft.fillRect(6, 136, 308, 98, ILI9341_BLACK);
// 绘制网格
for(int x=6; x<314; x+=20) {
tft.drawFastVLine(x, 136, 98, ILI9341_DARKGREY);
}
for(int y=136; y<234; y+=20) {
tft.drawFastHLine(6, y, 308, ILI9341_DARKGREY);
}
// 绘制心电图波形
for(int i=0; i<309; i++) {
int x = 6 + i;
int y1 = displayBuffer[(bufferIndex + i) % 310];
int y2 = displayBuffer[(bufferIndex + i + 1) % 310];
// 确保y值在有效范围内
y1 = constrain(y1, 136, 234);
y2 = constrain(y2, 136, 234);
tft.drawLine(x, y1, x+1, y2, ILI9341_YELLOW);
}
// 显示健康状态
tft.fillRect(6, 201, 308, 33, ILI9341_BLACK);
tft.setTextColor(healthStatus == "Warning!" ? ILI9341_RED :
healthStatus == "Caution" ? ILI9341_YELLOW : ILI9341_GREEN);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(80, 230);
tft.print(healthStatus);
}