Interrupciones en ATmega con WinAVR

Hola que tal, bueno pues me paso lo siguiente.

Estoy haciendo un pequeño programa para controlar unos motores, y hago uso de las interrupciones, mas o menos pongo el ejemplo para no poner todo el codigo y aburrir

int contador; //Variable global

ISR(INT0_vect)
{
contador++; //Aqui funciona bien el incremento de la variable, cada ves que se llama se
//la incrementa
}

int main()
{
contador++; //Aqui tambien funciona bien el incremento
sei(); //Cuando entro al while ya no incrementa la variable
while(1){ //Espero a que se genere la interrupcion
contador++; //Aqui ya no incrementa la variable, pero cuando va a la interrupcion si lo hace
}
return 0;
}

Porque no se incremente la variable cuando la pongo dentro del while y si l ohace cuando va a la interrupcion, aclaro que la interrupcion se genera cada segundo, lo programe y en real no funciona lo probe en proteus y me di cuenta que no incrementa la variable en el while y luego lo probe en el mismo simulador del avr studio y lo mismo, ¿Porque no puedo incrementar la variable global cuando estoy dentro del while?
 
En AVR-GCC que en windows es Win-AVR, para que una varialbe tenga interaccion con las rutinas de interupcion la tienes que declarar como "volatile", por que si por ejemplo declaras

Código:
uint8_t c;
/*que es lo mismo que*/
static uint8_t c;

esta variable funcionara bien dentro el programa pero no tendra efecto de cambio dentro alguna interrupcion y viceversa, asi que tienes que hacer esto.
Código:
volatile uint8_t c; 
/*o lo que es lo mismo*/
volatile unsigned char c;

Solo asi la variable cambia en una interrupcion o en el programa principal ambos tendran evalor real de la variable esto por la naturaleza del compilador recuerda debes anteponer el keyword "volatile" para esto, existen manuales del compilador AVR-GCC disponibles si quieres mas informacion de los tipos de variable.
 
Si estuve leyendo y en realidad las ISR no son funciones como tal, solo son macros, y no debo modificar variables dentro de la ISR ni debo llamar a funciones desde ella, en fin ya modifique todo de nuevo procurando no modificar ningun registro estando en las ISR y funciona, lo que hice fue hacer una especie de bandera global que es la unica variable que modifica la ISR ya cuando retorne al lugar donde ocurrio dicha interrupcion lo que hago es leer esa bandera, en realidad todo el tiempo la estoy leyendo bueno imagino que habra mil formas mas pero bueno funciona gracias por tu ayuda
 
ME lleva el chanfle ahora ya no se que hice jajajaja no en serio que paso ya no funciona ayuda con esto porfa asi esta la cosa

volatile int flag_INT0;

void main()
{
flag_INT0 = 'N'
MCUCR = (1<<ISC01) | (0<<ISC00); //INT0 por flaco de bajada, INT1 por pulso bajo
GICR = (1<<INT0)|(1<<INT1); //Habilito interrupcion externa en INT0 y INT1
sei();
do{
if(flag_INT0 == 1)
{
RTC_leer(&tempo);
coloca_fecha_display(&tempo);
coloca_contador_display(&tA,&tB,&CarrosA,&CarrosB);
flag_INT0 = 0;
}
}while(1);
} //Fin main


ISR(INT0_vect)
{
flag_INT0 = 1;
}
ISR(INT1_vect)
{
flag_INT0 = 0;
}

Y pues no funciona cada ves que se genera la interrupcion el programa vuelve a comenzar desde el principio, o se vuelve loco, es como si no estubiera definiendo la ISR y el programa saltara al vector de reset, por cierto porque si declaro la variable global flag_INT0 como un uint8_t el compilador marca error diciendo que no se ha definido esa variable en la funcion ISR sale gracias por el poyo
 
Hola como estás Dseda86.

En principio, tenés que revisar la lógica de tu programa para que veas si funciona logicamente.
Segundo tenés que revisar como has realizado las configuraciones del microcontrolador. En AVR-GCC el compilador no realiza nada de manera automática salvo el guardado de contexto en las interrupciones. Por lo tanto tenés que saber bien que registros estás tocando y de valores le estás asignando.

Yo personalmente tuve algunos conflictos con las interrupciones por recepción del puerto serie en un microcontrolador ATtiny2313, pero nada grave. Te paso un ejemplo usando interrupciones por eventos externos en el pin INT0.

Código:
/*************************************************
 PROGRAMAS DE EJEMPLO PARA EL ATtiny2313 - 20PU.
 EJERCICIO Nº8: Interrupciones externas.
 PROGRAMADOR: Moyano Jonathan.
 Fecha: 2011.
 Programa: Programa para demostrar el uso de las interrupciones. En este caso 
           usaremos la interrupción INT0 en el pin PD2.

 Cristal:  12Mhz.
 Programador: USBtinyISP.
 ************************************************/
#include <avr/io.h>     // Definiciones de hardware.
#include <avr/interrupt.h> // Funciones para trabajar con interrupciones.
#include <util/delay.h> // Librería para generar retardos.

SIGNAL (SIG_INT0) // Tratamos la interrupción.
{ 

  uint8_t i;
  
   for(i=0; i<=8; i++) {
   
     PORTB = i;
	 
	 _delay_ms(150);
	 
	 }

}

int main(void) // Bucle principal del programa.
{
    DDRB = 0x0F;  // PB0-PB3 salidas.
    PORTB = 0x00; // Ponemos todas las salidas a 0. 
    PCMSK |= (1<<PIND2); // PIN D2 - INT0 configurado como entrada.
    MCUCR = (1<<ISC01) | (1<<ISC00); // Interrupción en INT0, por flanco
	                             // de bajada.

    GIMSK  |= (1<<INT0); // Habilitamos la interrupción externa INT0.
    sei();                // Habilitamos todas las interrupciones.

    while(1){
	PORTB = 0xFF; // Ponemos todas las salidas en alto.
	}             // Entramos en un bucle infinito.
 }

Espero te sirva, es para el ATtiny2313.
 
Gracias por la ayuda, mira segun yo mi logica esta bien jajjaja "y quien soy yo no!!" bueno estube leyendo el manual del avr-gcc y no le encuentro el error, lo unico que quiero hacer es modificar una variable global desde una rutina de interrupcion, para luego usar esa misma variable en main(), pero no me anda, cada ves que ocurre una interrupcion se salta al vector de reset, segun lei no es nada recomendable hacer llamadas a funciones desde la rutina de interrupcion por ejemplo como tu que llamaste a _delay_ms(), leyendo me surgieron dos dudas mas primero exactamente para que sirve reti(); y la segunda es que hablan de acceso atomico, haciendo referencia a que se debe tener cuidado al modificar registros de 16bits en una interrupcion, pero no le entendi mas, en fin agradesco tu ayuda y ojala puedan seguir apoyandome poque me esta desesperando, ahorita voy a probar a llamar a una funcion desde la interrupcion para que esa funcion modifique la variable aver si asi funciona
 
Es el atmega32 ese link que pusiste es el que te digo que ya lei, y segun estoy haciendo bien todo lo que dice ahi, ya intenta cambiar la optimizacion del compilador y nada de nada

Es raro solo falla cuando intento modificar la variable global por que si hago esto:

ISR(INT0_vect)
{
LIMPIA_LCD();
}
ISR(INT1_vect)
{
LCD_IMP_CADENA("HOLA",0,0);
}

Si hago eso y genero la interrupcion INT1 se imprime bien el mensaje en la lcd y luego si genero INT0 se limpia lo que esta en la LCD y lo puedo hacer tantas veces como quiera y no falla, entonces porque cuando intento modificar esa variable global si falla

Creo que ya funciona, http://www.nongnu.org/avr-libc/user-manual/FAQ.html,
Solo que ahi dice que la variable global la declaran como volatile uint8_t flag; sin embargo si yo lo hago asi el compilador dice: variable no declarada en main(), pero me di cuenta que es de 8 bits asi que no me funciono eso de uint8_t pues la declare como char y asi si funciona que cosas no!!! entonces queda asi

volatile char flag; //Variable global que puede ser modificada por cualquier interrupcion o funcion

ISR(Vector_interrupcion)
{
flag = 1;
}

void main()
{
flag = 0;
while(1)
{
if(flag == 1)
{ //Codigo que se ejecuta en caso de genera la interrupcion
flag = 0; //Deshabilito la bandera de interrupcion
}
}
}//Fin main

Nota: si cambio a char flag, por int flag o por uint flag o cualquier otra convinacion no me funciona ¿Porque? a caso tiene que ver con el acceso atomico y si es asi como se soluciona?
 
Última edición:
Nota: si cambio a char flag, por int flag o por uint flag o cualquier otra convinacion no me funciona ¿Porque? a caso tiene que ver con el acceso atomico y si es asi como se soluciona?

No tengo tanta experiencia con interrupciones en AVR, pero si funciona con char usá ese tipo de datos.

Yo tengo que hacer más pruebas con AVR - GCC. Si puedo hacer un ejemplo con el tipo de problemas que vos planteas lo posteo acá.
 
Ok sale gracias Jonathan, yo tampoco tengo experiencia con GCC pero no se porque me gusta mas jugar con avr que con pic jejeje bueno le voy a dejar el tipo char a ver si despues alguien nos explica porque?
 
Hola Moyano Jonathan, yo tuve problemas con la interrupción de recepción del puerto serie con un atme168
y combinado con el problema de Ajna que problema tuviste vos? me contas? para ver si es algo parecido y me ayudas por favor por que ya no se que puede ser.
 
Lo malo de dirigirse a una sola persona es que probablemente nadien mas responda y si esa persona tampoco lo hace pues no vas encontrar ayuda. O al menos asi me lo hicieron ver el dia que yo hice lo mismo, y ciertamente tienen razon.

Al ser atmega lo mas seguro es que tenga el modulo para comunicacion serie (por cierto a que comunicacion serie te refieres I2C SPI o RS232) ¿Que problema tienes? Moyano se referia al Attiny2313 que tiene un modulo muy basico para comunicaciones serie y ciertamente se complica algunos detalle, pero en el atmega es aun mas facil
 
Me dirigí a él por que comento que tuvo un problema por el rs232 y quería saber si se parecía al mío y ver si podía ayudarme.

El problema es el Siguiente:

"va para cualquiera que pueda ayudarme"

Estuve haciendo un programa en CSharp para conectarme con mi circuito y leer variables
pero por el momento estaba probando si podía cambiar de velocidad desde mi programa hecho csharp cuando le mando a que cambie a 9600 que esta por default responde bien, pero cuando le cambio a otra por ejemplo 19200 anda mal y no contesta dejo el código de los dos programa para ver si alguien puede guiarme con las modificaciones por que ya no se como arreglarlo. :(

desde ya muchas gracias espero encuentren algún problema que yo no haya visto :(

saludos gracias Ajna!
 

Adjuntos

  • codigo corto.txt
    6.2 KB · Visitas: 6
  • Analizador.rar
    71.9 KB · Visitas: 13
Me dirigí a él por que comento que tuvo un problema por el rs232 y quería saber si se parecía al mío y ver si podía ayudarme.

Sinceramente hace bastante que no programo en AVRGCC y el problema específico no lo he podido solucionar para el ATtiny2313. Tampoco he probado el puerto serie en otros micros de ATMEL, todo lo que he realizado como proyecto, lo terminé haciendo con la plataforma Arduino.

Saludos !
 
Hola, amigos. Estoy al borde de la locura.
Este es el tema más afín que he encontrado, lo preguntaré aquí para no crear uno nuevo.
La interrupción no funciona, simplemente, cuando presiono el pulsador, debiese encender el pin PB7 y no lo hace.
C:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include<util/delay.h>
#include<avr/pgmspace.h>
#include<stdlib.h>

int main()
 {
       cli();

     PCICR = 0b00000001;
     PCMSK0 = 0b00001000;

     sei();
    
  DDRB = 0b10110010;
  PORTB = 0b00100010;   

   // Write your code here
   while (1)
   ;
   return 0;
 }

   ISR(PCINT3_vect)
 {
    PORTB |= (1<<PORTB7);
    _delay_ms(10000);
 }
 

Adjuntos

  • duda.png
    duda.png
    98.6 KB · Visitas: 2
Última edición por un moderador:
Es por un exceso de creatividad, el vector PCINT3_vect no existe en el 328P
Debiste escribir PCINT0_vect que es lo que corresponde para el primer grupo de interrupts on change.

Acordate que en las interrupts_on_change debe leerse el puerto dentro de la interrupción para limpiar la máscara.
 
Es por un exceso de creatividad, el vector PCINT3_vect no existe en el 328P
Debiste escribir PCINT0_vect que es lo que corresponde para el primer grupo de interrupts on change.

Acordate que en las interrupts_on_change debe leerse el puerto dentro de la interrupción para limpiar la máscara.

Gracias, Eduardo.
Perdona mi ignorancia, pero, ¿cómo se explica esto entonces???.
Cabe destacar que hace rato me dí cuenta que el datasheet de este componente es basura, es regado, arbitrario, vaya, es un desastre, nada que ver con los PIC.
Otra cosa que no comprendo es el termino volatile, pues si no lo pongo desaparece el valor de la variable.
Me refiero a una variable, global, fuera del main.
Se supone que tiene alcance para todo el mundo y que no debe perder su valor, o sea, esto en el CC5X para PIC, no existe, el termino volatile me refiero, además es ambiguo, pues volatile da la impresión que va a ser usada como una copia por valor y que fuera de la función usada volverá a ser como antes, y precisamente, hace lo contrario.
Ya creo que entendí, PCINT0, se pone en la función manejadora, pero en realidad es para todos los pins B que yo habilite con PCMSK0
¿Es correcto?
 

Adjuntos

  • Eduardo.png
    Eduardo.png
    129.4 KB · Visitas: 5
Última edición por un moderador:
Gracias Eduardo. Perdona mi ignorancia, pero como se explica esto entonces???.
En las interrupts_on_change tenés una máscara, que es la de la hoja que subiste, y el grupo de pines que activan la interrupción.
Son:
PCINT0_vect para los pines PCINT0-7
PCINT1_vect
para los pines PCINT8-15
PCINT2_vect
para los pines PCINT16-24

Que la nomenclatura es confusa??? Y... sí, pero es como quejarse de la humedad.

Otra cosa que no comprendo es el termino volatile, pues si no lo pongo, desaparece el valor de la variable. Me refiero a una variable, global, fuera de main. Se supone que tiene alcance para todo el mundo y que no debe perder su valor, o sea, esto en el CC5X para pic, no existe, el termino volatile me refiero, además es ambiguo, pues volatile dá la impresion que va a ser usada como una copia por valor y que fuera de la funcion usada volverá a ser como antes, y precisamente, hace lo contrario.
Lo que pasa es que GCC hace una compilación mucho mas retorcida que otros. Según como lo mires es bueno o malo, pero no hay que quejarse sino aprender como trabaja para aprovecharlas, o cambiar de compilador.

volatile indica que a esa variable te la puede cambiar otro proceso, por lo tanto al optimizar el código siempre la debe leer.
Por ejemplo si escribís
uint8_t x ;
void main(){
x=1 ;
x++ ;
x++ ;
x++ ;

GCC te va a generar directamente x=4; (en assembler obvio)
Pero si la declarás volatile van a ser las 4 instrucciones pues durante la ejecución te la pueden modificar.
 
Muchas gracias, Eduardo. Muy agradecido, hermano.
A
ver si termino el proyecto de una vez.
Esto lo tengo guardado hace meses, y hace rato estoy por preguntar en el foro.
¿Qué puedo programar con esto y por qué dice limitado?
O-
sea, ¿es para alguna cantidad de usos y ya, o se refiere a que se fabricaron pocos?.
PD: El que me lo regaló se fue del país y se dedicaba a piratear consolas de juego.
 

Adjuntos

  • IMG_20240329_011419.jpg
    IMG_20240329_011419.jpg
    111.3 KB · Visitas: 12
  • IMG_20240329_011501.jpg
    IMG_20240329_011501.jpg
    207 KB · Visitas: 12
Última edición por un moderador:
...¿Qué puedo programar con esto y por qué dice limitado?
O-
sea, ¿es para alguna cantidad de usos y ya, o se refiere a que se fabricaron pocos?.
Eso debe venir con un software. Si no, mas que para trabar la puerta no se me ocurre.

Lo de limitado no sé, supongo que se refiere a que a las memorias solo las podés programar un cierto número de veces, que puede ser 10000 o mas escrituras de un mismo sector.
En programaciones "normales" jamás vas a llegar a ese número, pero si se lo usa dentro de una aplicación que esté grabando sectores a cada rato, tranquilamente.
 
Atrás
Arriba