TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Trev_11 en 10 de Octubre de 2007, 15:01:29

Título: Tomando pulsos del Timer1:velocimetro
Publicado 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
Código: [Seleccionar]
#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);
         }
      }   
     
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: DarkVect en 12 de Octubre de 2007, 11:39:11
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.
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 12 de Octubre de 2007, 19:37:57
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  :)
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: MGLSOFT en 12 de Octubre de 2007, 21:08:51
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... :-/ :-/
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 13 de Octubre de 2007, 10:24:43
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  :(
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 13 de Octubre de 2007, 12:08:20
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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 13 de Octubre de 2007, 13:24:48
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

Código: [Seleccionar]
#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);
         }
      }   
     
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: reiniertl en 13 de Octubre de 2007, 17:10:22
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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 14 de Octubre de 2007, 11:44:43
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:

Código: [Seleccionar]
#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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 14 de Octubre de 2007, 12:20:29
Hola :lol: ,bueno lo del promedio me parece interesante por lo menos ahora no oscila tanto,aunque da lecturas algo erroneas.
Código: [Seleccionar]
#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);
         }
      }   
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 14 de Octubre de 2007, 12:27:43
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.
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 14 de Octubre de 2007, 12:47:02
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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 14 de Octubre de 2007, 12:56:42
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!!
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 14 de Octubre de 2007, 15:11:34
Cuantos más radios dibujes menor error. Lo normal es poner 4.
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 15 de Octubre de 2007, 13:48:03
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:

Código: [Seleccionar]
#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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 15 de Octubre de 2007, 14:31:12
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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: jfh900 en 15 de Octubre de 2007, 14:37:25
Hola pocher, si me permites una pequeña sugerencia, podrias modificar el código que pusiste:

Código: [Seleccionar]
main()
{
   int8 radios=4;                                 //Encoder de 4 radios
   float n;
   int16 pulsos;
   int8 cuenta_interrupciones;
   int16 velocidad_s,velocidad_m;  

Por:

Código: [Seleccionar]

#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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: pocher en 15 de Octubre de 2007, 15:46:26
oido cocina, marchando una de #define
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: Trev_11 en 18 de Octubre de 2007, 17:42:29
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:

Código: [Seleccionar]
#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);
}
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: criscol64 en 18 de Noviembre de 2008, 19:37:47
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
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: cago41 en 14 de Diciembre de 2008, 21:47:50
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!
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: elmumoperalta en 02 de Diciembre de 2011, 00:53:42
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();
  }
}
Título: Re: Tomando pulsos del Timer1:velocimetro
Publicado por: reiniertl en 26 de Diciembre de 2011, 14:06:28
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