Ich habe einen Assembler Code geschrieben, der per Uart daten empfängt
und dann die daten per pwm an leds ausgibt. Die daten werden vom
Programm Atmolight empfangen. Das ganze funktioniert auch, allerdings
flackert die Led ziemlich stark, ich vermute es hängt damit zusammen,
dass die Pwm durch den Uart empfang gestört wird.
Gibts es eine Möglichkeit Uart-Empfang und PWM gleichzeitig ablaufen zu
lassen? Immoment habe ich zwei interrupts, die ausgelöst werden, eine
für den Uart-Empfang und eine für die PWM.
Ich komm nicht wirklich weiter, wär nett, wenn jemand ne Idee hat. Ich
verwende einen Atmega8.
ldi temp, 0b00000001 ; TOIE0: Interrupt bei Timer Overflow
39
out TIMSK, temp
40
41
; Port D = Ausgang
42
43
ldi temp, 0xFF
44
out DDRD, temp
45
46
; Baudrate einstellen
47
48
ldi temp, HIGH(UBRR_VAL)
49
out UBRRH, temp
50
ldi temp, LOW(UBRR_VAL)
51
out UBRRL, temp
52
53
; Frame-Format: 8 Bit
54
55
ldi temp, (1<<URSEL)|(3<<UCSZ0)
56
out UCSRC, temp
57
58
sbi UCSRB, RXCIE ; Interrupt bei Empfang
59
sbi UCSRB, RXEN ; RX (Empfang) aktivieren
60
61
sei ; Interrupts global aktivieren
62
63
loop:
64
rjmp loop ; Endlosschleife
65
66
timer0_overflow: ; Timer 0 Overflow Handler
67
inc PWMCount ; den PWM Zähler von 0 bis
68
cpi PWMCount, 255 ; 255 zählen lassen
69
brne WorkPWM
70
clr PWMCount
71
72
WorkPWM:
73
ldi temp, 0b11000000 ; 0 .. Led an, 1 .. Led aus
74
75
cp PWMCount, ocr_1 ; Ist der Grenzwert für Led 1 erreicht
76
brlo OneOn
77
ori temp, $01
78
79
OneOn: cp PWMCount, ocr_2 ; Ist der Grenzwert für Led 2 erreicht
80
brlo TwoOn
81
ori temp, $02
82
83
TwoOn: cp PWMCount, ocr_3 ; Ist der Grenzwert für Led 3 erreicht
84
brlo ThreeOn
85
ori temp, $04
86
87
ThreeOn:cp PWMCount, ocr_4 ; Ist der Grenzwert für Led 4 erreicht
88
brlo FourOn
89
ori temp, $08
90
91
FourOn: cp PWMCount, ocr_5 ; Ist der Grenzwert für Led 5 erreicht
92
brlo FiveOn
93
ori temp, $10
94
95
FiveOn: cp PWMCount, ocr_6 ; Ist der Grenzwert für Led 6 erreicht
96
brlo SetBits
97
ori temp, $20
98
99
SetBits: ; Die neue Bitbelegung am Port ausgeben
100
out PORTC, temp
101
102
reti
103
int_rxc:
104
bit1:
105
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
106
rjmp bit1
107
in r24, UDR ; empfangenes Byte nach temp kopieren
108
cpi r24, 0xFF
109
brne bit1
110
bit2:
111
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
112
rjmp bit2
113
in r24, UDR ; empfangenes Byte nach temp kopieren
114
cpi r24, 0x00
115
brne bit1
116
bit3:
117
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
118
rjmp bit3
119
in r24, UDR ; empfangenes Byte nach temp kopieren
120
cpi r24, 0x00
121
brne bit1
122
bit4:
123
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
124
rjmp bit4
125
in r24, UDR ; empfangenes Byte nach temp kopieren
126
cpi r24, 0x0F
127
brne bit1
128
bit5:
129
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
130
rjmp bit5
131
in ocr_4, UDR ; empfangenes Byte nach temp kopieren
132
bit6:
133
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
134
rjmp bit6
135
in ocr_2, UDR ; empfangenes Byte nach temp kopieren
136
bit7:
137
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
138
rjmp bit7
139
in ocr_3, UDR ; empfangenes Byte nach temp kopieren
140
bit8:
141
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
142
rjmp bit8
143
in r25, UDR ; empfangenes Byte nach temp kopieren
144
bit9:
145
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
146
rjmp bit9
147
in r25, UDR ; empfangenes Byte nach temp kopieren
148
bit10:
149
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
150
rjmp bit10
151
in r25, UDR ; empfangenes Byte nach temp kopieren
152
bit11:
153
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
154
rjmp bit11
155
in r25, UDR ; empfangenes Byte nach temp kopieren
156
bit12:
157
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
158
rjmp bit12
159
in r25, UDR ; empfangenes Byte nach temp kopieren
160
bit13:
161
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
162
rjmp bit13
163
in r25, UDR ; empfangenes Byte nach temp kopieren
164
bit14:
165
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
166
rjmp bit14
167
in r25, UDR ; empfangenes Byte nach temp kopieren
168
bit15:
169
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
170
rjmp bit15
171
in r25, UDR ; empfangenes Byte nach temp kopieren
172
bit16:
173
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
174
rjmp bit16
175
in r25, UDR ; empfangenes Byte nach temp kopieren
176
bit17:
177
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
178
rjmp bit17
179
in r25, UDR ; empfangenes Byte nach temp kopieren
180
bit18:
181
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
182
rjmp bit18
183
in r25, UDR ; empfangenes Byte nach temp kopieren
184
bit19:
185
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
186
rjmp bit19
187
in r25, UDR ; empfangenes Byte nach temp kopieren
188
reti
Das ist mein Quellcode, hab ihn nicht gleich geschickt, weil ich mich
etwas dafür schäme:-(. Ist aus dem tutorial zusammen gebastelt. Die
braucht doch aber einen Timer, und während ich per Uart empfange,
funktioniert dieser Timer doch nicht oder?
sbis UCSRA, RXC ; warten bis ein Byte angekommen ist
4
rjmp bit2
In Interrupts wird grundsätzlich auf irgendwas gewartet!
>und während ich per Uart empfange, funktioniert dieser Timer doch nicht >oder?
Doch. Aber wenn du im uart-int wartest, bis weitere bytes eintrudeln,
kannst du natürlich deine soft-pwm nicht bedienen!
OMG, wo wird nur solcher Programmierstil gelehrt...
Im UART-Interrupt wird der Inhalt von UDR ausgelesen und in einen Puffer
gelegt, mehr nicht.
Die Mainloop überprüft zyklisch diesen Puffer, ob das darin enthaltene
Telegramm vollständig und damit gültig ist. Ist es gültig, dann wird es
ausgewertet (an die PWM-Sollwerte zugewiesen) und dabei gelöscht
(RX-Pufferzeiger auf Start).
Die Timer-ISR lässt sich auch noch optimieren. Da ein Register (Byte)
nur einen Wertebereich von 0 bis 255 hat, muss der Zählumfang nicht
begrenzt werden, nach 255 kommt nunmal 0. Die Vergleichsergebnisse der
einzelnen Kanäle landen im Carry-Flag. Durch Einrotieren in ein Register
(ROR oder ROL) kann man die Carry-Zustände "einsammeln" und in einem
Rutsch an den Port ausgeben. Das erspart eine Menge Branches.
...
>Die Vergleichsergebnisse der einzelnen Kanäle landen im Carry-Flag.
Das ist ne interessante Idee, aber mal so für mich gefragt: Wie macht
man das in C ?
>OMG, wo wird nur solcher Programmierstil gelehrt...
Das ist die Frage. Nennt sich Spaghetti-Code.
> Wie macht man das in C ?
Hmmm, der AVR kann kein C...
Ich auch nicht...
Also stellt sich die Frage nicht. ;-D
Wurde C (ANSI-C) nicht für 16-Bit-Maschinen gemacht?
Läuft es auf 8-Bit-Controllern nur durch standardfremde Erweiterungen?
Sind diese Erweiterungen nicht auch von Version zu Version
unterschiedlich?
Gibt es nicht andauernd Probleme, weil ein "gefundenes" C-Projekt mit
dem heimischen Compiler nicht compilierbar ist?
Also lasse ich C C sein und werkele in ASM... ;-)
Mögen mich die Fachleute dafür steinigen, ich werde es überleben...
...
hannes lux wrote:
>Wurde C (ANSI-C) nicht für 16-Bit-Maschinen gemacht?
Nein. Das hängt wohl eher vom Compiler ab.
C funktioniert auf 8, 16, 32, 64, ... Bit System oder was immer es auch
noch gibt.
>Läuft es auf 8-Bit-Controllern nur durch standardfremde Erweiterungen?
Was meinst du mit "stanardfremd"? Ja, es gibt Compiler abhängige C
Direktiven, die dem Programmierer z.B. erlauben einen Variable an eine
bestimmte Speicheradresse zu legen.
>Sind diese Erweiterungen nicht auch von Version zu Version>unterschiedlich?
Von Compiler zu Compiler unterschiedlich.
Aber du kannst ja auch den Assembler für AVRs nicht auf einem Mircochip
PIC verwenden.
Bei C kannst du den C Code von einem Controller auf den anderen
portieren, natürlich muss man die Startup-Funktionen, die Register
Initialisierungen und die Port Konfiguration anpassen, aber das dürfte
ja klar sein. Das schönste ist aber, dass man z.B. seine funktionierende
Display-Ansteuerung nicht neu schreiben muss. Selbst, wenn dein
Assembler Code super abstrahiert sein sollte.. wenn einfach der
Assembler ein anderer ist, ist er für einen anderen Controller
"unbrauchbar".
>Gibt es nicht andauernd Probleme, weil ein "gefundenes" C-Projekt mit>dem heimischen Compiler nicht compilierbar ist?
Siehe oben. Diese Probleme gibt es eher bei Assembler, das ist kein
"C-Problem".
C ist eine sogenannte "Hochsprache". C ist zwar Maschinen NAH aber es
ist keine konkrete Maschinensprache wie Assembler. Deshalb kann man
funktionalen C-Code auf vielen verschiedenen Plattformen einsetzen.
Diesen Vorteil solltest du dir mal klar machen.
Gruss
@Schobbe, es tut mir leid, dass Du auf meinen Spruch angesprungen bist,
er war für Lippi gedacht, es war ja eine (humorige) Antwort auf seine
(humorige) Frage. Es ging darum, die für einfachste ASM-Aufgaben in C
erforderlichen Verrenkungen ins (scherzhaft-)Lächerliche zu ziehen. Das
C eine Hochsprache ist, ist mir auch schon aufgefallen, der K&R liegt
hier auch irgendwo in Reichweite.
Wenn ich 40 Jahre jünger wär und mit Programmierung meine Brötchen
verdienen müsste, dann würde ich Dir recht geben, wobei mir Deine
Argumente alle bekannt sind, Du hast mir also nichts Neues gesagt. Das
ist aber nicht der Fall (40 Jahre jünger und Profi), daher kann ich mir
fürs Hobby die Controllerfamilie selbst aussuchen, es sind nunmal AVRs.
PICs, 8051er oder Motorolas (nur um einige andere 8-Bitter zu nennen)
und die ganzen 16/32-Bitter interessieren mich nicht, denn ich gehöre
nicht zu den Nachbauern, sondern zu den Selbermachern, da bin ich
ungebunden...
Ich hatte nunmal Kontakt zu BASIC und 6502-Assembler, bevor ich
irgendwelche Infos über C bekam, daher programmiere ich PCs in BASIC und
AVRs in ASM. Die paar Jahre, die mir noch bleiben, werde ich auch noch
auf C verzichten können.
Also, nix für ungut...
...
@hannes
Das war auch nicht böse gemeint.
Ich hatte nur nicht den ironischen Kontext deines Beitrags raus gelesen.
;-)
Du hast natürlich vollkommen Recht für Hobby / Bastler ist die
Programmierung ein Werkzeug. Auch der Mikrocontroller ist nur ein
Werkzeug um eine Aufgabe zu erfüllen. Deshalb ist es auch vollkommen
legitim, dass jeder das Werkzeug benutzt das er am besten beherrscht.
Und wenn man mal ehrlich ist, dann ist für die meisten kleineren
Anwendungen zu Hause ein 8 Bit Controller vollkommen ausreichend.
Bei mir ist es fast andersrum, ich habe zwar mal Assembler gelernt 8051
und PIC. Aber mittlerweile mache ich alles in C. Manchmal wäre es aber
ganz gut nochmal etwas in Assembler umzusetzen, weil, wie du schon
geschrieben hast, da hat man alles in der Hand. Da funkt dir kein
Compiler dazwischen.
Ab einer gewissen Größe würde ich es mir einfach gar nicht mehr zu
trauen, etwas in Assembler zu schreiben, ganz einfach weil mir da die
Erfahrung fehlt.
Aber so oder so. Man kann in Assembler schlecht programmieren und in C,
auch in C++, Java, C#, Pascal oder Delphi.. schlechter Code lässt sich
mit jeder Programmiersprache erzeugen.
Um mal wieder zu diesem Thread zurück zu kommen :) (der ja in Assembler
verfasst ist...)
Aktiv in einem Interrupt auf etwas zu warten, lässt sich auch in C
realisieren :-) aber ist da natürlich genauso böse..
Wie schon geschrieben wurde: Im UART Rx Interrupt das Rx Register
auslesen und in einen Puffer schreiben. Dann raus aus der Interrupt
Routine.
Gruss
habe mich jetzt doch dafür entschieden die hardware pwm zu benutzen.
OCR1A und OCR1B funktionieren auch schon. Jetzt bin ich grade dran den
Timer 2 für OCR2 zu initialisieren und kriege dass irgendwie nicht
richtig hin. kann mir jemand die init für Timer 2 in assembler schreiben
oder sagen was ich da machen muss?
Vielen Dank