TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: kidpic en 24 de Enero de 2010, 21:03:43
-
Muchachos necesito incorporar en un while(true) de una lectura del rtc lo siguiente:
el incremento de una variable hasta 60 ( seran segundos que recibira del rtc)y que produzca una interrupcion
para ello leo un pin del puerto b (B1) que es por donde van a ingresar los pulsos
int pulsos=0; // inicio el contador lo defino
if (input(pin_b1==1)) // leo el puerto
{pulsos++ // incremento
if(pulsos==60) ///aca tendria que producirse una interrupcion
}
cuando se produzca la interrupcion atendera una funcion de grabado en memoria externa .
La pregunta es: como configuro la interrupcion en este if y en la funcion a la que llamo
gracias!!!
-
Generar una interrupción? Lo que tienes que hacer es al llegar a 60 llamar a una función que haga lo que tenga que hacer. Y debes agregar un while(pin_b1==1); para que espere a que ocurra el flanco descendente, sino contará de forma errónea.
Saludos!
-
Lo que sucede suky que se va a meter en ese bucle hasta contar 60. y despues llama a la funcion. durante ese tiempo muerto no voy a ver los segundos del reloj en el lcd por eso queria ver lo de la interrupcion
-
Configura el Timer0 como contador de pulsos externos, precarga el timer0 con el valor (256-60) y conecta lo que esta ahora en RB1 al pin de entrada del Timer0(¿RA4?).
Habilita la interrupciones pertinentes, y deberia interrumir el timer0 cuando recibas 60 pulsos.
-
Lo que sucede suky que se va a meter en ese bucle hasta contar 60. y despues llama a la funcion. durante ese tiempo muerto no voy a ver los segundos del reloj en el lcd por eso queria ver lo de la interrupcion
jejeje! Claro, tienes toda la razón, lo que queda es hacer lo que indica Bruno, pero dependiendo del timer tiene su pin especifico para recibir los pulsos. Cuando ocurra una interrupción al recibir los 60 pulsos, activa una bandera para tratarla en el bucle principal, no es recomendable hacer demasiadas tareas en una rutina de servicio de interrupción.
Saludos!
-
Incorporo a mi programa pricipal estas lineas de configuracion del timer0 y una atencion de interrupcion:
El código del ejemplo será el siguiente:
#include <16F877A.h>
#fuses XT,NOWDT
#use delay(clock=4000000)
-------
------
-------
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_4); // configuro el timer como contador
enable_interrupts(INT_TIMER0); // habilito el int
enable_interrupts(GLOBAL);
set_TIMER0(0xF1); //inicializa el timer0
//el bucle infinito es necesario ya que si el micro entra en sleep
//desactiva la interrupción del TMR0
//configuro puerto B PinB0 como salida
bit_clear(option_reg,7); // habilitacion de pull-up
bit_clear(trisb,0); // B0 como salida
bit_clear(portb,0); // apago señalizacion
void TIMER0_isr(void) //function interrupción TMR0
{
bit_set(portb,0); //enciendo led
delay_ms (100); // retardo
bit_clear(portb,0); //apago led
set_TIMER0(0xF1); //inicializa el timer
}
Cuando compilo me da los siguientes errores
Executing: "C:\Archivos de programa\PICC\Ccsc.exe" +FM "final.c" +DF +LN +T +A +M +Z +Y=9 +EA
>>> Warning 203 "C:\ARCHIV~1\PICC\drivers\ds1307.c" Line 233(1,1): Condition always TRUE
*** Error 51 "final.c" Line 144(1,5): A numeric expression must appear here
*** Error 51 "final.c" Line 157(1,5): A numeric expression must appear here
*** Error 79 "final.c" Line 197(2,3): Expect }
3 Errors, 1 Warnings.
estoy cometiendo algun error en las lineas agrgadas a mi programa???
Gracias!!!!
-
Saludos
Tienes que tener en cuenta que la interrupción se ejecuta a penas ocurre la causa de interrupción y sale de void o de la función que se esta ejecutando para atender la interrupción "valaga la redudancia :D :D" .
Además debes tener la directiva adecuada para desborde del timer 0 la directiva es la siguiente #int_rtcc por ejmplo ha ocurrido un desborde por el timer 0 entonces como debes hacer la rutina
#int_rtcc
void TIMER0_isr(void) //function interrupción TMR0
{
bit_set(portb,0); //enciendo led
delay_ms (100); // retardo
bit_clear(portb,0); //apago led
set_TIMER0(0xF1); //inicializa el timer
}
Seria bueno que publicaras todo el código ;-).
Que es lo único diferente es la directiva de interrupción que indica que lo que sigue es la atención por desborde del timer0, debes tener en cuenta que el compilador limpia la banderas pero es obligación del programador configurar adecuadamente el micro.
-
incorporo esa directiva pero sigo con los errores: he aqui el codigo
coloco #int_rtcc ò #int_timer0
//////////////////////////////////////////////////////////////////////////////////
#include <16f887.h> //pic a utilizar
#device *=16 ADC=10;
#fuses XT,NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use fast_io(B)
#use rs232(baud=9600,parity=N, xmit=PIN_C6, rcv=PIN_C7,bits=8,) //manejo del RS232
#include <24256.c> //libreria eeprom 24LC256
#include <lcdflex.c>
#include <STDLIB.H>
#include <ds1307.c>
#byte trisb=0x86
#byte portb=0x06
#byte option_reg=0x81
////////////////////DECLARACION DE VARIABLES GLOBALES
long i;
int dir=0;
boolean menu; //si menu=0 se muestra el menu de inicio...
//void rs232 (void);
int temp=0;
int adress1=0;
float const resoluc=5.0/1024.0;
unsigned int16 rref=0;
long value=0;
float vref=0;
float tvolt=0;
int min,hr,sec,day,mth,year,dow;
//////////////////// FUNCION INTERRUPCION///////////////////////////////
#int_rda
void rs232()
{
char digito; //...variables
digito=getc( ); //almaceno dato serial(rs232) en digito
puts("****************************************************" );
switch(digito){
case '0':
menu=!menu; //muestra menu
break;
//case '1': puts("opcion 1 ");
// puts("Configurando Reloj" ); //llena memoria 0xff
// puts(" Configurado!" );
// break;
case '2':
lcd_gotoxy(1,1);
printf(lcd_putc,"enviando datos ",);
adress1=0;
for(i=0; i<=0x7fff;i++)
{
printf("Byte %lu=%2u\n\r",i,read_ext_eeprom(adress1++));
}
puts ("fin de lectura");
break;
case '3':
setup_adc(ADC_CLOCK_INTERNAL);
set_tris_a(0xff);
lcd_init();
delay_ms(6);
while(TRUE)
{
//configuro puerto B PinB0 como salida
bit_clear(option_reg,7); // habilitacion de pull-up
bit_clear(trisb,0); // B0 como salida
bit_clear(portb,0); // apago señalizacion
//configuro conversor para lectura analogica
setup_adc_ports( 0x0000); //configuro al conversor entre VSS y VDD
set_adc_channel(3); //para leer el canal 3
rref=read_adc();
setup_adc_ports(0x1000);//configuro al conversor entre vss y vref
set_adc_channel(4); //para leer el canal 4 del sensor
// configuro rtc
ds1307_init(DS1307_ALL_DISABLED);
ds1307_init(DS1307_OUT_ENABLED | DS1307_OUT_1_HZ);
ds1307_set_date_time(day,mth,year,dow,hr,min,sec);
ds1307_set_date_time(23,01,10,4,18,10,0);
while(TRUE)
{
value=read_adc();
//calculos
vref=rref*resoluc;
//tvolt=valor*resoluc;
tvolt=value*vref/1024;
temp=(tvolt*1000-500)/10;
/////////////////se lee rtc
delay_ms(10);
ds1307_get_date(day,mth,year,dow); /// se obtiene la fecha
ds1307_get_time(hr,min,sec); /// se obtiene la hora
//////////////escribo las variables en la ext eprom
write_ext_eeprom (dir++,value);
write_ext_eeprom (dir++,(value>>8));
write_ext_eeprom (dir++,hr);
write_ext_eeprom (dir++,min);
write_ext_eeprom (dir++,day);
write_ext_eeprom (dir++,mth);
///////////////////////////////visualizacion
delay_ms(100);
lcd_gotoxy(1,1);
printf(lcd_putc,"%02d/%02d/%02d ",day,mth,year);// por lcd fecha
//printf(lcd_putc,"vref:%2.1f ",vref);
lcd_gotoxy(11,1);
printf(lcd_putc,"uv:");
lcd_gotoxy(1,2);
//printf(lcd_putc,"tvolt: %f ",tvolt);
printf(lcd_putc,"%02d:%02d:%02d ",hr,min,sec); // por lcd hora
lcd_gotoxy(11,2);
printf(lcd_putc,"T: %2.0d ",temp);
printf("%2.0d \n\r",temp);// A la pc hiperterminal
//printf("%2.0lu\n\r",value);
if(dir==0x7fff) dir=0;
}
}
break;
// funcion de la interrupcion
#int_timer0 //la siguiente función tiene que ser la de interrupción del TMR0
void timer0_isr(void) //function interrupción TMR0
{
bit_set(portb,0); //enciendo led
delay_ms (100); // retardo
bit_clear(portb,0); //apagp led
set_TIMER0(0xF1); //inicializa el timer
}
///////////////////////////////////PROGRAMA PRINCIPAL///////////////////////
void main(void)
{
//configuro interrupcion por tmr0
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_4);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
set_TIMER0(0xF1); //inicializa el timer0
//el bucle infinito es necesario ya que si el micro entra en sleep
//desactiva la interrupción del TMR0
lcd_init();
delay_ms(6);
lcd_gotoxy(1,1);
printf(lcd_putc,"select menu PC",);
disable_interrupts (global);
enable_interrupts(int_rda); //activo interrupcion serial rs-232
enable_interrupts(global); //habilito la interrupcion
// init_ext_eeprom( );
do{ //bucle...
puts(" ");
puts("Lectura/Escritura de EEPROM 24LC256");
puts("==============================================" );
puts("Seleccione opcion:" );
puts("-------------------------------------" );
puts(" 0->Ver opciones" );
//puts(" 1->Configurar reloj" );
puts(" 2->Lectura EEPROM" );
puts(" 3->Sensado y Escritura de variable" );
//puts(" 4->Escritura en EEPROM" ); //...principal
menu=1; //muestra menu solamente una vez
while(menu==1){ } //espera tecla pulsada por teclado(rs-232)
} while(TRUE); //...infinito
}
-
Saludos.
En la interrupción #int_rda veo un problema creo que te falta una o dos llave por cerrar que es la del inicio al final en el break y otra la del while(true) ya que tienes dos while(true) y uno lo cierras y el otro no.
-
Bien, ahora si. veremos como anda en el hard.
si hace lo que tiene hacer.
Gracias
-
Cuando programo el timer0 como contador. va a recibir los pulsos por el RA4, lo tengo que programar como entrada a este PIn o ya esta por defeto en la configuracion del timer0
Gracias
-
Configuralo como entrada
-
Saludos. Cual era el problema kidpic del código?
-
faltaba cerrar las llaves. Ahora no rsponde a la interrucion. probarè de configurar al ra4 como entrada.
Gracias.
-
Por ahi lo que te esta pasando, es que tenes RA4 configurada como analogica. Asegurate de configurar todos los pines que no necesites con analógicos como digitales para poder usarlos sin problemas.
Saludos.
-
Saludos
Por que no intentas lo siguiente setup_timer_0(xxxx) por lo siguiente setup_counters(xxxxx) te puede servir.
-
sigue sin responder a la interrupcion. estas son las lineas que agregue y se compilan bien . Pruebo con counters y sigue igual.
#byte trisA=0x85
#byte portA=0x05
#byte option_reg=0x81
//atencion de la interrupcion
#int_timer0 //la siguiente función tiene que ser la de interrupción del TMR0
void timer0_isr(void) //function interrupción TMR0
{
write_ext_eeprom (dir++,value);
write_ext_eeprom (dir++,(value>>8));
write_ext_eeprom (dir++,hr);
write_ext_eeprom (dir++,min);
write_ext_eeprom (dir++,day);
write_ext_eeprom (dir++,mth);
set_timer0(0xF1); //inicializa el timer
}
//configuro interrupcion por tmr0
setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_4);
enable_interrupts(GLOBAL);
set_TIMER0(0xF1); //inicializa el timer0
//configuro puerto A PinA4 como entrada
bit_clear(option_reg,7); // habilitacion de pull-up
bit_set(trisA,4); // A4 como entrada
-
Saludos
A mi funciona debes estás configurando mal algo o debes estar simulando mal para que tengas encuenta lo siguiente:
Como estás configurando con un prescaler de 1:4 debes esperar 64 pulsos en TOCK1 y no 16 además intentaste configurar el timer con la siguiente línea.
setup_counters(RTCC_EXT_L_TO_H , RTCC_DIV_4); espero que te funcione.
-
Bueno si te funciona a vos es una alegria estoy haciendo algo mal yoó. No lo estoy simulando pero si tengo el proteus. (no se como incorporar este programa al proteus) Lo que me importa que esta funcionando la llamada a interrupcion.
Lo estoy probando con el hard directamebte trabajo con pickit2 y no obtengo resultados positivos.
Np entiendo lo de los 16 o 64, aparte reemplazo la linea de configuracion por la que me decis y aparece este error
EXPECT COMMA (en esa linea)
-
Chenao , me podrias pasar el archivo para correrlo con el proteus.
Gracias
-
Saludos
Con respecto a lo del prescaler debes tener varias cosas en cuenta pero mejor vamos a explicarlo en tu código tienes la siguiente instrucción SET_TIMER0(0xF1) que en décimal es 241 ahora tenemos que cada 15 pulsos se va desbordad el timer0 hasta aqui todo bien lo básico pero después estas configurando el timer externo y además con un predivisor de frecuencia que es 1: 4 acá va el chiste como estás trabajando timer0 con pulso externo en TOCK1 esté se convierte en el reloj y como tienes un predivisor 1:4 pues cada 4 pulso se incrementa el timer0 entonces para que cuente de 241 hasta 256 necesita 15*4 = 60 acá tuve un problema con el cálculo por que lo hice algo afanado.
Con respecto al la línea de código no estás copiando bien la instrucción ya que no estás poniendo la coma como aquí se muestra.
setup_counters(RTCC_EXT_L_TO_H , RTCC_DIV_4); "la coma está en la mitad del parentisis"
Acá adjunto la simulación esta hecha en el proteus versión 7.2 espero que te sirva.
-
gracias chenao. me surge una duda :yo necesito que desborde e interrumpa cada 60 pulsos con una frecuencia de 1hz que estaran entrado por el ra4.
lo cargo al timer con ese numero porque lo calcule con esta formula.
inter_tmr0 =(1/frecuencia del clock externo)X(256- valor del tmr0)Xprescaler
inter_tmr0 = es el tiempo en que se produce la interrupcion que sera igual a 60
frecuebcia del cclk externo = 1hz
prescaler=4
valor del tmr0 =es lo que despejo y me da 0XF1
puede que no este usando la formula correcta. si no es asi que calculo tendria que hacer para evitar lo que dices vos. örque no puedo modificar la frec de entrada
-
Me parece que estas entendiendo algo mal.
Deberias configurar el timer 0 como contador de pulsos externo. No necesitas hacer ningun calculo de tiempos con el Timer0 porque la idea es que lo uses como contador de pulsos, no contador de ciclos de reloj del uC.
Si el preescaler es 1:2 entonces vas a tener que precargar al timer0 con el valor 256-60/2= 226.
Por favor, lee cuidadosamente el funcionamiento del Timer0 en el datasheet.
Saludos.
-
saque informacion de este documento, te paso el link para que te fijes. Tal vez estoy errado en mi interpretacion
http://www.aquihayapuntes.com/indice-practicas-pic-en-c/uso-del-tmr0-como-contador.html
-
Estas interpretando mal, porque como bien dice Bruno debes entender que lo estas configurando como contador, entonces no necesitas saber que frecuencia tiene el clock externo, sino al saber que necesitas recibir 60 pulsos realizas el calculo como se te muestra (Pre-cargar con 226)
Saludos!
-
Saludos
Como dice el compañero Bruno ahora el timer no está contando por cada ciclo de reloj si no que está contando cada vez que hay un pulso externo en TOCK1 para tu caso cada 4 Hz (por el prescalador) de todas manera consulta el datasheet ahy explican detalladamente está configuración.
-
Gracias muchachos, que confusion!!.
En limpio: con un prescaler de 4 y cuando entren 60 pulsos externos ( que vienen de un ds1307) cual es valor de carga del timer0??
de acuerdo a lo que uds. ddicen sera (256 -60/4)= 241. Confirmelo por favor !!!
Entonces no tengo que tener en cuenta esta formula
inter_tmr0 =(1/frecuencia del clock externo)X(256- valor del tmr0)Xprescaler
GRacias, donde consigo el datasheet?????
-
Saludos
Si es correcto el cálculo. No tienes que tener en cuenta la fórmula impirica del timer0. el datasheet lo consigues en la página de microship (creo que así se escribe) o si no preguntale al google.
-
saludos Chenau, haciendo cuentas el 241 tambien lo obtengo de esta formula despejando el "valor de timer0"
inter_tmr0 =(1/frecuencia del clock externo)X(256- valor del tmr0)Xprescaler
despues de todo sigo sin respuesta requerida de la interrupcion.
tal vez el trabajar con una interrupcion dentro de otra provoca algun conflicto en este codigo.
-
Saludos
Por supuesto es el valor que estas cargando con la instrucción set_timer0(xxxx) en esté caso xxxx es 241 pero lo que cambia es la forma como el timer se incrementa ya no se incrementa por cada 4 ciclos de reloj (1:4) si no cada 4 pulso en RA4 (TOCK1) es la diferencia entre la configuración contador y la configuración timer. No has consultado el datasheet?
Si no estás resiviendo respuesta de interrupción te recomiendo que pruebes tu código por parte para identificar donde puede estás el error.
-
No, no...
No es para nada recomendable trabajar con una interrupcion dentro de otra. ademas cuando ocurre una interupcion, el bit de interrupcion global INTCON,GIE es deshabilitado automaticamente por lo que se va a producir otra interrpcion si ya estas dentro de una.
-
saludos Chenau, haciendo cuentas el 241 tambien lo obtengo de esta formula despejando el "valor de timer0"
inter_tmr0 =(1/frecuencia del clock externo)X(256- valor del tmr0)Xprescaler
No podés justificar que una ecuación sea la correcta porque funciona para un caso en particular(para freq=1Hz). Una ecuación es una LEY y se supone que representa a un conjunto de valores de entrada.
Cuando el Timer0 es configurado como contador de pulsos externos, NO IMPORTA la frecuencia de entrada. El Timer0 cuenta cada vez que ocurre un cambio de flanco alto/bajo(segun la configuracion si mal no recuerdo) en T0CKI. Si no llega ese cambio de flanco, ni el registro Tmr0 ni su preescaler van a incrementarse.Pueden pasar segundos, minutos, horas y todo el tiempo que el uC esté encendido, que el Tmr0, bajo esa configuracion no va a incrementarse.
Es evidente que la ecuacion que representa este comportamiento NO depende del tiempo, por lo tanto tampoco de una frecuencia, que es una medida asociada y ligada al tiempo.
-
GRacias, donde consigo el datasheet?????
En www.microchip.com
Saludos!
-
La entrada por RA4 (de los pulsos externos) tienen que conectarse a una resistencia y Vcc ( es pull-up)
gracias
-
No. Eso solo hace falta si pensas usar RA4 como SALIDA. Como entrada no tiene ningun requisito adicional. Solo asegurate de que este configurada como digital.
-
cuando te referis a la configuracion digital .....esto es lo que tengo configurado
#byte trisA=0x85
#byte portA=0x05
#byte option_reg=0x81
-------
--------
---------
bit_clear(option_reg,7); // habilitacion de pull-up
bit_set(trisA,4); // RA4 como entrada
set_tris_a(0xff); // aca pongo como entrada todo el puerto es algo redundante puede ir esto o la linea anterior solo para el RA4
gracias .........ya llevo 3 dias con este codigo.........
Esta funcionando solo que no me responde a la interrupcion en otro lugar esa rutina dentro de un while me funciona
gracias por las sugerencias
-
No. Es un error mio. Justo RA4 no es analogica. Perdona.
Publica el codigo entero y vemos.
-
Justamente BRUNOF. la RA4 es la entrada de los pulsos y creo que así la configuro como digital. O estoy en un error
aqui va el archivo
-
solucionado los problemas.
Gracias por los aportes. A seguir avanzando