TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: perry en 02 de Marzo de 2007, 07:28:56
-
Hollllaaaaaa!!!!!!!
Estoy haciendo un programa que recibe pulsos por RB0, utilizando el timer1 y visualizo la frecuencia por un lcd. Os pego el programa:
#include <18f4550.h>
#fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,BROWNOUT,NOPBADEN,NOLVP,NOCPD,DEBUG
#use delay(clock=20000000)
#use fast_io(B)
#include "lcd.c"
float const uSxTick = 0.2; // Microsegundos por Tick de TMR1 a 20 Mhz
///////////////////////////////////////////////////////////////////////////
// variables a guardar //
///////////////////////////////////////////////////////////////////////////
long t1;
long tt;
float st1;
float st_tot_overflow;
float f;
float f_final;
int n_overflow;
long t_tot_overflow;
long alarma_max=150;
long alarma_min=0;
long frecuencia();
/////////////////////////////////////////////////////////////////////////
//
// Interrupción por externa por cambio de flanco en RB0 //
//
/////////////////////////////////////////////////////////////////////////
#int_ext
void handle_ext_int()
{
t1=get_timer1();
set_timer1(0);
n_overflow=0;
output_high (PIN_A0);
delay_ms(200);
output_low (PIN_A0);
}
#int_timer1
void overflow()
{
++n_overflow;
}
void main ()
{
/////////////////////////////////////////////////inicializaciones generales///
delay_ms(333); // Espero a que todo se estabilice e ...
disable_interrupts(global); // Inicializo el Micro y ...
disable_interrupts(int_timer1); // deshabilitando todo lo no necesario ...
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_0(RTCC_OFF);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(FALSE);
delay_ms(333);
/////////////////////////////////////////////////////////////////////////
set_tris_b(0xFF);
lcd_init();
Delay_ms(1000);
lcd_putc("\f");
lcd_putc(" pulsometro \n");
Delay_ms (1000);
ext_int_edge(0,L_to_H);
enable_interrupts(int_ext); // Habilito las interrupciones necesarias
enable_interrupts(int_timer1);
clear_interrupt(int_ext);
clear_interrupt(int_timer1);
enable_interrupts(global);
while (true)
{
lcd_putc("\f");
lcd_gotoxy (2,10);
printf(lcd_putc,"%5.2f \n",f_final);
delay_ms (1000);
}
}
////////////////////////////////////////////////////////////////////////////////
//
// funciones
//
////////////////////////////////////////////////////////////////////////////////////
long frecuencia ()
{
st1 = uSxTick * t1; // calculo el tiempo en microsegundos
t_tot_overflow = (((2^16)-1) * n_overflow); // ticks de todos los overflow
st_tot_overflow = (t_tot_overflow * uSxTick); //tiempo overflows
tt = st_tot_overflow + st1; //tiempo total
f = 1 / (tt * 1000000); // frecuencia
f_final = f * 60;
return (f_final);
}
La interrupción del salto salta porque el led de A1 se enciende cada vez que llega un pulso pero no consigo visualizar en el display el tiempo, ya que sólo veo 0.00.
He estado mirando unos ejemplos de la pagina de redpic pero no encuentro el fallo que tengo. ¿me podeis echar un cable?
muchas gracias. No sabeis lo que me está ayudando este foro para ir haciendo mis programillas porque hace unas semanas no sabía ni lo que era el c :-/
-
Me he olvidado d llamar a la funcion frecuencia pero aún así no consigo ver nada
#include <18f4550.h>
#fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,BROWNOUT,NOPBADEN,NOLVP,NOCPD,DEBUG
#use delay(clock=20000000)
#use fast_io(B)
#include "lcd.c"
float const uSxTick = 0.2; // Microsegundos por Tick de TMR1 a 20 Mhz
///////////////////////////////////////////////////////////////////////////
// variables a guardar //
///////////////////////////////////////////////////////////////////////////
long t1;
long tt;
float st1;
float st_tot_overflow;
float f;
float f_final;
int n_overflow;
long t_tot_overflow;
long alarma_max=150;
long alarma_min=0;
long frecuencia();
/////////////////////////////////////////////////////////////////////////
//
// Interrupción por externa por cambio de flanco en RB0 //
//
/////////////////////////////////////////////////////////////////////////
#int_ext
void handle_ext_int()
{
t1=get_timer1();
set_timer1(0);
n_overflow=0;
output_high (PIN_A0);
delay_ms(200);
output_low (PIN_A0);
}
#int_timer1
void overflow()
{
++n_overflow;
}
void main ()
{
/////////////////////////////////////////////////inicializaciones generales///
delay_ms(333); // Espero a que todo se estabilice e ...
disable_interrupts(global); // Inicializo el Micro y ...
disable_interrupts(int_timer1); // deshabilitando todo lo no necesario ...
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_0(RTCC_OFF);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(FALSE);
delay_ms(333);
/////////////////////////////////////////////////////////////////////////
set_tris_b(0xFF);
lcd_init();
Delay_ms(1000);
lcd_putc("\f");
lcd_putc(" pulsometro \n");
Delay_ms (1000);
ext_int_edge(0,L_to_H);
enable_interrupts(int_ext); // Habilito las interrupciones necesarias
enable_interrupts(int_timer1);
clear_interrupt(int_ext);
clear_interrupt(int_timer1);
enable_interrupts(global);
while (true)
{
lcd_putc("\f");
frecuencia();
lcd_putc("\f");
lcd_gotoxy (2,10);
printf(lcd_putc,"%5.2f \n",f_final);
delay_ms (1000);
}
}
////////////////////////////////////////////////////////////////////////////////
//
// funciones
//
////////////////////////////////////////////////////////////////////////////////////
long frecuencia ()
{
st1 = uSxTick * t1; // calculo el tiempo en microsegundos
t_tot_overflow = (((2^16)-1) * n_overflow); // ticks de todos los overflow
st_tot_overflow = (t_tot_overflow * uSxTick); //tiempo overflows
tt = st_tot_overflow + st1; //tiempo total
f = 1 / (tt * 1000000); // frecuencia
f_final = f * 60;
return (f_final);
}
-
Prueba a quitar el delay_ms(200) de la función de interrupción de RB0. Para hacer el efecto de encender y apagar el led puedes usar el timer0 y así evitas usar delays en medio de una interrupción.
Saludos!!
-
Me parece que estás tratando de hacer un frecuencímetro. Si esa es tu aplicación creo que lo mejor será que utilices los contadores del uC, en el foro hay información de como hacer un frecuencímetro.
El uso de INT/EXT te puede servir pero si esa es tu aplicación no me parece la solución más lógica.
Un saludo Reinier
-
Buenas... Aprovechando el post de perry, aprovecho para hacer una consulta sobre el timer1, la aplicacion es simple, con un pic16f873, programado en ccs, a 4 mhz.
El programa (que luego escribo), espera una interrupcion externa a travez de rb0, en ese momento pone a cero el timer1, luego en el main(), lee el timer1, y lo compara con el resultado de una conversion AD de 10 bits, cuando el timer1 es igual o mayor al valor de la conversion AD, se ejecuta algo, hasta aca todo bien, el problema es que cuando hago esto, teniendo constante el valor del AD, el timer1 no se dispara siempre en el mismo valor...
Cual es la idea... simplemente comparar 2 valores de 16bits, uno generado por el AD (10bits) y otro generado por el timer1, esto me da un pulso del ancho que yo quiera (regulado por el AD).
Lo raro de esto es que si hago exactamente lo mismo, pero con el timer0 y el ad a 8 bits, si funciona a la perfeccion.
Les dejo el codigo.. y desde ya gracias.
Alejandro.
#include <16f873.h> // Definiciones del PIC 16F873
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT //
#use delay(clock=4000000) // Oscilador a 4 Mhz
#pragma use fast_io(A)
#pragma use fast_io(B)
#pragma use fast_io(C)
// PINES /////////////////////////////////////////////////////////////////
#define pLed1 PIN_A1
#define pLed2 PIN_A2
#define pLed3 PIN_A3
#define pLed4 PIN_A4
#define pSensor1 PIN_B7 //sensor de botella 1
#define pSensor2 PIN_B6 //sensor de botella 2
#define pContactor PIN_B5
#define pTanque PIN_B4
#define pPico2 PIN_B3
#define pPico1 PIN_B2
#define pMang2 PIN_B1
#define pMang1 PIN_B0
#define pEV1 PIN_C4 //Electrovalvula botella 1
#define pEV2 PIN_C5 //Electrovalvula botella 1
#define pE_lcd PIN_D0 //sensor de botella 2
// VARIABLES EN RAM ///////////////////////////////////////////////////////////
int1 f1_seg; // Flag de un segundo
int1 fcruce0;
int rTimer1; // Tiempo de encendido V1
int rTemp;
int rPulsos; //
int rTimeOff_V2; //
int1 prevIn1; //
int1 prevIn2; //
INT rDelay; //
int rLeds; // Imagen de los leds
// Declaración de Funciones ///////////////////////////////////////////////////
// INTERRUPCIONES /////////////////////////////////////////////////////////////
}
#int_RTCC
void RTCC_isr() { // Interrupción Timer 0
rDelay++;
}
#int_TIMER1
void T1_isr() { // Interrupción Timer 1
IF(input(PIN_B7))
output_low(PIN_B7);
ELSE
OUTPUT_HIGH(PIN_B7);
}
#INT_EXT
void ext_isr(){
if(input(PIN_B0)){
ext_int_edge(H_TO_L);
fcruce0=1;
}
ELSE{
ext_int_edge(L_TO_H);
fcruce0=1;
}
set_timer1(0);
}
#INT_TIMER2 //Interrupcion por timer 2
void TIMER2_isr() { //cada 1ms para control de tiempo
}
// Desarrollo de Funciones ////////////////////////////////////////////////////
//,,,,,,,,,,,,Programa Principal /////////////////////////////////////////////////////////
void main() {
//++++++++++++++++++Configura puertos analogicos++++++++++++++++++++++++++++++
setup_adc( ADC_CLOCK_INTERNAL );
setup_adc_ports( RA0_ANALOG ); // Ver que puertos van a ser analogicos
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
setup_timer_1(T1_INTERNAL|T1_DIV_8);
set_tris_a (0b00000011);
set_tris_b (0b00000001);
set_tris_c (0b11000000);
rDelay = 0;
rLeds = 1;
ext_int_edge(H_TO_L); //selecciono interrupcion por flanco descendente
//enable_interrupts(int_RTCC); // Habilita Interrupción TIMER0
enable_interrupts(int_ext); // Habilita Interrupción RB0
//enable_interrupts(int_TIMER1); // Habilita Interrupción TIMER1
// enable_interrupts(int_TIMER2); // Habilita Interrupción TIMER2
enable_interrupts(global); // Habilita interrupciones
output_b(0);
do {
rTimer1=get_timer1();
if(fcruce0){ // Si hay disparo pendiente
if(rTimer1>=rTemp){
fcruce0=0;
do {
output_high(PIN_C4);
delay_us(10);
output_low(PIN_C4);
delay_us(10);
}while(rPulsos++<20);
rPulsos=0;
rTemp=read_adc();
}
}
} while (TRUE);
}
-
Yo quitaría de la interrupción externa ese delay_ms(200) que lo único que hace es impedir que se recoja el siguiente pulso.
Para calcular la frecuencia estás dividiendo por 1.000.000 que imagino será una estimación del tiempo que tarda tu aplicación en volver a calcularla, por el delay_ms del bucle principal. Creo que es un método bastante inexacto; te recomiendo utilizar un segundo timer para establecer los periodos de recuento.
No obstante, creo que la mejor forma de hacer el frecuencímetro es otra, utilizando sólo dos timers y no la interrupción externa:
- configuras un Timer para que salte cada X tiempo fijo, por ejemplo, cada 10ms.
- configuras el otro timer para que cuente pulsos externos
- cada 10ms lees los pulsos que han entrado y multiplicas por 100, esos serán los pulsos de un segundo.