Problemas con las interrupciones de mi AVR ATmega2056

#1
Hola a todos.
Tengo un problema y necesito ayuda con un programa que estoy haciendo en donde manejo de instrucciones externas.
Compila correctamente y al momento de simularlo en Proteus trabaja tal como lo programé, pero al momento de descargarlo en mi ATMega2056 se muestra una interrupción pero no ejecuta las tareas dentro de ésta.

Principalmente lo que hace el programa es encender y apagar un led mientras no se presente alguna interrupción.
En el momento que se presenta la interrupción INT0 comenzará a incrementarse la intensidad de iluminación de otro led a través de un PWM y en el momento que se presenta la interrupción INT1 se decrementa la intensidad de iluminación del mismo led.
El programador que estoy utilizando es el USBasp y el microcontrolador es el que está montado en una tarjeta Arduino Mega la cual fue borrada para poder trabajar sobre Atmel Studio en C.

Dejo el código de mi programa:
C:
/*

* Dolly_project.c

*

* Created: 25/10/2018 11:51:02 a. m.

* Author : Eduardo-WCM

*/



//#ifndef F_CPU

#define F_CPU 16000000UL                    // set the CPU clock

//#endif



#include <avr/io.h>

#include <avr/interrupt.h>

#include <util/delay.h>





#define Max_Level 255   

volatile char brightness = 0;



void PWM_UP()

{

    while((PIND&0x01)==0x01 && brightness < 250)

    {

        brightness += 10;

        OCR3A = brightness;

        OCR3B = brightness;

        _delay_ms(50);

    }

}

void PWM_DOWN()

{

    while ((PIND&0x02)==0x02 && brightness>=30)

    {

        brightness -= 10;

        OCR3A = brightness;

        OCR3B = brightness;

        _delay_ms(50);

    }

  

}

ISR (INT0_vect)

{

    PORTA = (1<<PINA4)|(1<<PINA5)|(1<<PINA6);

    EIFR |= (1<<INTF0);

    PWM_UP();

    EIFR &=~ (1<<INTF0);

}

ISR (INT1_vect)

{

    EIFR |= (1<<INTF1);

    PWM_DOWN();

    EIFR &=~ (1<<INTF1);

}



// initialize PWM

void Config()

{

//---------------------- INTERRUPTS ---------------------------------   

//    cli();    //Disable interrupts

    EICRA |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);    // Interrupts are activated in rising edge

    PCICR |= (1<<PCIE0);

    EIMSK |= (1<<INT0)|(1<<INT1);    // Enable Int1 and Int0

    sei();    //Enable Interrupts





//-----------------------  PWM    ---------------------------------------

    // initialize timer0 in PWM mode

    // Waveform Generation Mode: Phase correct PW Mode, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP

    TCCR3A |= (1<<WGM30);

  

     // Compare Output Mode: Phase correct PWM, non-inverting mode, A, B and C Registers are activated

    TCCR3A |= (1<<COM3A1)|(1<<COM3B1)|(1<<COM3C1);



    // Clock Select: clk/64 => CS32|CS31|CS30 = 0|1|1 */

    TCCR3B |= (0<<CS32)|(1<<CS31)|(1<<CS30);



    // Set Timer3 pins as output : Channel A :(PE3/OC3A/AIN1)   Channel B :(PE4/OC3B/INT4)    Channel C :(PE5/OC3C/INT5)

    DDRE |= (1<<DDE3)|(1<<DDE4)|(1<<DDE5);

  

    DDRA = 0xFF;

    DDRB = 0xFF;

    DDRC = 0xFF;

    DDRD = 0xF0;

    _delay_ms(10);

}

int main(void)

{

  

    Config();

    OCR3A = brightness;

    OCR3B = brightness;

    while(1)

    {

      

        PORTA |= (1<<PINA0);

        _delay_ms(50);

        PORTA &=~ (1<<PINA0);

        _delay_ms(50);

  

    }

    return 0;

}
 
#2
Un par de cosas:

1- No es buena idea usar un while con delays dentro de una rutina de interrupción, menos si c/delay es de 50mS.
2- Supongo que usas un pulsador para activar las interrupciones externas, en la rutina de interrupción no se ve ningún tipo de antirrebote por soft, ¿tuviste en cuenta eso con el hardware?.
 
#4
Una pregunta sin ánimo alguno a ofender. Ya has reflexionado como es que funcionan las interrupciones, que inicialisaciones el controlador requiere y que tipo de labores se deja fuera de una rutine de servicio de una interrupción? Y porque?
Has reflexionado que es el tal rebote del que habla cosmefulanito04. Sabes que ocurre cuando se presenta el síntoma del rebote? Y has reflexionado de porque el "antirebote" evita el rebote?
Lo triste de entornos como los del Arduino es que ocultan muchas de las tareas de inicialisación por lo que usuarios se meten en aventuras y de pronto se sorprenden si algo no funciona como lo desean. Como no tuvieron que aprender el tipo de cosas que presento como preguntas al principio de esta publicación y no comprenden porque algo que funciona en un simulador como el proteus no hace lo mismo en un circuito real. Muy bien me puedo imaginar que el efecto de rebote no aparece en Proteus?
 
#6
@Dr.Zoidberg: No tengo Proteus por lo que no tengo experiencias de primera mano. Pero siempre me da tanta pena que personas con un interés inicial en electrónica abandonan esto por frustración. Siempre trato de hacer claro que lo que comento no quiere ser ofensivo en ninguna forma y que lo que escribo lo hago por ver repetir síntomas una y otra vez que llevan a la persona a abandonar sus actividades. La definición de tales personas como novatas no expresa nada de que tan peritos sean. Es no mas el perfil que vemos tan frequentemente.
 
#7
Hola, mirá el tema de las interrupciones no es comprendido inmediatamente por quienes las empiezan a utilizar por primera vez.

Así que pensando en eso, como te indicaron, debés permanecer el menor tiempo posible dentro de ellas, por eso te indican que nada de "delay" dentro de una interrupción, otro error recurrente es darle caña a feróz cálculo en punto flotante dentro de ellas, y así lo que se le pueda pasar por la mente de un novato...

Yo en tu lugar lo planteo así, detecto que presionaron un pulsador con una interrupción externa en tal o cual pin. Inmediatamente detectado el cierre del pulsador o sea dentro de la interrupción, paralizo éste tipo de interrupción, a continuación, programo un temporizador, de 50ms (a Mí me gusta 100ms o un poco más ) con un timer, que dispara otra interrupción, terminado éste tiempo, vuelvo a "conectar" la interrupción externa, la del pulsador... Y me preparo para detectar otra vez que lo presionen al pulsador/es del circuito.


Ahora es cuestión que te pongas a elaborar el código para la solución que te planteo, y que no es la única por cierto.

Vos ya diste un paso importantísimo, y es prescindir de la plataforma de software del arduino, que para muchos poblemas y gentes, es limitada.
Por cierto no era necesario eliminar el bootloader para programar el arduino directamente en C, con su bootloader original se pueden cargar los .hex del código C o de cualquier fuente, NO REQUERIS PROGRAMADOR EXTERNO, investiga el asunto, ya lo dije, me canso de copiarme...

¿ Es necesario modificar wiring.c en Arduino IDE ?
 
#8
Sobre lo del rebote, no soy un novato en eso de la programación, por años programé microcontroladores de Microchip en MPLAB y utilicé interrupciones por lo que conozco el problema del rebote y que se puede eliminar por hardware sin problemas. El detalle es que dejé de programar micros desde hace 2 años y los estoy retomando pero ahora con AVRs (no me gusta arduino, por eso no lo trabajo, pero las placas de AVR de arduino son baratas por eso decidí comprar un Arduino Mega, pero con el fin de trabajarlo en C) pero no tengo compañeros cercanos que sepan de éste tema, por eso me di a la tarea de escribir y poder tener un comentario constructivo y poder resolvr este problema rápido para poder añadirle más funciones y terminar mi proyectito.

Ale sergi: Muchas gracias por el comentario, lo voy a tomar en cuenta para ver si jala.
1543514315580.png
Les comparto el diagrama de conexiones (tal como se muestra en proteus lo conecté físicamente), así me ha servido con muchos proyectos anteriores cuando utilizaba PICs, pero si hay algún comentario para mejorarlo, agradezco sus comentarios

Ahora muestro mi programa reducido que aún sigue sin funcionar para saber si pudieran apoyarme.
C:
#define F_CPU 16000000UL                   



#include <avr/io.h>

#include <avr/interrupt.h>

#include <util/delay.h>



char Up=0, Down=0;



ISR (INT0_vect)

{

    PORTA = 0xFF;

    EIFR |= (1<<INTF0);

    Up = 1;

    EIFR &=~ (1<<INTF0);

    _delay_ms(100);

}

ISR (INT1_vect)

{

    PORTA = 0x00;;

    EIFR |= (1<<INTF1);

    Down = 1;

    EIFR &=~ (1<<INTF1);

}



void Config()

{

    //---------------------- INTERRUPTS ---------------------------------

    cli();    //Disable interrupts

    EICRA |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);

    PCICR |= (1<<PCIE0);

    EIMSK |= (1<<INT0)|(1<<INT1); 

    sei();    //Enable Interrupts

  

    DDRA = 0xFF;

    DDRD = 0x00;

    _delay_ms(50);

}



int main(void)

{

    Config();

    while(1)

    {     

        PORTA |= (1<<PINA0);    _delay_ms(50);

        PORTA &=~ (1<<PINA0);    _delay_ms(50);

        if(Up)

        {

            _delay_ms(1000);

            Up=0;

        }

        if(Down)

        {

            _delay_ms(1000);

            Down=0;

        }

    }

    return 0;

}
 
#9
Suponiendo que en el hard tenés en cuenta el antirrebote (en el esquemático que subiste eso no se ve, pero puede ser por un tema de simulación), lo que noto es lo siguiente:

C:
ISR (INT0_vect)

{

    PORTA = 0xFF;

    EIFR |= (1<<INTF0); //<------- Esta línea es la que limpia la interrupción <---- OK!

    Up = 1;

    EIFR &=~ (1<<INTF0); //<------- Esta línea está de más

    _delay_ms(100);  //<---------- Ya se discutió sobre este tema, 100mS en una rutina de interrupción es un horror.

}
Por otro lado, no hay diferencia entre Up y down en main, los dos haces exactamente lo mismo, es decir generan una demora de 1 Seg con el puerto A en estado bajo, salvo que la interrupción se haya dado luego de la línea "PORTA &=~ (1<<PINA0); _delay_ms(50);".

Por el lado de la inicialización, parece correcta.
 
#10
No se ve el esquema pero me parece que lleva resistencias de 10k y 330k valores que me parecen demasiado altos.
Habrá que ver ese compilador que hace, si inhabilita las interrupciones en los delays o no.
Yo probaría un código mas sencillo en plan encender un led con la interrupción por ir descartando cosas.
Respecto a los delays como ya lo ha dicho Dr.Zoiberg, no digo nada.
 

Temas similares


Arriba