Interrupcion externa y conversion ADC no me funcionan juntos CCS

Estoy controlando el ds1307 y midiendo temperatura, utilizo una interrupción externa para configurar el reloj y a la vez mido temperatura. Separados funcionan pero los junto y el ADC no deja que se active la interrupción, que podría ser?

aquí mi código:

C:
#include <18F4550.h>
#device adc=10
#include <stdlib.h>
#fuses NOWDT,NOPROTECT,NOLVP //INTRC_IO
#use delay(clock=8000000)
//#use delay(internal=8000000)
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7,bits=8, parity=N)  //parametros para la comunicación rs232
#use i2c(Master,sda=PIN_c0,scl=PIN_c1,FORCE_SW)       //Configuración I2C por software
#include <lcd.c>



/*************Declaracion de entradas y salidas*************/
#define  boton        pin_b0
#define  led_confi    pin_b7
/***********************************************************/


/*************Declaracion de variables globales*************/
//int flag=0;

char cadena[6];
unsigned int8 segundos,minutos,horas;
unsigned int8 diasS,diasM,meses,anios;

//para la temperatura
int16 q;
float p;
/***********************************************************/



/*************Inicializacion de Funciones*************/
void test_uart(void);
void despliega(void);
void reloj_inicia(void);
void Transforma(void);
void reloj_ingreso(void);

void ds1307_write(unsigned int8 address, int8 data);
void entero_bcd(void);

void temperatura(void);
/*****************************************************/


/*************interrupcion externa presionando boton*************/
#int_EXT
void  EXT_isr(void)
   {

    output_high(led_confi);
    delay_ms(2000);
    output_low(led_confi);
    
    printf("\n\r\n\r Configuracion reloj:");
    
    printf("\n\r año (dos ultimos digitos):");   
    gets(cadena);
    printf("%s",cadena);
    anios=atoi(cadena);

  
    printf("\n\r mes:");
    gets(cadena);
    printf("%s",cadena);
    meses=atoi(cadena);


    printf("\n\r dia:");
    gets(cadena);
    printf("%s",cadena);
    diasM=atoi(cadena);

              
    printf("\n\r hora:");   
    gets(cadena);
    printf("%s",cadena);
    horas=atoi(cadena);

    
    printf("\n\r minuto:");   
    gets(cadena);
    printf("%s",cadena);
    minutos=atoi(cadena);

    
    printf("\n\r segundo:");   
    gets(cadena);
    printf("%s",cadena);
    segundos=atoi(cadena);

  
    //se omite la validacion de datos, porque se asume que la PC mandara los datos correctos
    //se escriben los nuevos datos en el reloj
    entero_bcd();
    reloj_ingreso();
  
   }
/**************************************/


 
/******funcion principal******/
void main()
   { 
   enable_interrupts(GLOBAL);//habilito interrupción global
   enable_interrupts(INT_EXT);//habilito interrupción externa

 
   setup_adc_ports(ALL_ANALOG );     //Canal 0 analógico
   setup_adc(ADC_CLOCK_INTERNAL);    //Fuente de reloj RC
   set_adc_channel(0);           //Habilitación canal0


  
   lcd_init();   
   test_uart();
   reloj_inicia();
  
   while(true)
      {
      temperatura(); //muestrea temperatura
      despliega();   //despliega la hora y fecha
      Delay_ms(1000);
      }

 
   }
/******fin de funcion principal******/



/***********captura temperatura***********/
void temperatura(void)
{
      delay_us(20);
      q = read_adc();                  //Lectura canal 0
      p =q*0.48828125;           //Conversión de temperatura, formula valida para el lm35
}
/***********fin de captura temperatura***********/



/***********test de conexion uart***********/
void test_uart(void)
{
int cont;

for(cont=0;cont<10;cont++)
   {
   delay_ms(1000);
   printf("conectando %d",cont);
   printf("\r\n");
   }
}
/***********fin de test de conexion uart***********/




/***********INICIA RELOJ CON VALORES POR DEFECTO***********/
void reloj_inicia(void)
{
                        //inicia todo en cero
  ds1307_write(0x00,0); //segundos
  ds1307_write(0x01,0); //minutos
  ds1307_write(0x02,0); //horas

  //ds1307_write(0x03,0); //dia de la semana, esto no lo uso de momento
  ds1307_write(0x04,0); //dia del mes
  ds1307_write(0x05,0); //meses
  ds1307_write(0x06,0); //años
  ds1307_write(0x07,0x10); // frecuencia de salida de 1 hertz
 
}
/***********TERMINA RELOJ CON VALORES POR DEFECTO***********/



/***********INGRESA HORA Y FECHA AL RELOJ***********/
void reloj_ingreso(void)
{
 
  ds1307_write(0x00,segundos); //segundos
  ds1307_write(0x01,minutos); //minutos
  ds1307_write(0x02,horas); //horas
  //ds1307_write(0x03,0); //dia de la semana,  esto no lo uso de momento
  ds1307_write(0x04,diasM); //dia del mes
  ds1307_write(0x05,meses); //meses
  ds1307_write(0x06,anios); //años
  ds1307_write(0x07,0x10); // frecuencia de salida de 1 hertz 
 
}
/***********FIN DE INGRESA HORA Y FECHA AL RELOJ***********/


/***********LECTURA DESDE EL RELOJ***********/
void leer_tiempo() {

  i2c_start();               // Issue start signal
  i2c_write(0xD0);           // DIRECCION DEL RELOJ
  i2c_write(0X00);              // INICIA DESDE LA DIRECCION CERO
  i2c_start();               // Issue repeated start signal
  i2c_write(0xD1);           // DIRECCION DEL RELOJ MAS EL BIT DE LECTURA


  segundos = i2c_read(1);     // Read seconds byte
  minutos = i2c_read(1);     // Read minutes byte
  horas = i2c_read(1);       // Read hours byte
  diasS = i2c_read(1);         // Read year/day byte
  diasM = i2c_read(1);         // Read year/day byte
  meses = i2c_read(1);       // Read weekday/month byte
  anios = i2c_read(0);        //0
  i2c_stop();                // Issue stop signal
}
/***********FIN DE LECTURA DESDE EL RELOJ***********/




/***********muestra en rs232***********/
void despliega(void)
{
leer_tiempo();
Transforma(); //transforma de bcd a decimal

lcd_gotoxy(1,1);
printf(lcd_putc,"fecha:%d%d:%d%d:%d%d",(diasM/10),(diasM%10),(meses/10),(meses%10),(anios/10),(anios%10));

lcd_gotoxy(1,2);
printf(lcd_putc,"h:%d%d:%d%d:%d%d %f C",(horas/10),(horas%10),(minutos/10),(minutos%10),(segundos/10),(segundos%10),p);
}
/***********FIN DE MUESTRA EN uart***********/



void Transforma(void)   //bcd a entero, se convierte para poder visualizarlo en el display
{
  segundos=((segundos & 0xF0) >> 4)*10+(segundos & 0x0F);  // Transform segundos
  minutos=((minutos & 0xF0) >> 4)*10+(minutos & 0x0F);     // Transform months
  horas=((horas & 0xF0)  >> 4)*10+(horas & 0x0F);         // Transform hours
  anios=((anios & 0xF0)  >> 4)*10+(anios & 0x0F);         // Transform años
  diasS=((diasS & 0x30) >> 4)*10+(diasS & 0x0F);       // Transform day
  diasM=((diasM & 0x30) >> 4)*10+(diasM & 0x0F);       // Transform day
  meses=((meses & 0x10)  >> 4)*10+(meses & 0x0F);   // Transform month
}


  
void ds1307_write(unsigned int8 address, int8 data){
  i2c_start();                                   // Start I2C protocol
  i2c_write(0xD0);                               // DS1307 address
  i2c_write(address);                            // Send register address
  i2c_write(data);                              // Write data to the selected register
  i2c_stop();                                    // Stop I2C protocol
}

 
void entero_bcd(void)   //entero a bcd, se convierte antes de ingresarlo al reloj
   {
   int alta=0;
   int baja=0;
  
   /*para segundos*/
   alta=segundos/10;
   baja=segundos%10;
  
   alta=alta<<4;
   segundos=alta^baja;
  
   /*para minutos*/
   alta=minutos/10;
   baja=minutos%10;
  
   alta=alta<<4;
   minutos=alta^baja;
      
   /*para horas*/
   alta=horas/10;
   baja=horas%10;
  
   alta=alta<<4;
   horas=alta^baja;
  
   /*para diasM*/
   alta=diasM/10;
   baja=diasM%10;
  
   alta=alta<<4;
   diasM=alta^baja;
  
   /*para meses*/
   alta=meses/10;
   baja=meses%10;
  
   alta=alta<<4;
   meses=alta^baja;
  
   /*para anios*/
   alta=anios/10;
   baja=anios%10;
  
   alta=alta<<4;
   anios=alta^baja;
   }
 

Adjuntos

  • lcd-clock-adc-4550.7z
    83.8 KB · Visitas: 8
Tienes esto:
setup_adc_ports(ALL_ANALOG );

Si configuras todos los puertos con ADC como análogos, estás inhibiendo que RB0 funcione como digital, porque RB0 es AN12.

Si únicamente estás usando RA0 como entrada análoga, deberías usar:
setup_adc_ports(AN0);
 
¿La rutina de interrupción es la de ajuste del reloj?
Yo no lo hubiera hecho así, dará lo mismo quitar los delays, de todos modos se queda ahí esperando una cadena...
 
Claro. En la rutina de la interrupcion, jamas te conviene poner nada mas que cosas muy basicas, como sumas o asignacion de variables, como una bandera para poder, luego en el main hacer lo que se quiera. Pero para tu caso, ni siquiera hace falta una interrupcion, simplemente verifica el estado del pulsador en el loop del main
 
Buenas, pues les presento el codigo:

/*
* pruebaFotoresistencia.c
*
* Created: 23/01/2023 07:35:33 p. m.
* Author : fersa
*/

#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>



unsigned char swiches,DatoUDR;
unsigned int contador,ValorColor,limit;
unsigned int Botones, BotonesAnt, LimiteRepeticiones, Repeticiones;
unsigned int ValorADC;

int LeeBotones(void);

int main(void)
{

DDRD = 0xFF;//Declara el puerto D como salida
DDRC= 0x00;

//Configura timer 1 como sobreflujo cada 1ms
//TCNT1 = 49536;
//TCCR1B = 0x01;
//TIMSK1 |= 1<<TOIE1;

//Configura ADC como bandera
ADMUX = 0;
ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0) | (1<<ADSC);

//configuracion del USART
UBRR0 = 103;
UCSR0B=0x98;



//sei();

while (1)
{
Botones = LeeBotones();

switch (Botones)
{
case 0x80:

while((ADCSRA & ADIF)==0X10){}

ValorADC = ADC;

ValorColor=(ValorADC*5)/1.024;

UDR0=(ValorColor/1000)+ 0x30; _delay_ms(1);
UDR0=((ValorColor % 10000) / 1000) + 0x30; _delay_ms(1);
UDR0=((ValorColor % 10000) % 1000 / 100)+ 0x30; _delay_ms(1);
UDR0=(((ValorColor % 10000) % 1000) % 100 / 10)+ 0x30; _delay_ms(1);

UDR0= '\n';_delay_ms(100);
UDR0= '\r';_delay_ms(100);

//if (ValorColor>=4700 )
//{
//UDR0 = 'b';_delay_ms(1);
//UDR0 = 'l';_delay_ms(1);
//UDR0 = 'a';_delay_ms(1);
//UDR0 = 'n';_delay_ms(1);
//UDR0 = 'c';_delay_ms(1);
//UDR0 = 'o';_delay_ms(1);
//UDR0='\n';_delay_ms(1);
//UDR0='\r';_delay_ms(1);
//_delay_ms(250);
//}
//
//if ( ValorColor<4400)
//{
//UDR0 = 'n';_delay_ms(1);
//UDR0 = 'e';_delay_ms(1);
//UDR0 = 'g';_delay_ms(1);
//UDR0 = 'r';_delay_ms(1);
//UDR0 = 'o';_delay_ms(1);
//UDR0='\n';_delay_ms(1);
//UDR0='\r';_delay_ms(1);
//_delay_ms(250);
//}else{
//UDR0 = 'n';_delay_ms(1);
//UDR0 = 'a';_delay_ms(1);
//UDR0 = 'd';_delay_ms(1);
//UDR0 = 'a';_delay_ms(1);
//UDR0 = 'a';_delay_ms(1);
//UDR0='\n';_delay_ms(1);
//UDR0='\r';_delay_ms(1);
//_delay_ms(250);
//}
break;
}






}

}





//ISR(TIMER1_OVF_vect)
//{
//TCNT1 = 49536;
//
//
//
//ADCSRA |= 1<<ADSC;
//
//}




//ISR(ADC_vect)
//{
//unsigned int ValorADC;
//
//ValorADC = ADC;
//
//ValorColor=(ValorADC*5)/1.024;
//
//}

ISR(USART_RX_vect)
{
DatoUDR= UDR0;


}


int LeeBotones(void){
unsigned char Switches;
unsigned char ValBoton;

Switches = PIND & 0xf0;

if (Switches == BotonesAnt)
{
if (Repeticiones<LimiteRepeticiones)
{
Repeticiones++;
ValBoton = 0;
BotonesAnt = Switches;
}
else
{
if (Repeticiones == LimiteRepeticiones)
{
//Repeticiones++;
Repeticiones = LimiteRepeticiones + 100;
ValBoton = Switches;
BotonesAnt = Switches;
}
else
{
ValBoton = 0;
}
}
}
else//Si switches es diferente de BotonesAnt
{
BotonesAnt = Switches;
Repeticiones = 0;
ValBoton = 0;
}

return(ValBoton);
}



Como se pueden dar cuenta mis botones tienen un antirebote por software y ahora solo estoy usando un boton, mi Adc tiene conectada una fotoresistencia haciendo un divisor de voltaje, la aplicacion tiene una idea sencilla: mandar a llamar la conversion mediante el bit de registro del ADIF dentro del ADCSRA; habilitandolo con el boton, y colocar el valor del ADC en la terminal/hiperterminal/USART, cada que cargo lel programa y me conecto a la hiperterminal y presiono el boton, solo me muestra el primer valor de conversion. Entiendo que usando el ADC con la Interrupcion seria mas sencillo pero este codigo tiene comentadas unas lineas que seran introducidas despues para que en la misma terminal me muestre si lo que esta frente a la resistencia es blanco o negro, me gustria que funcione sin la interrupcion y adjunto fotos de la hiperterminal.

1675563152095.png
1675563174762.png

Adjunto tambien mi projecto de atmel studio/microchipstudio.
 

Adjuntos

  • pruebaFotoresistencia.zip
    95.1 KB · Visitas: 3
....la aplicacion tiene una idea sencilla: mandar a llamar la conversion mediante el bit de registro del ADIF dentro del ADCSRA; habilitandolo con el boton, y colocar el valor del ADC en la terminal/hiperterminal/USART, cada que cargo lel programa y me conecto a la hiperterminal y presiono el boton, solo me muestra el primer valor de conversion.
El bit ADIF indica el final de la conversión.
El inicio de la conversión es escribiendo un '1' en el bit ADSC. Como en el programa lo hacés una sola vez, pasa lo que tiene que pasar...

Entiendo que usando el ADC con la Interrupcion seria mas sencillo pero este codigo tiene comentadas unas lineas que seran introducidas despues para que en la misma terminal me muestre si lo que esta frente a la resistencia es blanco o negro, me gustria que funcione sin la interrupcion y adjunto fotos de la hiperterminal.

Código:
switch (Botones)
        {
            case 0x80:

            ADCSRA|=(1<<ADSC) ;            // Inicia la conversión
            while(!(ADCSRA&(1<<ADIF))) ;   // Espera que termine. La tenías mal escrita, la constante ADIF NO es una mascara

            ValorADC = ADC;
            ValorColor .........
 
Atrás
Arriba