/*
------------------ FIAP --------------------
CHALLENGE 2K25 SPRINT 3 - PASSA A BOLA
Participantes:
Prof. Paulo Marcotti PF2150
Arthur Berlofa Bosi RM564438
Danilo Fernandes dos Santos RM561657
Davi Melo Muniz Falcão RM561818
Mateus Saavedra de Mendonça RM563266
Ulisses Ribeiro Abreu RM562230
--------------------------------------------
Canal ThingSpeak para Processamento dos Dados
https://thingspeak.mathworks.com/channels/3077785
*/
#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
// Credenciais ThingSpeak
const char* ssid = "Wokwi-GUEST"; // Rede Wi-Fi
const char* password = ""; // Senha da rede Wi-Fi
const char* apiKey = "X0SAG9GGYOE4UP0A"; // Write API Key
const char* server = "http://api.thingspeak.com"; // Servidor ThingSpeak
// LCD predefinitions
int lcdColumns = 20;
int lcdRows = 4;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
// Objeto para o sensor MPU6050
Adafruit_MPU6050 mpu;
// Variáveis para a detecção de passos
double accelerationThreshold = 1.2; // Ajuste este valor conforme necessário
bool stepStateX, stepStateY, stepStateZ = false;
int stepCount = 0;
double pace = 0.0;
// Medição do BPM e SPO2.
#define bpmPin 34
#define spo2Pin 35
int bpm, spo2;
// Variaveis de controle de tempo
long lastMillis, actualMillis = 0;
// Declaração de Funções
void clearLCD();
double calcularPaceMedio(int totalDePassos, int tempoTotalEmMillis);
void enviaDados();
void setup() {
Serial.begin(115200);
Serial.println("Iniciando o contador de passos...");
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("BPM:");
lcd.setCursor(0,1);
lcd.print("SPO2:");
lcd.setCursor(0,2);
lcd.print("Passos:");
lcd.setCursor(0,3);
lcd.print("Pace min/Km:");
lcd.setCursor(12,3);
lcd.print("0");
// Inicializa o MPU6050
if (!mpu.begin()) {
Serial.println("Falha ao encontrar o chip MPU6050. Verifique as conexões.");
while (1) {
delay(10);
}
Serial.println("Chip MPU6050 conectado!");
}
// Configura a faixa do acelerômetro
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// Configura a faixa do giroscópio
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// Configura a faixa do filtro digital
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
// Inicialização e loop de verificação da rede Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Conectando ao WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" conectado!");
}
void loop() {
// Atualiza as informações de BPM e SPO2
bpm = map(analogRead(bpmPin), 0, 4094, 0, 300);
spo2 = map(analogRead(spo2Pin), 0, 4094, 0, 100);
// Atualiza a exibição dos dados no display
lcd.setCursor(5,0);
lcd.print(bpm);
lcd.setCursor(6,1);
lcd.print(spo2);
lcd.setCursor(8,2);
lcd.print(stepCount);
lcd.setCursor(13,3);
lcd.print(pace);
// Obter novos eventos do sensor MPU
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
// Detecção de passo eixo X
if ((a.acceleration.x > accelerationThreshold && !stepStateX) && a.acceleration.y < accelerationThreshold && a.acceleration.z < accelerationThreshold) {
stepCount++;
stepStateX = true;
pace = calcularPaceMedio(stepCount, millis());
}
else if (a.acceleration.x < accelerationThreshold && stepStateX) {
// Resetar o estado para permitir a contagem do próximo passo
stepStateX = false;
}
// Detecção de passo eixo Y
if ((a.acceleration.y > accelerationThreshold && !stepStateY) && a.acceleration.x < accelerationThreshold && a.acceleration.z < accelerationThreshold) {
stepCount++;
stepStateY = true;
pace = calcularPaceMedio(stepCount, millis());
}
else if (a.acceleration.y < accelerationThreshold && stepStateY) {
// Resetar o estado para permitir a contagem do próximo passo
stepStateY = false;
}
// Detecção de passo eixo Z
if ((a.acceleration.z > accelerationThreshold && !stepStateZ) && a.acceleration.x < accelerationThreshold && a.acceleration.y < accelerationThreshold) {
stepCount++;
stepStateZ = true;
pace = calcularPaceMedio(stepCount, millis());
}
else if (a.acceleration.z < accelerationThreshold && stepStateZ) {
// Resetar o estado para permitir a contagem do próximo passo
stepStateZ = false;
}
// Atualiza a variavel com o tempo atual
actualMillis = millis();
// Envio de dados a cada 30 segundos ao thingspeak
if (actualMillis - lastMillis > 30000) {
lastMillis = actualMillis;
enviaDados();
}
// Pequeno atraso para não sobrecarregar o loop
delay(100);
// Clear de partes do display
clearLCD();
}
// Função para limpar o display LCD
void clearLCD() {
lcd.setCursor(5,0);
lcd.print(" ");
lcd.setCursor(6,1);
lcd.print(" ");
lcd.setCursor(8,2);
lcd.print(" ");
}
// Função para calcular o pace médio
double calcularPaceMedio(int totalDePassos, int tempoTotalEmMillis) {
// Estimativa de passos por Km.
const double PASSOS_POR_KM = 1000.0;
// Converte o total de passos para quilômetros
double distanciaEmKm = static_cast<double>(totalDePassos) / PASSOS_POR_KM;
// Converte o tempo total de millis para minutos
double tempoTotalEmMinutos = static_cast<double>(tempoTotalEmMillis) / 60000.0;
// O pace é calculado dividindo o tempo total pela distância total
// Se a distância for zero, evitamos a divisão por zero.
if (distanciaEmKm > 0) {
return tempoTotalEmMinutos / distanciaEmKm;
} else {
return 0.0; // Retorna 0 se a distância for zero
}
}
// Função para envio de dados ao ThingSpeak
void enviaDados() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = String(server) + "/update?api_key=" + apiKey + "&field1=" + String(bpm) + "&field2=" + String(spo2) + "&field3=" + String(stepCount) + "&field4=" + String(pace);
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString(); // Resposta da requisição HTTP
Serial.println("Dados enviados ao ThingSpeak.");
Serial.print("Código HTTP: ");
Serial.println(httpCode);
Serial.println("Resposta: ");
Serial.println(payload);
} else {
Serial.print("Erro ao enviar dados. Código HTTP: ");
Serial.println(httpCode);
}
http.end();
} else {
Serial.println("WiFi não conectado. Tentando reconectar...");
}
}
BPM
SPO2