PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : interrupt



eric101
06.04.2005, 16:58
Leider gelöschter Text! :o(
Tschuldigung! *autsch -> das muss ja ausgerechnet mir passieren* *heul*

Gruß Florian

Florian
06.04.2005, 18:26
Shit!
Habe gerade einen ganz gravierenden Fehler gemacht!
Ich habe auf edit anstatt auf zitat gedrückt!
Bitte verzeihe mir Eric!
Könntest Du mir Deine Frage nochmals posten, dann werde ich den Text wieder umändern! *auf die Stirn hau*

Florian
06.04.2005, 18:26
Mein Quelcode:
Hi Eric!
Ich finde es ersteinmal sehr schön, dass Du die ASM-Sprache auserwählt hast! *g*
Da Du Dich ja nicht quelen (bzw. quälen) sollst, werde ich Dir helfen! :o)

Als erstes ein kleiner Tipp!
Ich bezeichne die Register immer mit Namen, damit ich sie besser auseinander halten kann, was ganz besonders wichtig bei großen Programmen ist!

Das erste Register nennt man meistens temp, temporäres Register, da es meistens das Hauptarbeitsregister ist.
Du kannst z.B. das Register r16 in temp umbenennen, indem Du folgende Zeile unter die Includes einfügst:
.def temp = r16
Der Befehl wird allerdings nur zur Leserlichkeit genutzt, er wird deshalb nicht im Speicher des AVRs abgelegt!

Nutzt Du eigentlich das AVR-Studio von ATMEL?
Wenn ja, dann brauchst Du nur
.include "2313def.inc" einfügen, es liegt in dem Programm bereits vor!

Die Zeile mit dem .org ist nicht ganz richtig, da hat sich ein kleiner Fehler eingeschummelt!
Es muss wie folgt heißen:
.org 0x000

Den ersten Interrupt bezeichnet man meistens als "reset", das ist aber kein Fehler!

Der IRQ0-Handler ist richtig, würde ich allerdings anders benennen, da es ein weig zu lang ist (für meinen Geschmack), kannst Du aber auch so lassen!

Nun kommst das fehlerhafte Label! ;o)
Für gewöhnlich initalisiert man als erstes den Stack, der beim 2313 ist allerdings so klein, dass man nicht in LOW- und HIGH-Byte unterteilen muss:
ldi temp , RAMEND
out SP , temp
Dann musst Du erst die Ports des AVR einrichten (Eingang oder Ausgang?) und dann die Interrupts aktivieren:
ldi temp, 0b00001010
out MCUCR, temp

ldi temp, 0b11000000
out GIMSK, temp

seiNur alle Interrupts global zu aktivieren reicht nicht aus, Du musst auch noch vorher die externen Interrupts einstellen!

Nun hast Du bei dem nächsten Block noch den Fehler gemacht, dass Du die Konstante 4 versucht hast dierekt in PORTD zu laden, dass musst Du allerdings über einen Umweg machen:
ldi temp , 4
out PORTD , temp

Den selben Fehler hast Du dann auch noch in der Interruptroutine gemacht:
ldi temp, 5
out PORTD , temp
reti

eric101
06.04.2005, 23:10
kein Problem Florian und danke für die Tips!
Ich kann deine Antwort ja unten lesen. Ich werds gleich mal ausprobieren und morgen sagen obs geklappt hat. Den Befehl sbi PORTD, 4 kann ich doch so ausführen, da die 4 in der include datei doch als PB4 definiert ist und dieses bit will ich ja setzen und nicht die konstante 4 rein laden. Seh ich das so richtig?

Meine Frage war:
Also ich hab mir vor einer Woche meinen ersten mikrocontroller gekauft und zwar einen at90s2313 und bis jetzt komm ich auch ganz gut damit klar, nur leider weiss ich nicht genau wie ich einen interrupt richtig programmier. Ich hab mir das so vorgestellt:

.include "C:\Dokumente und Einstellungen\eric\Desktop\asm\2313def.inc"

.cseg
.org 0000
rjmp prg
rjmp interrupt

prg: sei
ldi r16, ramend
out spl, r16
start: sbi PORTD, 4
rjmp start

interrupt: cbi PORTD, 4
sbi PORTD, 5
reti

wenn ich jetzt an int0, also PIN6 einen pegelwechsel hab müsste dann ja auch das bit 5 von Portd gesetzt werden, aber als ich während der kontroller lief 5V an int0 angelegt habe ist nichts passiert.
was genau hab ich falsch gemacht?

eric101
07.04.2005, 13:02
Jetzt funktionierts perfekt! Hab das mit dem MCUCR und GIMSK vorher im Datenblatt garnich realisiert :-k Jetzt is mir aber alles klar. Nochmals vielen dank. Ich werd jetzt versuchen einen Würfel zu basteln. Mal schaun ob ichs schaff O:)

eric101
07.04.2005, 13:04
garnich realisiert wollt ich schreiben :-b
achja, coole smilies =D>

Florian
07.04.2005, 14:39
Hi Eric!
Danke, dass Du mir verziehen hast, ich war gestern so in Eile, dass ich doch glatt den falschen Knopf gedrückt habe! *schmunzel*


Den Befehl sbi PORTD, 4 kann ich doch so ausführen, da die 4 in der include datei doch als PB4 definiert ist und dieses bit will ich ja setzen und nicht die konstante 4 rein laden. Seh ich das so richtig?Ja, da hast Du recht, ich habe in der Eile etwas völlig anderes gelesen! ;o)


Jetzt funktionierts perfekt!Das freut mich zu hören! :o)


Ich werd jetzt versuchen einen Würfel zu basteln. Mal schaun ob ichs schaff O:)Das ist eine recht schwierige Aufgabe!
Wie willst Du die Zufallszahlen generieren?
Eine Möglichkeit wäre über einen Taster die gedrückte Zeit zu messen, bzw. ein Register im gedrücktem Zustand incrementieren zu lassen, dann hat man die Zufallszahl! ;o)
Muss man leider etwas schummeln! *lol*

Viel Erfolg weiterhin! :o)

eric101
07.04.2005, 22:14
ich hab mir gedacht ich lass einen zähler einfach dauerhaft durchlaufen, so schnell wie möglich und im moment des tastendrucks speicher ich die momentanzahl mit hilfe eines interrupts und danach soll der würfel immer langsamer werden und schließlich auf der vorher gemerkten zahl stehen bleiben. Das könnte doch klappen 8-[

Florian
07.04.2005, 22:39
Ja, das kann und wird klappen, davon bin ich überzeugt, allerdings ist es dann keine "richtige Zufallszahl", zumindest nicht im herkömmlichen Sinne!

eric101
11.04.2005, 19:25
hey, hab den Würfel hinbekommen! hab aber das ganze wochende gebraucht, aber jetzt schauts dafür auch richtig gut aus! Als nächstes mach ich mich jetzt an eine gescheite Experementierplatine. Die nächsten Fragen folgen bestimmt 8-[

Florian
11.04.2005, 20:04
Mich würde mal interessieren, wie Du ihn programmiert hast, von der Form her usw.!
Wärst Du bereit den Code hier online zu stellen?
Vielleicht könnte man damit sogar eine Art Tutorial im Artikelbereich machen!

eric101
14.04.2005, 11:26
;Würfel mit 7seg Anzeige;

.include "C:\Dokumente und Einstellungen\eric\Desktop\asm\2313def.inc"


.equ dp=3
.def temp=r16
.def zahl=r17
.def counter=r18
.macro einsaus ;Segmente abhängig von der Platine;
ldi temp, 0b01000001
out PORTB, temp
.endmacro
.macro zweiaus
ldi temp, 0b10110011
out PORTB, temp
.endmacro
.macro dreiaus
ldi temp, 0b10110110
out PORTB, temp
.endmacro
.macro vieraus
ldi temp, 0b11010100
out PORTB, temp
.endmacro
.macro fuenfaus
ldi temp, 0b11100110
out PORTB, temp
.endmacro
.macro sechsaus
ldi temp, 0b11100111
out PORTB, temp
.endmacro



.cseg
.org 0x000
rjmp reset
rjmp int

reset: ldi temp, ramend
out SPL, temp
ldi temp, 0b01000000 ;externer interrupt an int0 wenn int0 auf low liegt(pull up an int0);
out GIMSK, temp
ldi temp, 0b00000000
out MCUCR, temp
sbi PORTB, dp
sei

main: ldi temp, 0x05


dec: nop ;zählschleife;
nop
nop
sbi PORTB, dp ;dp zeigt nacher an ob der Würfelvorgang abgeschlossen ist;
nop
nop
dec temp
breq main
rjmp dec

int: mov zahl, temp ;ermitteln der zahl die in temp war als der Interrupt ausgelöst würde;
ldi temp, 0x00
cpse temp, zahl
rjmp inta
rjmp eins
inta: ldi temp, 0x01
cpse temp, zahl
rjmp intb
rjmp zwei
intb: ldi temp, 0x02
cpse temp, zahl
rjmp intc
rjmp drei
intc: ldi temp, 0x03
cpse temp, zahl
rjmp intd
rjmp vier
intd: ldi temp, 0x04
cpse temp, zahl
rjmp inte
rjmp fuenf
inte: rjmp sechs

eins: einsaus ;durchzählen der 7seg Anzeige für die Optik :) ;
ldi counter, 0x00 ;counter für die Warteschleife null setzen;
rcall warte
zweiaus
rcall warte
dreiaus
rcall warte
vieraus
rcall warte
fuenfaus
rcall warte
sechsaus
rcall warte
einsaus
rcall warte
zweiaus
rjmp entp

zwei: zweiaus
ldi counter, 0x00
rcall warte
dreiaus
rcall warte
vieraus
rcall warte
fuenfaus
rcall warte
sechsaus
rcall warte
einsaus
rcall warte
zweiaus
rcall warte
dreiaus
rjmp entp

drei: dreiaus
ldi counter, 0x00
rcall warte
vieraus
rcall warte
fuenfaus
rcall warte
sechsaus
rcall warte
einsaus
rcall warte
zweiaus
rcall warte
dreiaus
rcall warte
vieraus
rjmp entp

vier: vieraus
ldi counter, 0x00
rcall warte
fuenfaus
rcall warte
sechsaus
rcall warte
einsaus
rcall warte
zweiaus
rcall warte
dreiaus
rcall warte
vieraus
rcall warte
fuenfaus
rjmp entp

fuenf: fuenfaus
ldi counter, 0x00
rcall warte
sechsaus
rcall warte
einsaus
rcall warte
zweiaus
rcall warte
dreiaus
rcall warte
vieraus
rcall warte
fuenfaus
rcall warte
sechsaus
rjmp entp

sechs: sechsaus
ldi counter, 0x00
rcall warte
einsaus
rcall warte
zweiaus
rcall warte
dreiaus
rcall warte
vieraus
rcall warte
fuenfaus
rcall warte
sechsaus
rcall warte
einsaus
rjmp entp

warte: inc counter ;Warteschleife abhängig von der Anzahl der Durchgänge (5Mhz Quarz);
inc counter
mov temp, counter
zaehl3: ldi r19, 0x01
zaehl2: clr r1
zaehl1: clr r0
zaehl0: dec r0
brne zaehl0
dec r1
brne zaehl1
dec r19
brne zaehl2
dec temp
brne zaehl3
ret

entp: in temp, pind ;überprüfen ob schalter noch gedrückt;
ldi r20, 0x04
cpse temp, r20
rjmp entp
ldi temp, 0x03
reti


Das Layout von meiner Schaltung hab ich auch noch, wenns einer will ^^
und wie findest es?

Florian
14.04.2005, 13:45
Das sieht ja richtig gut aus, da hast Du Dir ja ganz schön viel Mühe gegeben! ;o)
Ich gucke den Code nachher mal durch, aber einziger Markel ist die etwas geringe Übersichtlichkeit, etwas besser gliedern, aber das ist Geschmackssache! *lol*

eric101
14.04.2005, 21:06
mach mal bitte ein beispiel wie ich besser gliedern kann, damit ich mich bessern kann O:)

Florian
14.04.2005, 22:15
So z.B.:


.def temp , r16
.def temp2 , r17

.equ cristall , 16000000

.org 0x000
rjmp reset
reti
reti
reti
reti
reti
.
.
.

reset:
port_d:
ldi temp , 0xFF
out PORTD , temp

main:
aufgabe1:
nop
ldi temp , 0xFF
aufgabe2:
nop
ldi temp , 0xFF

underroutines:
aufgabea:
nop
ldi temp , 0xFF
aufgabeb:
nop
ldi temp , 0xFF

interruptroutines:
aufgabeI:
nop
ldi temp , 0xFF
aufgabeII:
nop
ldi temp , 0xFF

eric101
14.04.2005, 22:26
jo hast recht, das is so echt viel übersichtlicher! Merk ich mir

Florian
14.04.2005, 23:43
Schön, dass ich Dir helfen konnte! ;o)