Hallo,

Ik zit wat te prutsen met een ATtiny2313...
Als ik een knopje die op PB0(INT0) zit indruk moet een ledje op PD5 gaan branden.

Ik heb nu deze code geschreven in ASM:

 .include "tn2313def.inc"

.def temp = R16

.org 0x0000
rjmp Init
.org INT0addr
rjmp ledje

Init:
ser temp		
out DDRD, temp						;port D is output

LDI   temp, LOW(RAMEND) 			;Initiate Stackpointer
OUT   SPL, temp

ldi temp, (1<<INT0)+(1<<INT1)		;Int masks 0 and 1 set
out GIMSK,temp
rjmp loopje

loopje:
rjmp loopje

ledje:	
sbi PORTD, 5 
rjmp loopje

De code is wat bij elkaar geraapt uit andere voorbeelden.

Weet iemand wat ik fout doe?

Fout = assembly gebruiken ipv C :-)

Je moet wel global interrupts activeren, anders reageert de AVR op geen enkele interrupt. SEI, dus.

Bekijk ook het MCUCR-register eens. Daar kan je instellen op welke toestand INT0 en INT1 moeten reageren.
Dat kan een laag niveau zijn. Af te raden IMHO, omdat er dan --zolang de pin laag is-- telkens opnieuw naar de ISR gesprongen wordt.
Een interrupt bij hoog-naar-laag of bij laag-naar-hoog lijkt me beter. Ook een interrupt bij elke niveau-wisseling is bruikbaar - 't hangt er van af, wat de toepassing is.

Verder zou ik bij zoiets geen plusteken maar een or-teken gebruiken:

ldi temp, (1<<INT0)+(1<<INT1)

Het maakt in dit geval geen verschil, maar als je een boel bits in een register wil setten, en je tikt uit verstrooidheid tweemaal hetzelfde bit, dan gaat de assembler daar iets van maken dat je niet wil.
Voorbeeldjes, die een verschillend resultaat opleveren:


ldi temp, (1<<INT0)+(1<<INT1)+(1<<INT0)
ldi temp, (1<<INT0)|(1<<INT1)|(1<<INT0)

Enkel de tweede regel geeft het gewenste resultaat, ook al plaats je er nog 88 maal "|(1<<INT0)" bij.

[Bericht gewijzigd door pros op (22%)]

Op 23 december 2008 19:30:06 schreef pros:
Fout = assembly gebruiken ipv C :-)

Dat is de volgende stap op mn lijstje;)

Bekijk ook het MCUCR-register eens.

Welke waarde moet ik in het MCUCR register schrijven om de interrupt te laten reageren op een negatieve flank?

In C: :-)


MCUCR = (1 << ISC01) | (1 << ISC11);

Bedenk wel, dat een gewone drukknop contactdender zal veroorzaken, waardoor de ISR meermaals wordt aangeroepen, met onvoorspelbaar resultaat tot gevolg. Een software-vertraging maakt daar korte metten mee. Je moet dan wel --net voor het verlaten van de ISR-- de interrupt-flag wissen uit voorzorg.


EIFR |= (1 << INTF0);  // Of (1 << INTF1)

Volgens mij loopt ook uw interupt routine vast.
Je moet terug keren uit je routine met "RETI" ipv "RJMP loopje".
Met RETI gaat hij terug naar daar waar hij bezig was voor de cpu in de interupt routine kwam
Nu gaat de interupt routine nooit afgewerkt zijn.

Op 23 december 2008 20:38:31 schreef pros:
In C: :-)


MCUCR = (1 << ISC01) | (1 << ISC11);

Ik kan het niet opmaken uit de datasheet... wat moet het zijn in ASM?

Je moet terug keren uit je routine met "RETI" ipv "RJMP loopje".

Een reden te meer om C te gebruiken. >:)

Nou, niet echt, hoor. Ik ben allesbehalve afkerig van assembly. Daarmee heb je alles in de hand. Maar je moet voor iedere microprocessor/microcontroller telkens weer andere instructies gebruiken, en daar wordt een mens niet blij van...

@JOK:


ldi temp, (1 << ISC01) | (1 << ISC11)
out MCUCR,temp

Denk ik (hoop ik) toch...

Op 23 december 2008 21:23:14 schreef pros:

Nou, niet echt, hoor. Ik ben allesbehalve afkerig van assembly. Daarmee heb je alles in de hand. Maar je moet voor iedere microprocessor/microcontroller telkens weer andere instructies gebruiken, en daar wordt een mens niet blij van...

Off-topic: Eens. Ik heb een aantal dingetjes in assembler gedaan, maar in C ontwikkel je veel sneller, plus dat overstappen op een andere uC relatief pijnloos is. Wil natuurlijk niet zeggen dat je geen traditionele 'gotcha's' hebt (poorten die op een ATmega8 wel werken, en op een atmega32 net even anders werken; JTAG-interface wat in de weg zit, dat soort dingen)

Daarnaast: je eindigt al snel met het idee 'ja, laat ik allerlei hulproutines gaan maken en die in een library gooien... hrm, heet zoiets niet libc?'

Op 23 december 2008 21:13:29 schreef JOK:
[...]

Ik kan het niet opmaken uit de datasheet... wat moet het zijn in ASM?

Ik heb verschillende oefeningen staan met interrupts in assembly...misschien leer je daar iets van?

dit zie ik bij jou niet staan


sei     ; set interrupt

de 'sei' is ook zeer belangrijk!
en wil je in een bepaald gedeelte van jou pros prog geen interrupt dan zet je cli ; clear interrupt

Bedankt allemaal tot zover!

Ik heb nu deze code:


.include "tn2313def.inc"


.def temp = R16

.org 0x0000
rjmp Init
.org INT0addr
rjmp ledje

Init:

SEI
ser temp		
out DDRD, temp						;port D is output

LDI   temp, LOW(RAMEND) 			;Initiate Stackpointer
OUT   SPL, temp

ldi	temp, (1<<INT0)|(1<<INT1)		;Int masks 0 and 1 set
out	GIMSK,temp
ldi temp, (1 << ISC01) | (1 << ISC11)
out MCUCR,temp

sei

rjmp loopje


loopje:
rjmp loopje					; never ending loop (wait for interrupt)


ledje:	
sbi PORTD, 5 
reti

Het ledje brand nu vanaf het begin en de drukknop heeft geen invloed meer:(
Wat zie ik over het hoofd?

Hoe is die drukknop aangesloten? Tussen INT-pin en GND, samen met een pull-up weerstandje? Als dat laatste ontbreekt, kan je ook de interne pull-up inschakelen.

Verder blijft PD5 hoog, zodra er 1 enkele interrupt heeft plaatsgevonden.
Er is in je code nergens een instructie die de pin terug laag maakt.

die knop is met een pullup en een RC-netwerkje aangesloten op PB0.

Ik snap wel dat de LED altijd aan zal blijven, maar dat mag toch niet gebeuren als ik de knop nog nooit ingedrukt heb?

Dat zou niet mogen, nee. Misschien nog een "cbi PORTD, 5" op het einde v/d init?

Nu is de led inderdaad uit. Echter blijft de led uit ook nadat ik op de knop druk.

Moet ik misschien nog iets in de code toevoegen wat de uC duidelijk maakt op welke poort de knop hangt? Of hoort de PB0,INT0 altijd bij de INT0 interrupt?

Ow! Daar heb ik over gekeken:

Ik zit wat te prutsen met een ATtiny2313...
Als ik een knopje die op PB0(INT0) zit indruk moet een ledje op PD5 gaan branden.

INT0 zit bij de ATtiny2313 op PD2.

Nog steeds geen reactie van de led...

Raak ik nu niet in de knoei omdat Port D al als output gedeclareerd is?

Zoja.. hoe maak ik alleen pin PD5 output en PD2 input?

Heb je geen simulator? Zit in AVRstudio standaard in. Even 5 minuten simuleren en je weet waarom de led gelijk aan gaat.

hoe maak ik alleen pin PD5 output en PD2 input?

Je kan daarvoor de sbi en cbi instructies gebruiken. Die werken niet enkel op een I/O-pin, maar ook op het bijbehorende DDR-bit.
Om PD2 als ingang te schakelen hoef je --na een RESET-- niets te doen. Alle I/O-pinnen zijn dan immers als ingang geschakeld.

als je met PB0 wil werken is het PCINT0 die je moet instellen en niet INT0 dat is niet hetzelfde...

ook moet jou Interrupt vector veranderen in .org PCIaddr

kijk eens naar deze oefening dan zie je de instellingen die je nodig hebt...alleen de sleep mode hoef je niet in te stellen.

volgens mij heb je genoeg met deze extra instellingen


        ldi	temp,(1<<PCINT0)	; selecteer PCINT0
	out	PCMSK, temp

	ldi	temp,(1<<PCIE)	        ; PCIE, PCInterrupt enable
	out	GIMSK, temp
 
	sei				; toelaten ( set enable interrupts ) interrupts