Hola.
En su momento me hice un generador de sañal para simular un motor a injeccion, una vez acabado quiero visualizar las rpm desde otro arduino.
asi que empece usando una salida digital del "master" y mandado un pulso cada vuelta al "Slave" que esta conectado a una pantalla.
funciona relativamente bien pero un poco inestables las rpm, me puse a buscar y vi varias opciones que usan las interrupciones asi que aplique el codigo a mi situacion.
Desde ese momento las rpm son estables pero hay una cosa que no funciona bien ni con la opcion digital ni con la Iqr.
Las RPM que visualizo no son exactas pero eso puede ser por algun delay que puedo ver a posterior, voy subiendo rpm y cuando paso de 2880rpm que son 124108us baja a 2460rpm visualizando 145900us y asi sucesivamente a 4100 5400 etc... el calculo es correcto de las rpm falla los micros() (creo)
He verificado con un osciloscopio y la señál del puso es correcta y si conecto una adquisicion de datos a la salida las rpm son correctas y sin este salto.
Por lo que se aprecia es como si cada vez va acortando el tiempo hasta que hace el salto en ese momento las rpm son exactas.
¿Alguna idea?
Muchas gracias.
#include <openGLCD.h> //Cargamos la libreria para la pantalla 128x64 GLCD.
volatile byte rpmcount = 0; //Variable para la interrupcion.
unsigned int rpm = 0; //Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.
unsigned long timeactual = 0; //Variable time long ya que trabajamos en microsegundos y nos movemos por encima de los 100.000 en algunos casos.
unsigned long timeold = 0; // Misma situacion timeactual.
unsigned long timenew = 0; // Misma situacion anterior.
void setup()
{
attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.
GLCD.Init(); //inicializamos la pantalla
GLCD.ClearScreen(); //limpiamos la pantalla
GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente
}
void rpm_fun()
{
rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
}
void loop()
{
if (rpmcount == 6) { //cuando tenemos cinco pulsos
timeactual = micros(); //asignamos a la variable timeactual los microsegundos actuales.
detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM
timenew = (timeactual - timeold); //despejamos el tiempo que se a necesitado para tener los 5 pulsos.
delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
// y a altas rpm casi no se pueden ver.
rpm = (((6 * 1000000) / (timenew)) * 60); //hacemos el calculo de las RPM
GLCD.ClearScreen(); // limpiamos la pantalla
GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
GLCD.print(rpm); // imprimimos el valor rpm en pantalla
GLCD.CursorToXY(0, 15);// seleccionamos una segunda posicion en patalla
GLCD.print(timenew); // imprimios los micros() que se han tardado los 5 pulsos
attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion
rpmcount = 0; // ponemos a cero el contador
timeold = micros(); // asignamos el tiempo actual.
}
}
Te recomiendo que leas las Normas del foro y luego apliques como se deben postear los códigos. No como adjuntos sino pegados usando tag para cada cosa. En este caso tag de códigos </> este es un ícono, no algo que tienes que poner antes de tu código, te lo comento porque ya alguien hizo eso.
A ver si estos pequeños y sutiles cambios mejoran.
Si no ocurre, te propongo un cambio radical de la rutina de medición.
Pruébala y nos comanteas!!
#include <openGLCD.h> //Cargamos la libreria para la pantalla 128x64 GLCD.
volatile byte rpmcount = 0; // Variable para la interrupcion.
unsigned int rpm = 0; // Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.
unsigned long timeactual = 0; // Variable time long ya que trabajamos en microsegundos y nos movemos por encima de los 100.000 en algunos casos.
unsigned long timeold = 0; // Misma situacion timeactual.
unsigned long timenew = 0; // Misma situacion anterior.
volatile bool flag = false;
void setup() {
attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.
GLCD.Init(); //inicializamos la pantalla
GLCD.ClearScreen(); //limpiamos la pantalla
GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente
}
void rpm_fun() {
rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
if (rpmcount >= 6) {
timeactual = micros();
flag = true;
}
}
void loop() {
if (flag) { //cuando tenemos seis pulsos
//asignamos a la variable timeactual los microsegundos actuales.
detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM
timenew = (timeactual - timeold); //despejamos el tiempo que se a necesitado para tener los 5 pulsos.
delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
// y a altas rpm casi no se pueden ver.
rpm = 100000 / timenew; //hacemos el calculo de las RPM
GLCD.ClearScreen(); // limpiamos la pantalla
GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
GLCD.print(rpm); // imprimimos el valor rpm en pantalla
GLCD.CursorToXY(0, 15);// seleccionamos una segunda posicion en patalla
GLCD.print(timenew); // imprimios los micros() que se han tardado los 5 pulsos
flag = false;
rpmcount = 0; // ponemos a cero el contador
attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion
timeold = micros(); // asignamos el tiempo actual.
}
}
Hola de nuevo.
Gracias por responder tan rapido.
He probado el codigo y no se veian las rpm al verificarlo he visto que has modificado la formula de calculo, al ponerla como al principio se visualizan pero el problema sigue igual no he apreciado diferencias.
Depende del numero de pulsos el salto se produce mas o menos veces.
De momento no se me ocurre nada he probado muchas combinaciones y siempre pasa, de la unica forma que casi no se aprecia es poner un numero muy alto de pulsos ej. 100 pero en este caso el sistema es inutilizable por el tiempo que necesita para ver las RPM.
Muchas gracias.
necesito que se vean rapido por eso no puedo poner un numero alto de pulsos.
En un principo asignaba un tiempo determinado y leia cuantos pulsos lee en ese tiempo pero la resolucion es muy baja RPM max 13000 = 216hz pero a 2000rpm seria 33,3hz los decimales no sirven asi que un pulso son muchas rpm.
Lo curioso del tema es que es un problema recurrente siempre en el mismo sitio y siempre hace lo mismo no es falta de precision es como si cuando se llega a un valor de microsegundos salta unos pocos,
Podria aumentar el numero de pulsos por giro pero ya no me serviria para el uso que quiero darle.
He hecho una crokis de lo que ocurre.
subo a 3600rpm=97000us cae a 2940rpm=120000us
sigo subiendo 4200rpm=85900us cae a 3500rpm=102000us
5400rpm=66700us cae a 4400rpm=80000us
6000rpm=60000us cae a 5000rpm=71800us.
Cada vez que cae cuando subo paso otra vez por el numeor de rpm donde habia caido antes.
Es un poco extraño si fuera por la precision de los pulsos seria inestable +-500 o 700 rpm pero aqui si dejo la frecuencia fija las rpm estan estables.
Gracias.
¿Y por qué no utilizas directamente el método de Nick Gammon? Creo que es bastante más preciso, y además mide más rápido pues creo que medía el periodo entre dos pulsaciones.
Basicamente dice que para frecuencias bajas debes medir el período y no la frecuencia como esas haciendo.
Asi que midamos el período.
Si quieres medir señales de tan baja frecuencia debes tener una compuerta o GATE por un lapso de tiempo que asegure una lectura precisa. Tu GATE de 100 mseg no es preciso, no asegura una buena lectura.
Asi que si medimos el tiempo entre transiciones de la interrupción tendremos una lectura muy buena y estable.
Parece que lo he solucionado, he probado la opcion de Nick Gammon y no funciona, sucede lo mismo o mas.
asi que pensando en el cometario de surbyte he hecho unas modificaciones usando la logica, al final he tenido que poner un correctivo para que el valor sea exacto +- 10rpm.
#include <openGLCD.h> //Cargamos la libreria para la pantalla 128x64 GLCD.
volatile byte rpmcount = 0; // Variable para la interrupcion.
unsigned int rpm = 0; // Variable rpm tipo int ya que no superamos las 32767 y unsigned no queremos numeros negativos.
unsigned long tiempo_1=0; // Variables para cada pulso
unsigned long tiempo_2=0;
unsigned long tiempo_3=0;
unsigned long tiempo_4=0;
unsigned long tiempo_5=0;
unsigned long tiempo_6=0;
unsigned long tiempo_7=0;
unsigned long tiempo_total=0;
volatile bool flag = false;
void setup() {
attachInterrupt(0, rpm_fun, RISING); //habilitamos la interrupcion y seleccionamos la subida del pulso como accion.
GLCD.Init(); //inicializamos la pantalla
GLCD.ClearScreen(); //limpiamos la pantalla
GLCD.SelectFont(Arial14); //Seleccionamos el tipo de fuente
}
void rpm_fun() {
tiempo_7=tiempo_6; //creamo una operacion que cada vez que entra asigna el tiempo al tiempo anterior y asi tenemos los 7 tiempos para hacer las 6 lecturas
tiempo_6=tiempo_5;
tiempo_5=tiempo_4;
tiempo_4=tiempo_3;
tiempo_3=tiempo_2;
tiempo_2=tiempo_1;
tiempo_1=micros();
rpmcount++; //Cada vez que llega un pulso aumenta el contador en uno
if (rpmcount >= 8) //si queremos el tiempo de 6 dientes necesitamos 7 tiempos y al octavo salta, ahora calcular el tiempo en cada pulso.
{
tiempo_total= ((tiempo_6-tiempo_7) + (tiempo_5 - tiempo_6) + (tiempo_4 - tiempo_5) + (tiempo_3 - tiempo_4)+(tiempo_2 - tiempo_3)+(tiempo_1 - tiempo_2))*1.006;// calculamos el tiempo total de 6 pulsos + un correctivo
flag = true;
}
}
void loop() {
if (flag) { //cuando tenemos seis pulsos
detachInterrupt(0); //desabilitamos la interrupcion para hacer el calculo de las RPM
delay (100); //ponemos este valor para tener una carencia en el display, de los contrario cada 5 pulsos se visualizaria
// y a altas rpm casi no se pueden ver.
rpm = (((6000000) / (tiempo_total))*60); //hacemos el calculo de las RPM
GLCD.ClearScreen(); // limpiamos la pantalla
GLCD.CursorToXY(0, 0); // seleccionamos la posicion de pantalla
GLCD.print(rpm); // imprimimos el valor rpm en pantalla
GLCD.CursorToXY(0, 14);
GLCD.print(tiempo_total);
flag = false;
rpmcount = 0; // ponemos a cero el contador
attachInterrupt(0, rpm_fun, RISING); // habilitamos la interrupcion
tiempo_1=0; //Ponemos todas la variables a 0
tiempo_2=0;
tiempo_3=0;
tiempo_4=0;
tiempo_5=0;
tiempo_6=0;
tiempo_7=0;
tiempo_total=0;
}
}
Nick Gammon no funciona? Por favor.. algo haces mal.
En fin si alcanzaste un resultado satisfactorio bien pero puede mejorarse.
Hubo mucho trabajo este fin de semana y no pudo buscarte la respuesta mas apropiada. Debía probarla y simularla y eso lleva tiempo.
Creo que me he expresado mal, si que funciona pero hace lo mismo podria decir que hace un diente de sierra poco mas o menos como los otros programas, supongo que seria adaptarlo.
Con la opcion ultima es coherente rapido y preciso lo he verificado con el osciloscopio y ocn la adquisicion de datos al maximo hay 10 rpm de error que sera un chorrada ya que si hago el calculo con la calculadora me da exacto.
Si teneis un momento y podeis hecharle un vistazo, seguro que habar mas de una "cosa ilogica" yo me quede con el clipper en msdos y estoy muy oxidado.