Hola, buenas tardes.
Estoy adaptando el proyecto de https://www.instructables.com/id/ECG-Simulator/ para colocarle pulsadores (en lugar de potenciómetro) y un display 16x2.
Las modificaciones las he podido realizar con cierto éxito, ya que puedo seleccionar las pulsaciones por botón y visualizar el valor en el display.
La falla que observo es en cuanto a la frecuencia que emite el dispositivo.
Al seleccionar, por ejemplo, 60 pulsaciones por minuto, obtengo una frecuencia de salida de 0.99 Hz.
Dicho problema se agraba al aumentar aún mas las ppm (al llegar al valor máximo -110 ppm- se obtiene una frecuencia de 1.8 Hz que equivalen a 108 ppm).
El código original se puede visualizar en el link que agregúe mas arriba y el código modificado por mi lo dejo mas abajo.
Si alguien puede darme una mano con ese tema, sería de gran ayuda.
#include "SPI.h"
#include <Wire.h>
#include <LiquidCrystal.h>
#define INIT 0
#define IDLE 1
#define QRS 2
#define FOUR 4
#define THREE 3
#define TWO 2
#define ONE 1
const short y_data[] = {};
unsigned int NumSamples = sizeof(y_data) / 2;
unsigned int QRSCount = 0;
unsigned int IdleCount = 0;
unsigned long IdlePeriod = 0;
unsigned int State = INIT;
unsigned int DisplayCount = 0;
float BeatsPerMinute;
unsigned int tcnt2;
unsigned int DisplayValue = 0;
//////////////////////////////////////DISPLAY///////////////////////////////////////////////
const int rs = 10, en = 12, d4 = 8, d5 = 7, d6 = 6, d7 = 5;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//////////////////////////////////////BOTONERA///////////////////////////////////////////////////////////////
const int boton1 = 33;
const int boton2 = 35;
int valorboton1;
int valorboton2;
int ppmanterior1;
int ppmanterior2;
int valorppm;
unsigned int minimo = 30;
unsigned int maximo = 110;
unsigned int actual = 30;
void setup() {
/////////////////////////////////////BOTONERA////////////////////////////////////////////////////////////
pinMode(boton1, INPUT);
pinMode(boton2, INPUT);
///////////////////////////////////////////////////////////////////////////////////////////////////////////
pinMode(3, OUTPUT); // D/A converter chip select (low to select chip)
pinMode(51, OUTPUT); // SDI data
pinMode(52, OUTPUT); // SCK clock
SPI.begin(); // encender el bus SPI
SPI.setDataMode(0); // mode: CPHA = 0, datos capturados en el borde ascendente del reloj (bajo → alto)
SPI.setClockDivider(SPI_CLOCK_DIV64); // system clock / 64
SPI.setBitOrder(MSBFIRST); // bit 7 clocks out first
//////////////CONFIGURACIÓN DEL TIMER//////////////////////////////
TIMSK2 &= ~(1<<TOIE2);
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
ASSR &= ~(1<<AS2);
TIMSK2 &= ~(1<<OCIE2A);
TCCR2B |= (1<<CS22) | (1<<CS20);
TCCR2B &= ~(1<<CS21);
tcnt2 = 131;
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
}
void loop() {
///////////////////BOTONERA///////////////////
valorboton1 = digitalRead(boton1);
valorboton2 = digitalRead(boton2);
/////////////////BOTON 1 (SUBIR PPM)////////////////////////
if (valorboton1==HIGH && ppmanterior1==LOW){
if (actual<maximo){
actual++;
}
else if (actual>=maximo){
actual=maximo;
}
}
/////////////////BOTON 2 (BAJAR PPM)////////////////////////
else if (valorboton2==HIGH && ppmanterior2==LOW){
if (actual>minimo){
actual--;
}
else if (actual<=minimo){
actual=minimo;
}
}
/////////////CORRIGE LA DETECCION DEL FLANCO//////////////
ppmanterior1 = valorboton1;
ppmanterior2 = valorboton2;
noInterrupts();
DisplayValue = actual;
interrupts();
BeatsPerMinute = (float)actual;
noInterrupts();
IdlePeriod = (unsigned int)((float)60000.0 / BeatsPerMinute) - (float)NumSamples; // aca calcula el periodo inactivo dividiendo a 1 minuto sobre las ppm, menos el numero de muestras (543)
interrupts();
delay(20);
}
ISR(TIMER2_OVF_vect) {
// recarga el temporizador
TCNT2 = tcnt2;
switch (State) {
case INIT:
QRSCount = 0;
IdleCount = 0;
// DisplayCount = 0;
State = QRS;
break;
case QRS:
DTOA_Send(y_data[QRSCount]); //envía al CDA valores de y_data y activa el contador QRSCount
QRSCount++;//inicia el contador QRSCount
if (QRSCount >= NumSamples) { //compara el valor contado por QRSCount con el N° de muestras
QRSCount = 0; //si es mayor o igual el conteo al N° de muestras envía el primer valor de las muestras al CDA
DTOA_Send(y_data[0]);
State = IDLE;
}
break;
case IDLE:
IdleCount++;//comienza el contador de periodo inactivo
if (IdleCount >= IdlePeriod) { //compara con el valor obtenido en el calculo de IdlePeriod
IdleCount = 0; //si es mayor o igual pone el contador a cero y envía el estado a QRS
State = QRS;
}
break;
default:
break;
}
////output to the 7-segment display every 50 msec
DisplayCount++;
if (DisplayCount >= 50) {
DisplayCount = 0;
Display7Seg_Send(DisplayValue);
}
}
void DTOA_Send(unsigned short DtoAValue) {
byte Data = 0;
// select the D/A chip (low)
digitalWrite(3, 0); // chip select low
// send the high byte first 0011xxxx
Data = highByte(DtoAValue);
Data = 0b00001111 & Data;
Data = 0b00110000 | Data;
SPI.transfer(Data);
Data = lowByte(DtoAValue);
SPI.transfer(Data);
digitalWrite(3, 1); // chip select high
}
void Display7Seg_Send(unsigned int HeartRate) {
unsigned int value;
value = HeartRate;
//if (value/10<100){
// lcd.setCursor(9,1);
// lcd.print(" ");
//}
lcd.setCursor(7,1);
lcd.print((value));
}
PD: quité los valores de la señal y_data[] para poder subir el código