Autor Tema: Serie Técnicas en C : Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB  (Leído 5818 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5416
    • Picmania by Redraven
Y por fin le damos una vuelta de tuerca al Tema de Capturar el ancho de un pulso ...

Por indicación del amigo filth ampliamos lo que hemos visto en Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT y en Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP.

En ambas hemos utilizado la técnica de recoger el valor de TMR1 cuando ocurre o la interrupción externa por RB0 o la interrupcion CCP, sea en el flanco de caída, sea en el de subida. Con los valores de ambos flancos y simplemente restando el uno del otro tenemos el valor del ancho del pulso.

Hay otra manera de hacer exactamente lo mismo utilizando una tercera fuente de interrupción de los PIC's: Utilizando la intetrrupción por cambio de estado de RB04:7

A.- Conceptos involucrados:

Los conceptos son exactamente los mismos que los descritos en las parte anteriores por lo que os ruego que  consultéis si os es necesario: Midiendo un pulso. 1ª Parte y/o 2ª Parte.

B.- Técnica a Aplicar:

La interrupción por Cambio de Estado de los pines 4 a 7 del PORTB es una interrupción muy socorrida aunque algo falta de precisición. No dispone como en nuestros anteriores ejemplos INTEXT e INTCCP de la posibilidad de pre-programar el flanco que deseamos que dispare la Petición de Servicio de Interrupción (ISR).

Aunque esta interrupción, a la que a partir de aquí llamaremos INTRB, afecta en principio a los bits desde el 4 hasta el 7 del PORTB, solo lo hará efectivamente a aquellos que esten configurados como de entrada, que hayamos programado con el TRIS a 1.

Al dispararse la interrupción solo sabemos que uno o mas de estos pines ha cambiado de estado. Nada mas, ni nada menos.

Por ello es imprescindible al usar INTRB que vayamos recogiendo sobre una variable estática de un byte los cambios sucesivos que se van produciendo para poder comparar en el momento de recibir la interrupción el estado actual del PORTB con el inmediatamente anterior.

Así si el bit correspondiente al pin que estamos utilizando para nuestra medición del pulso es igual en el estado actual que en el anterior no tenemos cambio en el pulso y además no ha sido éste pin el responsable de disparar la interrupción.

Si el estado anterior era bajo y el actual es alto estamos ante el flanco de subida de nuestro pulso y además es él quien ha producido el disparo de la interrupción.

Si por el contrario el estado anterior del pin era alto y ahora es bajo entonces acabamos de detectar el flanco de bajada de nuestro pulso, y por supuesto también ha sido él el responsable de disparar la interrupción INTRB.

Con esta información realizaremos exactamente igual que en los ejemplos anteriores: guardamos el valor de TMR1 tras el flanco de subida y tras el de bajada, realizamos la correspondiente resta entre ambos valores y transmitimos los resultados.

C.- Implementación en C:

Para configurar inicialmente nuestra interrupción INTRB debemos hacer que nuestro pin, en este caso el 4, sea de entrada, y habilitaremos las interrupciones necesarias con:

Código: C
  1.    set_tris_b(0b00010000);                  // Habilito como entrada RB7 para interrupción RB
  2.    enable_interrupts(int_rb);
  3.    enable_interrupts(global);
  4.  

Nuestra rutina ISR para INTRB quedaría como sigue:

Código: C
  1. int  estado_portb_anterior=0;
  2. int  estado_portb_actual=0;
  3.  
  4. ...
  5.  
  6. #int_rb
  7. void handle_rb_int(){
  8.  
  9.    estado_portb_actual=input_b();
  10.    if ((!bit_test(estado_portb_anterior,4))&&(bit_test(estado_portb_actual,4)))
  11.    {
  12.      hay_flanco_de_bajada=0;
  13.    }
  14.  
  15.    if(hay_flanco_de_bajada!=0){             // He recibido Flanco de Subida
  16.       t1=get_timer1();                      // Guardo en t1 el valor de TMR1 al Flanco de Subida
  17.    } else {                                 // He recibido Flanco de Bajada
  18.       t2=get_timer1();                      // Guardo en t2 el valor de TMR1 al Flanco de Bajada
  19.       set_timer1(0);                        // Reinicio TMR1
  20.       if(flagHayDatos==0){                  // Si los datos anteriores han sido procesados ...
  21.          flagHayDatos=1;                    // Indico que ya hay nuevos datos de flancos para calcular
  22.       }
  23.    }
  24. }
  25.  

El resto de la implementación en C de esta Técnica es identica a la mostrada en Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT  y Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP

Bueno, y esto es todo por hoy amigos.  :)
Mañana, más.




« Última modificación: 24 de Octubre de 2014, 09:56:50 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado pabloavilad

  • PIC10
  • *
  • Mensajes: 6
Re: Serie Técnicas en C : Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB
« Respuesta #1 en: 02 de Abril de 2007, 01:36:40 »
Hola, mi nombre es pablo y escribo desde argentina. Estoy en problemas al necesitar medir anchos de pulso de aproximadamente entre 50 ms y 200 ms. Ya lo intente con el comand count de PIC BASIC pero detiene todas las operaciones del pic (incluyendo el refresco de los displays) para contar pulsos. Me parece bueno hacerlo con interrupciones ya que el resto del tiempo el pic se debe dedicar a multiplezar la informacion en 3 displays de 7 segmentos. En algun otra parte del foro explicaste que "para computar tiempos de pulso mayores 13,1072 milisegundos solo habría que computar tambien cuantas veces se desborada completo TIMER1 y realizar los cálculos aritméticos correspondientes". Lo que necesito es saber como configurar el timer1 para que me avise que debo sumar cada vez que se desborde, es decir como habilitar la ISR del timer. Otra pregunta es si tienes idea si el PIC16f628 posee El TIMER1 y la Interrupción Externa por RB0. Yo tengo este pic y tambien el 16f876 y el 16f877 y estos dos si lo tienen pero el 16¨f628 no lo se. Muchas gracias de antemano si puedes clarificarme el camino. Por el momento estoy aprendiendo tambien como usar proteus porque se me complica probar los circuitos en vivo (lo vengo haciendo porque no me queda alternativa).

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5416
    • Picmania by Redraven
Re: Serie Técnicas en C : Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB
« Respuesta #2 en: 02 de Abril de 2007, 02:26:54 »
El 16F628 si tiene ambos recursos, el TIMER1 de 16 bits y la INTEXT por RB0, así que puedes utilizarlos.

En cuanto al PIC BASIC no puedo ayudarte, he hecho algunas cosas con él pero sólo a nivel de ultra-principiante, ni siquiera llegué a utilizar interrupciones con ese idioma.

Pero en el foro hay grandes conocedores del PIC BASIC y no dudo que te podrán dar una mano para utilizarlo correctamente.

Suerte.
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado lucaspascual

  • PIC10
  • *
  • Mensajes: 31
Re: Serie Técnicas en C : Midiendo un pulso. 3ª Parte. Tiempo en Alto con INTRB
« Respuesta #3 en: 02 de Mayo de 2013, 18:40:27 »
Buenas tardes redpic, estoy haciendo un proyecto para introducir en el pic los datos de un calibre digital, el programa para tomar 8 bits de datos esta hecho, pero ahora cuando quiero visualizarlo en lcd no pasa nada, me parece q es un problema de donde inicializo el lcd, (adentro de la interrupcion o fuera).
Este es el programa.

#include <16f877.h>
#fuses hs,nowdt,put,nowrt,nolvp,noprotect
#use delay(clock=20000000)
#use fast_io(b)
#include <lcd.c>
int8 dato;

#int_ext

ext_isr()
{
 
delay_us(496);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,0);
else
bit_clear(dato,0);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,1);
else
bit_clear(dato,1);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,2);
else
bit_clear(dato,2);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,3);
else
bit_clear(dato,3);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,4);
else
bit_clear(dato,4);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,5);
else
bit_clear(dato,5);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,6);
else
bit_clear(dato,6);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,7);
else
bit_clear(dato,7);
printf(lcd_putc,"\f%u",dato);

}

void main()
{

lcd_init();
set_tris_b(0x03);
output_low(PIN_B7);
port_b_pullups(true);
enable_interrupts(int_ext);
ext_int_edge(l_to_h);
enable_interrupts(global);

while(1)
{
 
}
}


 

anything