Sida 1 av 1

AVR-kod kastar ingen interrupt. Varför?

Postat: 21 november 2012, 23:39:57
av mattswe
Ok, AVR-specialister. Nedanstående kod verkar inte kasta något interrupt och jag begriper inte varför. Den är skriven i Atmel Studio 6 och exekveras i en ATtiny45.
På T0 (klockingången) har jag för tillfället anslutit en liten tangentbordsknapp som är hårdvarumässigt "avstudsad". Den signalen ser hur fin ut som helst på oscilloskopet (10uF, 10k och en Inv. Schmittrigger). Jag förväntar mig alltså att då jag tryckt på knappen 5 gånger ska led:en på PB1 tändas, men det händer ingenting.

Kod: Markera allt

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main(void)
{
	DDRB |= (0 << PB2); // Pin PB2(T0) markeras som input (vilket är default)
	DDRB |= (1 << PB1); // Pin PB1 markeras som output
	PORTB |= (1 << PB2); // Aktiverar pullup-resistorn
	
	//Kontrollblink
	PORTB |= (1<<PB1);
	_delay_ms(500);
	PORTB &= (0<<PB1);

	cli(); // Stänger av globala interrupts (clear interrupts)
	
	TCCR0A = 0; // Sätter hela registret till 0	
	TCCR0B = 0;

	TCCR0B |= (1 << CS00); //Extern klocka på T0. Stigande flank.
	TCCR0B |= (1 << CS01); //Extern klocka på T0. Stigande flank.
	TCCR0B |= (1 << CS02); //Extern klocka på T0. Stigande flank.
	
	TCCR0A |= (0 << WGM00); // Mode CTC (Clear Timer on Compare Match Mode)
	TCCR0A |= (1 << WGM01); // Mode CTC
	TCCR0B |= (0 << WGM02); // Mode CTC

	OCR0A = 5; // Räknarens upplösning, TOP-värde.
	
	TIMSK = (1 << OCIE0A); // Aktiverar interrupt för TCNT0 = OCR0A (TOP-värdet är nått)
	
	sei(); // Slår på globala interrupts (set interrupts)

    while(1)
    {
    }
}

ISR(TIMER0_COMPA_vect)
{
	//Kontrollblink
	PORTB |= (1<<PB1);
}

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 21 november 2012, 23:44:46
av bearing
Räknar räknaren nedåt?

Jag tror den räknar uppåt. Du ska alltså initiera med värdet -5, alternativt trycka 250 gånger.

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 00:01:22
av sodjan
Det är väl en "compare" funktion?
När TCNT0 = OCR0A så bör interruptet utföras.
Jag vet inte varför det inte fungerar, men bara
som en kommentar till bearing... :-)

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 00:49:07
av bearing
Aha, så klart.

Jag kan inte heller se något fel. Men, mattswe, ditt sätt att sätta bitarna ger inte alltid önskat resultat. T.ex. denna rad: PORTB &= (0<<PB1); - vilken AND-ar porten med 0, d.v.s. tar bort pull-up på ingången. Fast ifall ingången är ansluten till en digital utgång från en schmitt-trigger borde ju inte det spela någon roll.

Även TCCR0B |= (0 << WGM02); är tveksam kod, eftersom att det inte förändrar något att göra OR med 0. Men eftersom att du skrivit 0 till registrena innan, borde det inte innebära ett fel.

Om du vill ändra bitarna abc till 010 måste du göra såhär:

Kod: Markera allt

REGISTERX &= ~(1 << BITa);
REGISTERX |=  (1 << BITb);
REGISTERX &= ~(1 << BITc);
Alternativt sätta alla önskade bitar på en gång (utan varken AND eller OR):

Kod: Markera allt

REGISTERX = (0 << BITa) | (1 << BITb) | (0 << BITc);

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 06:29:08
av Swech
Du sätter väl också inte själva räknaren till 0 vid start?
Om räknaren är > 5 så gör den ingen clear on compare förrän den slagit runt och
kommer till 5 igen

Swech

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 16:04:40
av Bylin
TCNT0 kommer att vara större än 5 innan interrupt för compare register A sätts.

Tänk på att TIMER0 blir aktiverad så fort någon av CS bitarna sätts. Eftersom CS00 först sätts så kommer räknaren att börja räkna där enligt CS00 mode. När CS01 sätts kommer räknaren att räkna enligt CS01 + CS00 mode osv. Det är inte fören CS02 sätts som räknaren kommer att stoppa och hamna i extern clock mode.

Därför så har räknaren redan räknat ett tag innan instruktionen "TCCR0A |= (1 << WGM01)" utförs.

Du kan nolla TIMER0 innan sei(); instruktionen eller sätta registervärdena samtidigt och inte behöva nolla TIMER0.

Pröva med denna kod:

Kod: Markera allt

OCR0A = 5;
TIMSK = (1 << OCIE0A);
TCCR0A = (1<<WGM01);
TCCR0B = (1<<CS00)+(1<<CS01)+(1<<CS02);
sei();


Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 22:33:45
av mattswe
Tack, när jag nollställer TCNT0 (eller använder Bylins kod) så fungerar det. Ett litet mysterium återstår dock. Jag måste trycka på knappen 6 gånger innan led:en tänds. Varför 6 och inte 5?!?
Men, mattswe, ditt sätt att sätta bitarna ger inte alltid önskat resultat.
Tack för denna anmärkning, ska tänka på det. Jag ska alltid skifta in en etta alltså, aldrig en nolla?
Även TCCR0B |= (0 << WGM02); är tveksam kod, eftersom att det inte förändrar något att göra OR med 0.
Jag förstår att detta inte har någon funktion, ville bara tydliggöra koden för mig själv, är tämligen grön på att programmera uC.

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 22 november 2012, 22:43:23
av sodjan
> Jag måste trycka på knappen 6 gånger innan led:en tänds. Varför 6 och inte 5?!?

Jag vet inte mycket om AVR, men i databladet (kap 11.5 i DOC2586.PDF) står det:
"A match will set the Output Compare Flag (OCF0A or OCF0B) at the next timer clock cycle."

Fundera lite på vad "next timer clock" betyder just i ditt fall.
Timern "klockas" ju just från tryckknappen, eller hur?

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 07:45:19
av mattswe

Kod: Markera allt

Jag vet inte mycket om AVR, men i databladet (kap 11.5 i DOC2586.PDF) står det:
"A match will set the Output Compare Flag (OCF0A or OCF0B) at the next timer clock cycle."
Ok, det förklarar ju saken. Jag har nog läst det men all databladets info är lite överväldigande än så länge.

Tack för hjälpen!

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 10:05:16
av sodjan
Och "lösningen" är alltså, vadå? :-)

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 11:27:34
av mattswe
Tja, lösningen var ju att nollställa TCNT0. Precis som du skrev så kastas interrupten vid "nästa klockcykel", alltså vid den sjätte pulsen, klockcykeln, från knappen. Nu ska jag byta ut knappen mot en "brusig" tachometersignal och mäta varvtal. :)

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 11:32:15
av Neptunus
Intressant svar på Sodjans fråga. Jag skulle nog använda fyra istället för fem för att tända upp dioden efter 5 knapptryck.

OCR0A = 4;

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 11:34:09
av sodjan
> Tja, lösningen var ju att nollställa TCNT0.

Ja, lösningen på det *gamla* problemet, det du undrade över nu
var ju varför du måste trycka sex gånger. Och "lösningen" som jag
frågade efter är ju så klart den som Neptunus angav...

Re: AVR-kod kastar ingen interrupt. Varför?

Postat: 23 november 2012, 11:38:26
av mattswe
Ok, jag förstår.