TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Trev_11 en 10 de Octubre de 2007, 15:01:29
-
Hola :) ,intento tomar cada 400ms ,prefijados por interrupcion del timer0,la cantidad de pulsos recogidos por el timer1 en modo externo,mi idea seria ke con cada pulso se tenga una revolución,parece ke funciona bien,busco un numero redondo al temporizar el timer0 en 2ms,pero sobre el display se observa una oscilacion sobre la cantidad de pulsos correcta(si tiene ke leer 50 pulsos durante esos 400ms muestra sobre el LCD 50 un momento y 51 al sig.y de nuevo a 50)alguien puede ayudarme a corregir este error?.
Dejo el archivo proteus.
Saludos
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT,PUT,BROWNOUT,NOPROTECT,NOLVP,NOWDT
#include <lcd.c>
#byte portb=6
double rev_s,rev_m;
double pulsos;
int aux;
#int_rtcc
void muestreo()
{
if(aux==200)
{
aux=0;
pulsos=get_timer1();
set_timer1(0);
rev_s=pulsos/0.4;
rev_m=rev_s*60;
}
aux+=1;
set_timer0(130);
}
main()
{
set_tris_c(0x01);
set_tris_d(0x00);
lcd_init();
setup_timer_0(rtcc_div_16|rtcc_internal);
enable_interrupts(global);
enable_interrupts(int_rtcc);
setup_timer_1(t1_external_sync);
set_timer1(0);
set_timer0(130);
lcd_putc("Rev/s=");
lcd_gotoxy(1,2);
lcd_putc("Rpm=");
while(1)
{
lcd_gotoxy(8,1);
printf(lcd_putc,"%.0f",rev_s);
lcd_gotoxy(6,2);
printf(lcd_putc,"%.0f",rev_m);
delay_ms(3000);
}
}
-
Hay varias cosas... por partes:
Lo primero es que dentro de la interrupción del timer haces dos operaciones con decimales cuando por norma general hay que salir de la interrupción lo antes posible.
Yo lo cambiaría por un flag y la operación la haría en el main.
Por otro lado el retardo ese de 3 segundos en el main realizado con un delay_ms() particularmente no me gusta nada, ya que puede dar problemas. La solución es utilizar un timer para generar los retardos que te interesen y mediante un flag realizar las esperas.
Finalmente y si mis cálculos no han sido erróneos (estoy espeso esta mañana) la configuración de tu timer es:
T = (1 / 4MHz) · 4 · 16 · (256 - 130) = 0,002016
Si haces el muestreo cada 200 interrupciones tienes 0,4032 que NO son 400ms sino algo más por lo que ese error se puede ir sumando hasta hacer que te entre una interrupción más.
-
Hola Darkvect,gracias por responderme,mira es verdad,saque las 2 cuentas fuera,ajuste el timer a 131 para ke de exactamente 20ms y sigo con el mismo problema sigue oscilando con un pulso de mas,no se ke se puede hacer pero igual te doy las gracias :)
-
Una forma tonta que yo utilizo para establecer la configuracion del timer (cualquiera) es utilizar el Wizard que trae el CCS, abro un proyecto nuevo y le cargo el pic y el cristal que realmente voy a utilizar.
Luego activo la interrupcion del timer en cuestion, y por ultimo en la solapa de configuarcion de ese timer, elijo los valores hasta que me da el tiempo exacto que busco entre interrupciones, anda muy bien y me ahorra trabajo de los calculos, que son tediosos... :-/ :-/
-
Bueno gracias Mglsoft lo voy a probar,aunque ya no creo que tenga mas vuelta esto,si no que otra cosa se les ocurre,a mi nada!,chau :(
-
En efecto,tal como te indican por arriba el usar decimales es un mal rollo, ya que a medida que la frecuencia aumenta el error es mayor. Luego tienes en el programa una división de los pulsos por 0,4 o lo que es lo mismo una multiplicación de los pulsos por 2,5, otro decimal.
He estado haciendo números y con tus valores, el TMR0 se desborda cada 2016us, con lo que tomas datos del TMR1 cada 200·2016=403,2ms, con lo que el 2,5 debiera de ser 2,48 y no 2,5.
En fin yo corrigiría todo esto para que no aparecieran decimales.
Otra cosa, ¿cual es el intervalo de frecuencias (mínimo-máximo) que deseas? Te lo digo porque la fosc=4Mhz no sirve para cualquier intervalo de frecuencias.
Pon exactamente como tienes el programa ahora.
Un saludo
-
Bueno,que tal :) gracias por responder,bueno redondie el muestreo para hacerlo cada 500ms(cosa que no era mi idea,1/2 segundo me parece mucho tiempo,pero bueno esto lo hice con prueba y error)para que con ello me diera un numero redondo sin decimales y seguimos igual(sino mirenlo en el proteus),ahh y mi idea era medir la velocidad de motores DC oscilando entre las 3000 y 10000 rpm o sea entre los 50 y 150 pulsos que es donde menos error esto comete.Saludos
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT,PUT,BROWNOUT,NOPROTECT,NOLVP,NOWDT
#include <lcd.c>
#byte portb=6
double rev_s,rev_m;
double pulsos;
int aux;
#int_rtcc
void muestreo()
{
if(aux==250)
{
pulsos=get_timer1(); //Esto se ejecuta cada 2ms*250=500ms
set_timer1(0);
aux=0;
}
aux+=1;
set_timer0(131); //T=(1/4000000)*4*16*(256-131)=0.002s=2ms
}
main()
{
set_tris_c(0x01);
set_tris_d(0x00);
lcd_init();
setup_timer_0(rtcc_div_16|rtcc_internal);
enable_interrupts(global);
enable_interrupts(int_rtcc);
setup_timer_1(t1_external_sync);
set_timer1(0);
set_timer0(131);
lcd_putc("Rev/s=");
lcd_gotoxy(1,2);
lcd_putc("Rpm=");
while(1)
{
lcd_gotoxy(8,1);
rev_s=pulsos*2; //No hay decimales.
printf(lcd_putc,"%.0f",rev_s);
lcd_gotoxy(6,2);
rev_m=rev_s*60;
printf(lcd_putc,"%.0f",rev_m);
delay_ms(1000);
}
}
-
Yo tu no me preocuparía demasiado por la presición, un motor girando de 3000 a 10 000 rpm, puede que tenga un momento de giro que se corresponda con 3000rpm en un instante y otro después haya dado 150 vueltas a 3010rpm, así que no te preocupes demasiado, si quieres aumentar la presición, puedes hacer dos cosas, metes más pulsos por vuelta en el timer1 y mides por menos espacio de tiempo, un conjunto elevado de muestras y luego promedias, o simplemente dejas las cosas como están y no cojas demasiada lucha.
Recuerda que un motor es un dispositivo mecánico, así que para subir o bajar la velocidad en algunos cientos de rpm, tomará tiempo si la idea es controlar la velocidad de giro, creo que tu aplicación anda bien.
Lo que te aconsejan de irte volando de las subrrutinas de interrupción, es de momento lo mejor que puedes hacer, por ejemplo puedes tomar las muestras cada poco tiempo y acumularlas en una variable de promedio, y actualizar la LCD, cada 1s, notarás que es más estable el proceso.
Saludos
Reinier
-
Bueno creo que ya está, me piqué con él y hasta que no lo he sacado no he parado. Además esto lo tenía ya hecho por algún sitio, se lo solucioné a un Picmaniaco hace mucho tiempo, pero no he podido encontrarlo, así que me ha tocado hacerlo de nuevo y esta vez de manera diferente saltandome un par de reglas:
- En una interrupción haz lo que necesites y lárgate rápidamente :D
- En las temporizaciones no uses decimales hijo mío :D
Y es que las reglas estan para eso ... para romperlas.
Bueno ahí va el programa que me ha tenido en vilo desde las 5 de la mañana:
#include <16f876.h>
#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#include <lcd.c>
#include <math.h>
#define radios 4 //Encoder de 4 radios
float n;
int16 pulsos;
int8 interrupcion;
int16 velocidad_s,velocidad_m;
#int_RTCC
RTCC_isr()
{
pulsos=get_timer1(); //Se entra en la interrupción cada 10ms
interrupcion++;
if(interrupcion==100) //10ms · 100 = 1s
{
n=pulsos/radios;
velocidad_s=floor(n+(n-floor(n))); //Redondea n, por si recibe algún pulso
//de más ó de menos
velocidad_m=velocidad_s*60;
lcd_putc('\f'); //Borra display
lcd_gotoxy(1,1);
printf(lcd_putc,"%lu rev/s %uradios",velocidad_s,radios); //rev/s
lcd_gotoxy(1,2);
printf(lcd_putc,"%lu r.p.m.",velocidad_m); //r.p.m.
interrupcion=0;
set_timer1(0);
//set_rtcc(178); //Inicializa el TMR0
set_rtcc(217); //Inicializa el TMR0
}
else
{
//set_rtcc(178); //Inicializa el TMR0
set_rtcc(217); //Inicializa el TMR0
set_timer1(pulsos); //Recupera los pulsos
}
}
main()
{
set_tris_c(0x01); //Entrada de pulsos por RC0
enable_interrupts(GLOBAL);
enable_interrupts(INT_RTCC);
//setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);
//set_rtcc(178); //10ms -> 10000us -> 10000/128=78,125 -> 256-78=178
setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_256);
set_rtcc(217); //10ms -> 10000us -> 10000/256=39,0625 -> 256-39=217
setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1);
set_timer1(0);
interrupcion=0;
lcd_init();
while(1);
}
Revisarlo, deshuesarlo y manosearlo todo lo que querais a tuti plen.
Ya me direis algo ... chao, chao
Un saludo
-
Hola :lol: ,bueno lo del promedio me parece interesante por lo menos ahora no oscila tanto,aunque da lecturas algo erroneas.
#include <16f877.h>
#use delay(clock=4000000)
#fuses XT,PUT,BROWNOUT,NOPROTECT,NOLVP,NOWDT
#include <lcd.c>
#byte portb=6
double rev_s,rev_m;
double pulsos;
int aux,flag;
#int_rtcc
void muestreo()
{
if(aux==250)
{
flag+=1;
if(flag==4)
{
pulsos+=get_timer1();
pulsos/=4;
rev_s=pulsos*2;
rev_m=rev_s*60;
set_timer1(0);
flag=0;
}
aux=0;
}
aux+=1;
set_timer0(131); //T=(1/4000000)*4*16*(256-131)=0.002s=2ms
}
main()
{
set_tris_c(0x01);
set_tris_d(0x00);
lcd_init();
setup_timer_0(rtcc_div_16|rtcc_internal);
enable_interrupts(global);
enable_interrupts(int_rtcc);
setup_timer_1(t1_external_sync);
set_timer1(0);
set_timer0(131);
lcd_putc("Rev/s=");
lcd_gotoxy(1,2);
lcd_putc("Rpm=");
while(1)
{
delay_ms(1000);
lcd_gotoxy(8,1);
printf(lcd_putc,"%.0f",rev_s);
lcd_gotoxy(6,2);
printf(lcd_putc,"%.0f",rev_m);
}
}
-
Bueno bacan tu laburo gracias Pocher :) a mi me cuesta bastante seguir esas reglas y pienso que bueno si el C nos permite realizar operaciones con decimales en ventaja del asembler creo que hay que usarlas pero si ustedes lo dicen...y teniendo en cuenta sus experiencias para mi que soy novato vale,pues de antemano gracias y me pongo a echarle un ojo a tu programa! :-/ .Salu2 a todos.
-
Era broma, sigue las reglas, sobre todo si empiezas. Lo que ocurre que a veces te emperras en una cosa y te preguntas ¿y esto porqué no tiene que funcionar así? y es lo que me ha sucedido en este caso.
Mañana si tengo un rato, intentaré hacerlo todo desde el main y sin interrupciones ¿Quién dá más?
Un saludete
-
Bacan!! funciona de pelos como diria Bart hehe :-) salvo cuando pongo radios=1 pero bueno,ahora si que puedo seguir adelante!!,Pocher ni idea de esa flor de funcion jaja,ya me parecia necesario que existiera una función asi,pero bueno no tengo un buen manual de C,todo lo que aprendi lo hice chusmeando por aqui :-/.Ahora que tengo la velocidad instantanea quiero poder ingresarle por un pad la velocidad de referencia y contrastarla permanentemente con aquella y poder realizar la corrección pertinente al duty del PWM,algo asi como un burdo control a lazo cerrado ya vere que me sale.Salu2!!
-
Cuantos más radios dibujes menor error. Lo normal es poner 4.
-
Hola, ¡eh voila!
Os dejo el programa, en el cual no se emplean decimales para la temporización del TMR0, ya que lo hago girar una vuelta completa, sin precargarlo y al no haber precarga no se pierde tiempo en la instrucción de precarga (no hay set_timer0()).
Tampoco entra en la interrupción con lo que tampoco se pierde tiempo.
Para esta técnica es necesario usar un cristal de 3,2768MHz ó otro cualquiera de forma que no aparezcan decimales en el cálculo de la temporización y que aunque el cálculo de la temporización sea exacto no haya que precargar al TMR0 (el de 4MHz no sirve), es decir que la precarga sea de 0.
Como alguién habrá deducido esta es la técnica para programar un reloj con un PIC que funcione bien, sin retrasos ni adelantos.
Este es el programa:
#include <16f876.h>
#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use fast_io(B)
#use delay(clock=3276800) //Para conseguir 1s sin precargar (retrasos) al TMR0
#include <lcd.c>
#include <math.h>
#bit T0IF=0x0B.2
#define radios 4 //Encoder de 4 radios
main()
{
float n;
int16 pulsos;
int8 cuenta_interrupciones;
int16 velocidad_s,velocidad_m;
lcd_init();
lcd_putc('\f');
set_tris_c(0x01); //Entrada de pulsos por RC0
setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);
// El TMR0 se desbordará cada: Temp=(256-0)·(4·128)/3,2768=40ms (40ms · 25 = 1s)
setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RTCC);
cuenta_interrupciones=0;
set_timer1(0);
set_timer0(0);
T0IF=0;
while(1)
{
if(T0IF)
{
T0IF=0;
cuenta_interrupciones++;
if(cuenta_interrupciones==25) // 40ms · 25 = 1s
{
pulsos=get_timer1();
n=pulsos/radios;
velocidad_s=floor(n+(n-floor(n))); //Redondea n, por si recibe algún pulso
//de más ó de menos
velocidad_m=velocidad_s*60;
lcd_putc('\f'); //Borra display
lcd_gotoxy(1,1);
printf(lcd_putc,"%lu rev/s %uradios",velocidad_s,radios); //rev/s
lcd_gotoxy(1,2);
printf(lcd_putc,"%lu r.p.m.",velocidad_m); //r.p.m.
cuenta_interrupciones=0;
set_timer1(0);
set_timer0(0);
}
}
}
}
Como esta pregunta de como contar pulsos se ha hecho muchas veces a lo largo de estos años, dejaré unos días los programas para que los reviseis, posteriormente los subiré al subforo de Ejemplos para simular (sin quitarlos de aquí) donde añadiré la correspondiente simulación.
Yo aprendí a programar a base de picarme y resolver dudas a los demás, lástima que muchos de esos programas no me los copié. Podía haber hecho una colección y publicarla por aquí por si servía a alguien.
Un saludo
-
Esta muy bueno y es todavia mas preciso,pero no se si conseguire ese cristal :D ,no te parece mucho un segundo para el ciclo?,digo porque me gustaria modificar el duty al final de cada ciclo y en un segundo puede pasar mucho,hoy que es feriado me voy a poner con eso ya les contare.Salu2 a todos
-
Hola pocher, si me permites una pequeña sugerencia, podrias modificar el código que pusiste:
main()
{
int8 radios=4; //Encoder de 4 radios
float n;
int16 pulsos;
int8 cuenta_interrupciones;
int16 velocidad_s,velocidad_m;
Por:
#define radios 4
main()
{
float n;
int16 pulsos;
int8 cuenta_interrupciones;
int16 velocidad_s,velocidad_m;
Con eso el código es ligeramente más corto y más rápido.
Un saludo
-
oido cocina, marchando una de #define
-
Hola :) modifique el código un poco,le agregue un keypad para poder visualizar un numero de 4 digitos sobre la LCD,me surge otro problema,tengo pequeños cambios esporadicos en la lectura de la velocidad despues de cada vez que ingreso este numero,le agregue un par de lineas y mejoró pero no del todo,como podria solucionarse?,gracias les dejo el codigo:
#include <16f877.h>
#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=4000000)
#include <lcd.c>
#include <math.h>
#byte portb=6
#define radios 4
int TECLA_PULSADA;
int8 digitos; //Encoder de 4 radios
float n;
int16 pulsos;
int8 interrupcion;
int16 velocidad_s,velocidad_m;
char escan_teclado()
{
int tecla=44;
int i=0;
int vect[5]={0x0E,0x0D,0x0B,0x07,0};
int matriz_teclado[4][3]={1,2,3,4,5,6,7,8,9,0,0,0};
while(i<4)
{
portb=vect[i];
if(!input(PIN_B4))
{
tecla=0;
tecla=matriz_teclado[i][tecla];
}
if(!input(PIN_B5))
{
tecla=1;
tecla=matriz_teclado[i][tecla];
}
if(!input(PIN_B6))
{
tecla=2;
tecla=matriz_teclado[i][tecla];
}
i++;
}
return(tecla);
}
#int_RB
RB_isr()
{
disable_interrupts(int_rtcc);
port_b_pullups(true);
digitos=0;
lcd_gotoxy(7,1);
lcd_putc(" ");
while(digitos<4)
{
while(escan_teclado()!=0x2c)
{
TECLA_PULSADA=escan_teclado();
if(digitos==0){
lcd_gotoxy(1,1);
printf(lcd_putc,"V.Ref=%d",TECLA_PULSADA);
}
if(digitos==1){
printf(lcd_putc,"%d",TECLA_PULSADA);
}
if(digitos==2){
printf(lcd_putc,"%d",TECLA_PULSADA);
}
if(digitos==3){
printf(lcd_putc,"%d",TECLA_PULSADA);
delay_ms(250);
printf(lcd_putc," R.p.m");
}
delay_ms(1000);
digitos++;
}
}
portb=0x00;
set_timer1(0);
enable_interrupts(int_rtcc);
set_timer0(217);
}
#int_RTCC
RTCC_isr()
{
pulsos=get_timer1(); //Se entra en la interrupción cada 10ms
interrupcion++;
if(interrupcion==100) //10ms*100 =1s
{
n=pulsos/radios;
velocidad_s=floor(n+(n-floor(n))); //Redondea n, por si recibe algún pulso
//de más ó de menos
velocidad_m=velocidad_s*60;
lcd_gotoxy(1,2);
printf(lcd_putc,"Vel.=%lu R.p.m.",velocidad_m); //r.p.m.
interrupcion=0;
set_timer1(0);
//set_rtcc(178); //Inicializa el TMR0
set_rtcc(217); //Inicializa el TMR0
}
else
{
//set_rtcc(178); //Inicializa el TMR0
set_rtcc(217); //Inicializa el TMR0
set_timer1(pulsos); //Recupera los pulsos
}
}
main()
{
set_tris_b(0xf0);
portb=0x0f;
set_tris_c(0x01); //Entrada de pulsos por RC0.
set_tris_d(0x00);
enable_interrupts(global);
enable_interrupts(int_rtcc);
enable_interrupts(int_rb);
//setup_timer_0 ( rtcc_internal|rtcc_div_128);
//set_rtcc(178); //10ms -> 10000us -> 10000/128=78,125 -> 256-78=178
setup_timer_0 ( rtcc_internal|rtcc_div_256);
set_rtcc(217); //10ms -> 10000us -> 10000/256=39,0625 -> 256-39=217
setup_timer_1(t1_external|t1_div_by_1);
set_timer1(0);
interrupcion=0;
lcd_init();
printf(lcd_putc,"V.Ref=3500 R.p.m");
lcd_gotoxy(9,1);
while(1);
}
-
Hola, yo pienso que si desea la mayor precision y velocidad en la muestra de los datos le recomiendo no hacer escaneos de pulsos por segundo, mas bien mida el tiempo entre un pulso y el siguiente, asi obtiene exactamente las revoluciones y puede mostrar los datos de manera instantanea sin tener que esperar a que pase un segundo...
Yo lo he hecho y me ha funcionado de maravilla
-
hola, estoy haciendo algo parecido y no he podido entender lo que hacen ustedes con la variable "radios". si alguno me pudiera explicar su función les agradecería mucho, porque no entiendo cómo dividiendo los pulsos por esa variable da correcta la lectura. gracias!
-
estimados:
se me estan por care todas las nueces del nogal y sigo con este problema. No puedo encontrar la falla en este programa para mikroc.
La logica es similar a muchos programas los cuales investigue pero no doy en la tecla, sumado a mi novatez en el tema.
adjunto codigo, espero que me puedan ayudar. NO TOMAR EN CUENTA LOS COMENTARIOS DEL PROGRAMA
///////////////////////////
void envio1 ();
void envio2 ();
void envio3 ();
void recibo ();
void pulsos ();
unsigned int peso1,peso2,set,temp_p1,temp_p2,cntL,cntH, sel, i;
unsigned int TMR1H_old, TMR1L_old, cnt, TMR1H_NEW, TMR1L_NEW;
void interrupt()
{ // Rutina de interrupción
cnt++;
INTCON =0xa0;
tmr0=217;
// Interrupción causa el incremento de cnt por 1
}
void main()
{
ADCON1 = 0x81; // Configure analog inputs and Vref en la entrada RA3
PORTA = 0; // Reiniciar el puerto PORTA
TRISA = 0xFF; // PORTA is input
TRISB = 0x00; // Pins RB7, RB6 are outputs
//Configuro el prescaler del Timer1
T1CON.TMR1CS = 1; //modo de trabajo de tmr1 como contador de pulsos externos
T1CON.T1OSCEN = 0; //Desabilita el Oscilador externo
T1CON.T1SYNC = 1; // desabilita la sincronizacion con el reloj
T1CON.T1CKPS1 = 0;
T1CON.T1CKPS0 = 0; // Start timer1
OPTION_REG = 0x87; // Pre-escalador en 256
INTCON =0xa0;
cnt=0;
TMR1H=0;
TMR1L=0;
Usart_Init(19200);
TMR1H_old = 0;
TMR1L_old = 0;
//precarga
do {
T1CON.F0 = 1; //habilito cnt de pulsos
envio1();
//delay_ms(10);
envio2();
//delay_ms(10);
if (cnt==100)
{
TMR1H_NEW = TMR1H;
TMR1L_NEW = TMR1L;
TMR1H_old = TMR1H;
TMR1L_old = TMR1L;
TMR1H=0;
TMR1L=0;
cnt=0;}
else
{
TMR1H_NEW = TMR1H_old;
TMR1L_NEW = TMR1L_old;
}
// ENVIO DE CUENTAS TMR1
Usart_Write(TMR1H_NEW);
Usart_Write(TMR1L_NEW);
Usart_Write(cnt);
Usart_Write(TMR0);
Usart_Write (0x0A);
recibo();
PORTB = set;
} while(1);
}
void envio1()
{
peso1 = Adc_Read(0); // Get results of AD conversion
delay_us(5);
temp_p1 = ADRESH;
temp_p2 = ADRESL;
Usart_Write(temp_p1);
Usart_Write(temp_p2);
}
void envio2()
{
peso2 = Adc_Read(1); // Get results of AD conversion
delay_us(5);
temp_p1 = ADRESH;
temp_p2 = ADRESL;
Usart_Write(temp_p1);
Usart_Write(temp_p2);
}
void recibo ()
{
if (Usart_Data_Ready())
{
set = Usart_Read();
}
}
-
Luego de releer este hilo me he dado cuenta de un error de concepto cometido por mi al hacerte la primera recomendación.
Lo que en realidad debí recomendarte implica que los sufrimientos a los que te has sometido pudieron ser evitados al utilizar adecuadamente las opciones que muy probablemente ya vienen incluidas en el hardware de tu microcontrolador.
Si utilizas el TIMER1 en modo Input capture te podrías ahorrar una pila de problemas. En este modo lo que haces es medir el tiempo que le toma al temporizador detectar una cierta cantidad de pulsos por la entrada externa. De este modo si por ejemplo tu motor tiene un detector de índice, es decir un detector que da un pulso por revolución, puedes perfectamente saber con el timer cuanto le tomó al motor dar una vuelta completa. Si el motor gira muy rápido, entoces lo dejas dar varias vueltas y promedias el tiempo entre el número de vueltas y así obtienes la velocidad angular media del motor.
Es un método muy eficaz, incluso si tienes un encoder que da varios pulsos por vuelta, basta con configurar el módulo en modo Input Capture y decirle cuantos frentes de subida o caía o ambos deseas contar, luego calculas y listo.
Si escoges apropiadamente la cantidad de pulsos a contar, supongamos que cuentas pulsos en potencias de dos, entoces puedes ahorrarte algunas divisiones con un simple desplazamiento del resultado. Hay muchas formas de hacer esto de manera eficaz y eficiente. Con mucho menos código y a velocidades de vértigo. Sin tener que utilizar dos TIMERs y poner cristales externos de valores de resonancia complicados o difíciles de hayar.
Un saludo
Reinier