Hallo!
Frohes Neues an alle ;-)
Nachdem der UART nun läuft wollt ich (eigentlich noch vor dem essen :P)
den Timer0 zum laufen bringen.
Hier mein Code:
1
.include "m88def.inc"
2
3
.org 0x0000
4
rjmp main
5
6
.org URXCaddr ; Interruptvektor für UART-Empfang
7
rjmp int_rxc
8
9
.org OVF0addr
10
rjmp timer0_overflow ; Timer Overflow Handler
11
12
13
; Hauptprogramm
14
15
main:
16
nop
17
nop
18
int_rxc:
19
reti
20
timer0_overflow:
21
reti
Die Fehlermeldung, beim compilieren lautet:
D:\Eigene Dateien\Mega88\Mega88ROMTest.asm(33): error: Overlap in .cseg:
addr=0x12 conflicts with 0x12:0x13
Diese tritt übrigens beim zweiten NOP Befehl auf
Was mache ich nun schon wieder falsch?
Hallo,
einmal siehe Marius Wensing (mw1987), ist aber nicht die Ursache für die
Fehlermeldung.
Geh doch den Ablauf für den Assembler einfach mal "zu Fuß" durch:
.org 0x0000 -> assembliere an Adresse 0x0000
rjmp main
.org URXCaddr -> assembliere ab Adresse 0x0012 ***
rjmp int_rxc
.org OVF0addr -> asssembliere ab Adresse 0x0010
rjmp timer0_overflow
-> der Assembler ist jetzt bei Adresse 0x0012 ***
ab hier soll er jetzt aber Deine main übersetzen, kann er aber nicht,
weil Du ihm schon gesagt hast, daß dort der rjmp int_rxc hinsoll...
Siehe Vectorliste im Datenblatt.
Entweder die Vektoren in der Reihenfolge ihres Auftretens zuweisen, also
die Reihenfolge von
.org URXCaddr -> assembliere ab Adresse 0x0012 ***
rjmp int_rxc
und
.org OVF0addr -> asssembliere ab Adresse 0x0010
rjmp timer0_overflow
vertauschen oder
alle Vektoren in ihrer Reihenfolge eintragen
oder aber per .org vor der main festlegen, wo der Assembler weitermachen
soll. Geht am Besten mit
.org INT_VECTORS_SIZE
vor main.
Ist in den AVR-includes definert auf die Länge der Vector-Liste.
Gruß aus Berlin
Michael
Hi
>So wird das ja auch nix.>Das ist kein lauffähiges Programm.
Quatsch. Das interessiert des Assembler herzlich wenig.
>.org URXCaddr ; Interruptvektor für UART-Empfang> rjmp int_rxc>.org OVF0addr> rjmp timer0_overflow ; Timer Overflow Handler
Du kannst die .org nichr beliebig mischen
.org OVF0addr
rjmp timer0_overflow ; Timer Overflow Handler
.org URXCaddr ; Interruptvektor für UART-Empfang
rjmp int_rxc
OVF0addr ist kleiner als org URXCaddr. Damit platzierst du dein Main
zwischen den beiden Adressen und dein Code überschneidet sich mit 'rjmp
int_rxc'
Die Reihenfolge muss den Interruptvektoren entsprechen.
MfG Spess
spess53 wrote:
> Die Reihenfolge muss den Interruptvektoren entsprechen.>> MfG Spess
um dich mal zu zitieren:
> Quatsch. Das interessiert des Assembler herzlich wenig.
;)
Das einzige was man tun muß ist den Einsteigspunkt für die Main an die
richtige stelle setzen nämlich INT_VECTORS_SIZE...
Hi
> MfG Spess
um dich mal zu zitieren:
> Quatsch. Das interessiert des Assembler herzlich wenig.
Dann sieh dir mal an, worauf sich das bezogen hat.
Ich weiss nicht, wer dieses .org-Gedödel erfunden hat (wahrscheinlich
der Gleiche mit den 'tempxy'). Die Datenblattvariante wäre weniger
irreführend gewesen.
MfG Spess
Hallo,
@spess53: ich finde das .org-Gedödel durchaus praktisch, auch die
tempxy, allerdings heißen die bei mir TEMP_0 usw. ;-)
Warum soll ich x IRQ-Vectoren reinschreiben, wenn ich nur einen brauche?
Ja, man kann die kopieren, aber ich finde es lesbarer, wenn eben dann
nur einer oder zwei dastehen.
Und seit Atmel netterweise INT_VECTORS_SIZE in den includes hat, erspart
es selbst bei Änderungen auf eine andere CPU dann dort unnötige
Korrekturen.
Gruß aus Berlin
Michael
Hi
>Warum soll ich x IRQ-Vectoren reinschreiben, wenn ich nur einen brauche?
Muss ich nicht. Ich kann mein Programmgerüst aus den XML-Dateien des
AVR-Studios erzeugen.
> auch die tempxy, allerdings heißen die bei mir TEMP_0 usw. ;-)
Registerdefinitionen sind vielleicht bei kleinen Programmen hilfreich.
Bei grösseren empfinde ich sie als störend. Wenn ein Register in einem
Programm zig verschiedene Inhalte haben kann, muss ich entweder dauernd
umdefinieren oder mit irrführenden Bezeichnungen leben. Beides ist für
mich inakzeptabel.
MfG Spess
Läubi Mail@laeubi.de wrote:
> Das einzige was man tun muß ist den Einsteigspunkt für die Main an die> richtige stelle setzen nämlich INT_VECTORS_SIZE...> Man kann die Vektoren dann beliebig anordnen...
Es geht sogar noch einfacher und übersichtlicher.
Man muß nicht umständlich alle Vektoren in ein File eintragen, sondern
kann das auch erst direkt dort machen, wo man den Interrupthandler
definiert.
Das geht am besten mit einem kleinen Macro:
1
.nolist
2
.include "m88def.inc"
3
.listmac
4
.list
5
6
.macro INTHAND
7
.set _curr_addr = pc
8
.org @0
9
rjmp _curr_addr
10
.org _curr_addr
11
.endmacro
12
13
14
.org 0x0000
15
rjmp main
16
.org INT_VECTORS_SIZE
17
main:
18
;...
19
rjmp main
20
;...
21
INTHAND URXCaddr
22
; handler code
23
reti
24
;...
25
INTHAND OVF0addr
26
; handler code
27
reti
Das spart dann auch das Ausdenken eines Labels für den Handler.
Peter
Hi
Langsam dämmert es mir. Man muss also Assembler nur so unverständlich
wie möglich zu machen, um den Einsatz sog. Hochsprachen zu
rechtfertigen. Interessante Strategie.
MfG Spess
Xundes Neues...
> Man muss also Assembler nur so unverständlich> wie möglich zu machen, um den Einsatz sog. Hochsprachen zu> rechtfertigen.
Hmmm... Da scheint was dran zu sein.
Das ist dann für mich ein Grund mehr, bei einfachem verständlichem
überschaubarem Hobbybastler-ASM zu bleiben und wie bisher die komplette
Interrupt-Vektorliste zu kopieren.
~
spes53 wrote:
> Langsam dämmert es mir. Man muss also Assembler nur so unverständlich> wie möglich zu machen, um den Einsatz sog. Hochsprachen zu> rechtfertigen. Interessante Strategie.
Ich vermute mal, Du bist ein Einzelkämpfer und hast daher weder die
Notwendigkeit noch das Interesse, Deine Programme für andere besser
lesbar und verstehbar zu machen.
Defines und Macros helfen aber nicht nur anderen, sondern auch einem
selber, ältere Programme wieder schnell verstehen zu können.
Du hast natürlich recht, daß diese Hilfen ihren Ursprung in Hochsprachen
haben.
Aber warum soll man denn nicht auch nützliche Dinge bei der
Assemblerprogrammierung verwenden?
Assembler muß nicht automatisch spartsanisch und unübersichtlich sein.
Insbesondere, da ja neuere AVRs einige IO-Register im SRAM haben, ist
ein Zugriffsmacro sinnvoll, welches automatisch IN/OUT bzw. LDS/STS
benutzt.
Peter
@Peter:
Interessanter Ansatz. Einfach (wenn man den Preprozessor verstanden hat
;) ) und effektiv. Das Makro dürfte vor allem wenn man für ein neues
Feature in der Anwendung plötzlich doch noch ein paar Interrupts mehr
benutzen möchte praktisch sein.
Danke für den Tip!
Für den Anfang bzw. zum lernen dürfte allerdings der Datenblatt-Ansatz
günstiger sein, da man hier den Aufbau der Interrupt-Vektortabelle
ständig vor Augen hat und sich nicht mit vom verwendeten Assembler
abhängigen Konstrukten beschäftigen muss.
Hallo!
Also es tut mir leid dass ich mich nicht für die Makro-Variante sondern
für die einfache, die Adressen nach der Vektortabelle zu sortieren,
entschieden habe... vielleicht später mal mit Makro ;-)
Eigentlich wollte ich jetzt nach so einer Interrupt-Vektortabelle
fragen, ich habe die zwar irgendwo schon einmal gesehen, wusste aber
nicht mehr wo. Nun, da ihr ja aber entweder Gedanken lesen könnt oder in
die Zukunft sehen, habt ihr die Tabelle ja schon geposted bevor ich die
Frage stellen konnte :-)
Der Timer läuft nun, Interrupt wird ausgelöst, trotzdem noch eine Frage:
Ich habe am Mega88 ein Quarzoszillator angeschlossen, 1.8 GHZ für RS232.
Der Timer0 läuft ohne Prescale. In der Interrupt Routine zähle ich dann
noch ein Register hoch. Wenn dieses kleiner als 128 ist, schalte ich die
LED an , andernfalls aus.
So etwa:
1
...
2
ldi r16, 0b00000001 ; Timer enable - Kein Prescale
3
sts TCCR0B, r16
4
5
ldi r16, 0b00000001 ; TOIE0: Interrupt bei Timer Overflow
6
sts TIMSK0, r16
7
8
sei
9
10
11
...
12
13
14
timer0_overflow:
15
lds r17, PWM
16
17
lds R16, LED1
18
cp r16, r17
19
20
BRLO Led1AUS
21
sbi PORTC,0 ;LED1 AN
22
rjmp LED2Test
23
LED1AUS: cbi PortC,0 ;LED1 AUS
24
25
26
LED2Test:
27
28
inc R17
29
sts PWM, R17
30
31
32
reti
33
34
...
OK, die "..." bedeuten, dass da noch mehr Code steht :-)
Das ich auch die Register R16 und R17 nicht sichere, ist mir auch
bewusst (mach ich jetzt gleich).
Zur Frage:
Die LED sollte doch jetzt so schnell blinken, dass ich es mit dem Auge
nicht sehen kann, oder? Aber aus irgendeinem Grund ist die Frequenz so
niedrig, dass ich sie flackern sehe? Wieso?
Meine letztes Posting könnte zur Verwirrung sorgen:
"out TCCR0B, r16
nicht
STS TCCR0B, r16
muss es heißen ;-)"
Bezieht sich auf einen COPY/Paste Fehler, der mir passiert ist, als ich
den Code oben eingefügt habe. Soll aber NICHT heißen, dass das Problem
"flackern" mit dieser Änderung gelöst ist....
>Die LED sollte doch jetzt so schnell blinken, dass ich es mit dem Auge>nicht sehen kann, oder?
Was für ein Ergebnis spuckt denn Deine Berechnung der Blinkfrequenz aus?
Ich komme auf 1843200 Hz : 256 : 256 = 28.125 Hz.
Eine mit dieser Frequenz bestromte LED wird nicht mehr als blinkend,
sondern als dauerleuchtend, aber mit deutlichem Flimmern empfunden.
>Aber aus irgendeinem Grund ist die Frequenz so>niedrig, dass ich sie flackern sehe? Wieso?
Wenn sich Deine LED eher schnell blinkend präsentiert, dann ist
höchstwahrscheinlich die CKDIV8-Fuse enabled. Dann läuft Dein Controller
nur mit 1843200/8 Hz und die LED mit ca. 3.5 Hz.
Hast Du eine Digitalkamera? Dann kannst Du die Frequenz leicht messen.
Dazu darfst Du keinen Automatik-Modus verwenden, sondern musst die
Verschlusszeit von Hand z. B. auf 1 Sekunde festsetzen. Dann die Kamera
gleichmäßig während das Bild aufgenommen wird in größerem Abstand über
die blinkende LED hinwegziehen. Sozusagen eine Luftaufnahme machen, mit
Deinen Händen als "Flugzeug". Ergibt ein Bild wie im Anhang. Hier war
die Verschlusszeit 1 s, und um die Blinkfrequenz der untersten LED zu
bestimmen, musst Du nur die gelben Streifchen zählen. Sie hat mit 20 Hz
geblinkt.
Hallo!
Das mit der Kamara ist eine gute Idee... das werde ich mal testen.
CKDIV8-Fuse ist nicht gesetzt. Wenn ich es setze, blinken die LEDs
wirklich...
Zur Frequenzberechnung:
Ich dachte es wäre: 1843200 Hz : 256 : 2 =3600 HZ ?
Mit meinem Zähler (PWM = R17) teile ich doch nicht mehr durch 256
sondern lediglich durch 2, oder?
Oder habe ich da einen Denkfehler drin?
Ist natürlich Quatsch... du hast Recht!
War ein Denkfehler von mir.
Ich muss den Zähler dann ja nur bis zb 128 zählen lassen, dann
verdoppelt sich die Frequenz.
56 Hz müsste man dann nicht mehr blinken sehen können, denke ich mal...
>56 Hz müsste man dann nicht mehr blinken sehen können
Nein, bei 40 Hz flirrt es noch ein ganz kleines bisschen, aber oberhalb
ca. 50 Hz wirst Du das Leuchten als flimmerfrei wahrnehmen.
Die Kameramethode ist übrigens bis ca. 1 kHz praktikabel. Wenns mehr
sein soll, braucht man dann doch einen Frequenzzähler ;-)
Silver69 wrote:
> Also es tut mir leid dass ich mich nicht für die Makro-Variante sondern> für die einfache, die Adressen nach der Vektortabelle zu sortieren,> entschieden habe... vielleicht später mal mit Makro ;-)
Braucht Dir nicht leid zu tun, es gibt ja viele Wege, etwas zu tun.
Man sollte bloß nicht wie manch anderer sagen: "Alles was ich nicht
benutzte, ist Mist", sondern auch mal andere Meinungen zulassen.
Der Grund, warum ich Macros bevorzuge, ist auch, daß ich viele
verschiedene AVRs benutze und dann sind die Vektortabellen
unterschiedlich.
Wenn Dir z.B. der Flash ausgeht und Du schnell mal auf den ATmega168
upgraden willst, zeigt Deine Vektortabelle in den Wald.
Die .ORG-Anweisungen stimmen dagegen immer noch.
Peter