Pagina 1 di 1

Interrupt con AtMega16

MessaggioInviato: 17 mag 2012, 13:50
da EliseoMy
Ciao ragazzi.

Sono disperato...ho fatto

un piccolo e semplice firmware per la gestione di alcune sonde pt100 e alcuni consensi dei relè e roba simile, il tutto visualizzato su display LCD.

La gestione del tutto è affidata al microcontrollore atMega16.

Ora il problema è che volevo gestire un semplice orologio che mi serve per alcuni parametri, ma nonostante utilizzi sempre il solito sistema di interrupt sul timer1, stavolta non riesco a farlo funzionare.

Ogni volta che interviene l'interrupt, mi si resetta il micro.

Allora ho rifatto il programma solo per gestire l'interrupt, ma nulla da fare, si resetta ad ogni interrogazione.

Dove sbaglio?? qualcuno sa aiutarmi??

Posto il programma timer1.

Codice: Seleziona tutto
// Target : M16
// Crystal: 8.0000Mhz
#include <iom16v.h>
#include <macros.h>

char secondi=0;

void port_init(void)
{ PORTA = 0xF0;
DDRA  = 0xF0;
PORTB = 0xFF;
DDRB  = 0xFF;
PORTC = 0xF0;
DDRC  = 0xF0;
PORTD = 0x0B;
DDRD  = 0x0B;
}
//Watchdog initialisation
// prescale: 1024K cycles
void watchdog_init(void)
{ WDR();
WDTCR = 0x0E;
}
//TIMER1 initialisation - prescale:1024
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:  1,000Sec (0,0%)
void timer1_init(void)
{ TCCR1B = 0x00;
TCNT1H = 0xE1;
TCNT1L = 0x7C;
OCR1AH = 0x1E;
OCR1AL = 0x84;
OCR1BH = 0x1E;
OCR1BL = 0x84;
ICR1H  = 0x1E;
ICR1L  = 0x84;
TCCR1A = 0xC0;
TCCR1B = 0x05; //start Timer
}
void init_devices(void)
{ CLI();
port_init();
watchdog_init();
timer1_init();
MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x10;
SEI();
}

//void main(void)
{ init_devices();
while (1)
    WDR();
//if (TCNT1==OCR1A)
//secondi++;       
//TCNT1H = 0xE1;
//TCNT1L = 0x7C;}
//if ((secondi%2)==0)   
//PORTC=PORTC|0x80;//spegni disp
//else 
//PORTC=PORTC&0x7f;//accendi disp
//}
}

#pragma interrupt_handler timer1_compa_isr:7
void timer1_compa_isr(void)
{
secondi++;
if (secondi%2)
PORTC=PORTC|0x80;//spegni disp
else
PORTC=PORTC&0x7f;//accendi disp
}


Come si vede, nel main ho commentato delle righe di codice, che sono quelle gestite dall'interrupt, infatti se lo disabilito e utilizzo quelle righe di codice, la frequenza sul pin7 della porta C è perfetto ad 1 secondo.

GRAZIE

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 8:25
da simo85
Per caso hai abilitato il WTD? Se si disabilitalo.

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 8:37
da EliseoMy
WTD??....cosa intendi il watch dog??...anche disabilitandolo non cambia nulla.
E' proprio alla interrogazione dell'interrupt, anche cambiando il tempo del timer, si allunga o accorcia il reset, esattamente con la frequenza del timer impostata. (misurata con oscilloscopio)

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 8:47
da simo85
Riesci ad interpretare il tuo stesso codice?

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 8:53
da EliseoMy
Certo che lo interpreto....ma il problema non è il watch dog, già provato a disabilitarlo

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 9:06
da simo85
Stando al tuo codice, questo richiama la funzione WDR() all'infinito.. Perché? Quello che hai commentato non veniva ugualmente mai eseguito, o così sembra..
Detto questo la logica del firmware, a prima impressione, non mi sembra corretta.

Non sono un indovino ma secondo me WDR sta per Watch Dog Reset, giusto? Se lo disabiliti che senso ha resettarlo?

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 9:19
da EliseoMy
Allora:
1)Il ciclo infinito while(1) continua a resettare il Watch dog, altrimenti al termine del suo conteggio si resetta il micro, poiché, come si vede dal codice, il wacth dog è abilitato.
Dalla tua prima risposta, mi indicavi il problema del continuo reset sul watch dog, ma quello non è, perché anche disabilitandolo, e quindi cambiando il codice con
while(1);
il mio problema non si risolve.
2)le frasi commentate nel main, non vengono MAI eseguite, ma le ho postate comunque, perché sono gli stessi comandi che dovrebbe fare l'interrupt, solo che se inseriti nel main (togliendo il commento) il sistema funziona con la frequenza desiderata, senza alcun reset, il che significa che il reset che si autogenera non è provocato dalle righe stesse di codice.
3)Il vero principio del firmware è: non fare nulla.....attiva e disattiva l'uscita solo se si presenta l'intrerrupt di comparazione timer1. Il problema però è che ogni qual volta entra in interrupt, mi resetta il micro.
Sembra quasi che l'indirizzo dello stack si cancelli e non riprenda il programma da dove era stato lasciato

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 12:09
da simo85
EliseoMy ha scritto:1)Il ciclo infinito while(1) continua a resettare il Watch dog, [...] ma quello non è, perché anche disabilitandolo [...] il mio problema non si risolve.

Allora non usare il WTD..

2)le frasi commentate nel main [...] sono gli stessi comandi che dovrebbe fare l'interrupt, solo che se inseriti nel main [...] il sistema funziona con la frequenza desiderata.
[...]
Sembra quasi che l'indirizzo dello stack si cancelli e non riprenda il programma da dove era stato lasciato


A quale documento o microcontrollore si fa riferimento? A questo? Quale compilatore o IDE usi? Si sa poco o niente di come stai lavorando. :(

Il tuo main deve essere qualcosa del genere:
Codice: Seleziona tutto
void main(void)
{
   while(1)
   {
      if((secondi % 2) == 0)
         PORTC |= 0x80;
      else
         PORTC &= 0x7f;
   }
}

E nell'interrupt incrementi solo i secondi.

Re: Interrupt con AtMega16

MessaggioInviato: 18 mag 2012, 12:34
da EliseoMy
Utilizzo ICC AVR della ImageCraft, il microcontrollore è un ATmega16 della Atmel, quello che hai postato col datasheet.
Il firmware è molto più complesso, ma visto che si trattava di un problema sull'interrupt, ho fatto un programmino di 3 righe per vedere e capire dov'è il problema.
Come si fa a gestire l'interruput??
Comunque ho rifatto il codice, ma non funziona.

Codice: Seleziona tutto
#include <iom16v.h>
#include <macros.h>
char secondi=0;
void port_init(void)
{
PORTA = 0xF0;
DDRA  = 0xF0;
PORTB = 0xFF;
DDRB  = 0xFF;
PORTC = 0xF0; //m103 output only
DDRC  = 0xF0;
PORTD = 0x0B;
DDRD  = 0x0B;
}
//TIMER1 initialisation - prescale:1024
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:  1,000Sec (0,0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xE1; //setup
TCNT1L = 0x7C;
OCR1AH = 0x1E;
OCR1AL = 0x84;
ICR1H  = 0x1E;
ICR1L  = 0x84;
TCCR1A = 0xC0;
TCCR1B = 0x05;
}
void init_devices(void)
{CLI();
port_init();
timer1_init();
MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x10;
SEI();
}
void main(void)
{
init_devices();
while (1)
{if (secondi%2)
    PORTC=PORTC|0x80;//spegni disp
  else
    PORTC=PORTC&0x7f;//accendi disp
}
}//main
#pragma interrupt_handler timer1_compa_isr:7
void timer1_compa_isr(void)
{ secondi++;
}

Re: Interrupt con AtMega16

MessaggioInviato: 6 giu 2012, 12:56
da dursino
Sai, potresti provare il programma che resetta sempre e aggiungere all'inizio una routine che si salva il registro di reset dell'atmega.
E' un registro dove si setta un bit opportuno a seconda della causa di reset.

Se questo sarà tutto nullo, allora il problema è solo software (stack Overflow?).

Ciao