Conteo de pulsos con Arduino

Si lo haces reducirás la cantidad de dientes del engranaje plastico o sea el movimiento angular.
El tema es que si reemplazaras ese engranaje por uno metálico y usas un sensor magnético o uno de efecto hall que detecte cada diente, tendrias la precisión que estas buscando.
 
Si lo haces reducirás la cantidad de dientes del engranaje plastico o sea el movimiento angular.
El tema es que si reemplazaras ese engranaje por uno metálico y usas un sensor magnético o uno de efecto hall que detecte cada diente, tendrias la precisión que estas buscando.

Descarto esa opcion por el momento, muy complicado cambiar ese engranaje por uno metalico. Tendría que mandar a que lo fabriquen y va a salir mas caro que la parabólica seguramente. Tampoco se si acá en Uruguay alguien fabrica engranajes.

No creo que necesite una precisión diente x diente. Así como esta funciona, pero si puedo duplicar la precisión mucho mejor.

Sale más barato usar las dos interrupciones que poner el doble de imanes.

Los imanes son muy baratos. A que te refieres con usar las 2 interrupciones? usarla en modo CHANGE?
Por lo que vi si lo uso de esa forma (que yo pensaba que funcionaba mejor) en realidad hace un movimiento corto y después uno largo.

El lunes comprare los imanes y voy a probar.
 
Olvida el modo CHANGE, esta claro (al menos para mi) que no es el camino.
Usa FALLING y agrega mas imanes y eso reducirá a la mitad lo que ahora se desplaza con FALLING.
Por otro lado los imanes son muy grandes, eran adecuados para el reed switch pero con el sensor Hall ahora estan sobrados.
Podrias usar mas pequeños y distribuir mas aún. Considéralo.
 
He usado indistintamente Rising, falling o chance a unas "bonitas velocidades" sin pegas.
Claro, si el imán no cubre el 50% del hueco hay menos tiempo del Rising al falling que al revés, pero tienes más pulsos.
Si los quieres iguales tendrás que mecanizar los iguales pero eso puede ser complejo sin herramientas adecuadas.
También puedes poner varios sensores en paralelo decalados unos grados, ya no recuerdo si eran colector abierto, si lo son se ponen sin más los que quieras.

Si ahora no tienes ruido ni rebotes ya has ganado cosas. Simplicidad del circuito, robustez frente a vibraciones etc. Puedes quitar todo el código de filtrado.
 
Estuve avanzando con el codigo del posicionador y me olvide de un detalle.
Tengo definida la variable que cuenta los pulsos como "volatile".
Esta puede aumentar o disminuir dentro de la interrupción en cualquier momento.

Pero ademas dentro del loop() cada X tiempo solamente leo la variable para hacer varias cosas:
Controlar que realmente se este moviendo el motor
Hacer la variación de velocidad con el control proporcional.
Muestro el valor en la LCD.

Debería de parar las interrupciones antes de acceder a la variable? o puedo copiar el contador a otra variable "temporal" y usar esa dentro del loop?
de esa forma el conteo real no se vería afectado cierto?

El fin de semana desarmo nuevamente el motor y les informo la reducción del mecanismo.
Consegui unos imanes de neodimio de 3mm x 1mm.
 
Esto de detener las interrupciones se emplea seguido cuando cuentas pulsos de un caudalimetro o RPM en una ventana de tiempo, pero no es tu caso.
Aca cuentas sectores entre imanes (90 grados) y debido a la reducción de tus engranajes eso tendrá una equivalencia en dientes desplazados o mejor dicho recorridos.
Esta claro que la cantidad de dientes desplazados, deberían ser la menor cantidad pero son lo que por ahora 4 imanes y la reducción determinan.
Puedo equivocarme pero cuento 3 o 4 dientes que se desplazan, nada mas. Me parece bastante bien. Si aumentaras al doble los imagens reducirias a 2 dientes el movimiento.
 
Última edición:
En realidad no hace falta hacer volátiles a las variables globales.
Se hace volátiles a una variable local que no quieres que se destruya al salir de la función.
Si accedes en el main y en la interrupción es que es global.
 
Tomado de Luis Llamas,
Qué soy y como usar interrupciones en Arduino

Para poder modificar una variable externa a la ISR dentro de la misma debemos declararla como «volatile». El indicador «volatile» indica al compilador que la variable tiene que ser consultada siempre antes de ser usada, dado que puede haber sido modificada de forma ajena al flujo normal del programa (lo que, precisamente, hace una interrupción).
Al indicar una variable como Volatile el compilador desactiva ciertas optimizaciones, lo que supone una pérdida de eficiencia. Por tanto, sólo debemos marcar como volatile las variables que realmente lo requieran, es decir, las que se usan tanto en el bucle principal como dentro de la ISR.
 
Pues será así, yo nunca declaré volatile las variables y siempre me iban bien en las interrupciones porque eran globales (creo). Cuando vi un ejemplo en el que la variable era declarada dentro de la función, entendí que al salir de la función la variable se destruye y por eso había de ser "volatile". En ese ejemplo era un contador o algo así que nunca hubiera contado ya que cada vez que se entraba la variable era nueva.
En cualquier caso , "por si acaso" desde que leí lo de volatile las declaro así pero ya digo que siempre me han funcionado bien sin hacerlo.
 
Es que las volatile casi siempre tambien son globales por que deben ser accedidas por diferentes funciones (una de ellas siempre es una ISR), y las globales siempre van en el heap a diferencia de las locales que viven en el stack y por eso nace y mueren con la funcion que las declara.

En el caso de la consulta, que sean "volatile" es el primer paso, el siguiente es asegurar que la variable se procesa (lee y escribe) en forma atomica, cosa que es dificil de saber si la variable tiene mas de un byte de tamaño. En ese caso hay que encerrar la zona donde las interrupciones pueden ocurrir, con un macro del AVR-GCC que se llama algo como ATOMIC_READ y ATOMIC_WRITE (no recuerdo exactamente el nombre) para que los accesos a las variables multibyte sean atomicos y no se produzca la lectura de unos bytes mientras actualizo los otros...y les garantizo que van a necesitar estos macros.
 
Ok. Entonces dentro del loop al inicio la copiaré de forma atómica a otra variable temporal y leo la copia.
En realidad no necesariamente tiene qué tener el valor exacto en ese momento, principalmente es para verificar que si el motor esta encendido realmente se esté moviendo .

Existe la posibilidad de perder alguna interrupción? Porque en ese instante estarán paradas.

Otra duda, si las interrupciones son muy frecuentes existe la posibilidad de que no pueda leer correctamente el puerto serie?
La comunicación es a 115200 baudios y leo un máximo de 16 caracteres
 
Existe la posibilidad de perder alguna interrupción? Porque en ese instante estarán paradas.
Depende de la frecuencia con la que ocurran las interrupciones. De todas formas, la zona "protegida en form atómica" debe ser lo mas corta posible para minimizar el riesgo de saltear alguna interrupcion...y solo vos sabés cual es la frecuencia mas elevada a la que ocurren las interrupciones...

Fijate que es parte de un código que subí al foro el año pasado, y mirá que corta es la zona protegida:
C:
#ifdef USE_TIMER1
ISR(TIMER1_COMPA_vect)    // interrupt service routine
#else
#ifdef USE_TIMER0
ISR(TIMER0_COMPA_vect)    // interrupt service routine
#else
#ifdef USE_TIMER2
ISR(TIMER2_COMPA_vect)    // interrupt service routine
#else
#pragma GCC error "You must define USE_TIMER0, USE_TIMER1 or USE_TIMER2 in dispatcher.h"
#endif
#endif
#endif
{
  tickCounter++;
}


/* acá viene mas verdura... */

unsigned int get_ticks() {
  unsigned int tmp;
 
  ATOMIC_BLOCK( ATOMIC_RESTORESTATE ) {
    tmp = tickCounter;
  }
  return tmp;
} // get_ticks
 
El puerto serie del Arduino funciona con interrupciones y tiene dos buffers fifo de 32 bytes cada uno. Eso dice la documentación.
En principio cuanto más rápido menos tarda y es mas probable que vacíe el buffer antes de que llegue el siguiente pulso del sensor.
El problema gordo viene cuando mandas más de 32 bytes que el sistema se paraliza hasta que "trague" la uart la trama de bytes. Si envías menos de 32 es transparente, el programa funciona con normalidad mientras va saliendo el contenido del buffer. Todo eso lo dice la documentación, pero yo que soy un descreído lo comprobé midiendo tiempos con un analizador lógico, activaba un pin al empezar el serial.print y lo desactiva después.ientras veía ese pin veía la tra de la uart que seguía después de caer el pin.
 
Atrás
Arriba