8pwm2.asm


1
;Demoprogramm für 8-fach-PWM mit Tastensteuerung und Pollin-LCD 4x27.
2
3
;8 LEDs gegen Vcc an Port B (STK500)
4
;4 entprellte Tasten gegen GND für die einzelnen PWM-Kanäle an Port C
5
;Davon 2 Tasten (Dimm-Tasten) mit Repeat-Funktion bei Dauerdruck.
6
;LCD 4x27 an Port D
7
8
.nolist                     ;List der Include-Datei unterdrücken
9
.include "m8515def.inc"     ;vereinbarte Namen verwenden (lt. Datasheet)
10
.list                       ;Programm listen
11
.listmac                    ;Makros listen
12
.equ clock = 8000000        ;Taktfrequenz 8Mhz
13
14
15
.equ pwu = 100              ;PWM-Zählumfang (sollte 100 sein wegen %)
16
.equ timerwert = -100       ;Timer-Startwert (Reload)-100
17
.equ step=1                 ;Schrittweite für Änderung pro Tastendruck
18
.equ lep=portb              ;Port für LEDs
19
.equ tap=pinc               ;Tastenport
20
    .equ ruck      = 4          ;Taste zurück (braucht kein Mensch...)
21
    .equ dimplus   = 3          ;Taste Dimmen plus  
22
    .equ dimminus  = 2          ;Taste Dimmen minus
23
    .equ chanplus  = 1          ;Taste Kanal hoch
24
    .equ chanminus = 0          ;Taste Kanal runter
25
.equ dimtast=(1<<dimplus)|(1<<dimminus) ;Maske auf Dimm-Tasten
26
;.equ alltast=dimtast|(1<<chanplus)|(1<<chanminus)|(1<<ruck)
27
.equ alltast=255
28
29
.equ twz0=250               ;Startwert Tastendruckdauer
30
.equ twz1=30                ;Wiederholwert für Tasten
31
32
;Array mit 8 Sollwerten in Registern, damit die Software-PWM schnell wird
33
.def soll0 = r0             ;Sollwert Kanal 1
34
.def soll1 = r1             ;Sollwert Kanal 2
35
.def soll2 = r2             ;Sollwert Kanal 3
36
.def soll3 = r3             ;Sollwert Kanal 4
37
.def soll4 = r4             ;Sollwert Kanal 5
38
.def soll5 = r5             ;Sollwert Kanal 6
39
.def soll6 = r6             ;Sollwert Kanal 7
40
.def soll7 = r7             ;Sollwert Kanal 8
41
42
.def tsw = r8               ;Timer-Startwert
43
.def sregtemp = r9          ;Sicherheitskopie SREG
44
45
.def tz0 = r11              ;Tasten-Prellzähler Bit0
46
.def tz1 = r12              ;Tasten-Prellzähler Bit1
47
.def tas = r13              ;Tastenstatus (gültig)
48
.def null = r14             ;immer 0 
49
.def kanal = r15            ;aktuelle Kanalnummer
50
51
.def temp = r16             ;temporär (exklusiv in der ISR)
52
.def tfl = r17              ;Flags für Tasten, die gedrückt wurden
53
.def twz=r18                ;Tasten-Wiederholzähler
54
55
.def pwz = r22              ;PWM-Zähler
56
.def flags = r23            ;Steuerflags
57
    .equ lcdcontroller1 = 6     ;Flag für Controller 1
58
    .equ lcdcontroller2 = 5     ;Flag für Controller 2
59
60
.def wl=r24                 ;Working L
61
.def wh=r25                 ;Working H
62
63
64
.cseg
65
.org 0              ;Reset- und Interrupt-Vektoren AT-Mega 8515
66
 rjmp RESET         ;Reset Handler
67
 rjmp nix;EXT_INT0      ;IRQ0 Handler
68
 rjmp nix;EXT_INT1      ;IRQ1 Handler
69
 rjmp nix;TIM1_CAPT     ;Timer1 Capture Handler
70
 rjmp nix;TIM1_COMPA    ;Timer1 Compare A Handler
71
 rjmp nix;TIM1_COMPB    ;Timer1 Compare B Handler
72
 rjmp nix;TIM1_OVF      ;Timer1 Overflow Handler
73
 rjmp TIM0_OVF      ;Timer0 Overflow Handler
74
 rjmp nix;SPI_STC       ;SPI Transfer Complete Handler
75
 rjmp nix;USART_RXC     ;USART RX Complete Handler
76
 rjmp nix;USART_UDRE    ;UDR0 Empty Handler
77
 rjmp nix;USART_TXC     ;USART TX Complete Handler
78
 rjmp nix;ANA_COMP      ;Analog Comparator Handler
79
 rjmp nix;EXT_INT2      ;IRQ2 Handler
80
 rjmp nix;TIM0_COMP     ;Timer0 Compare Handler
81
 rjmp nix;EE_RDY        ;EEPROM Ready Handler
82
 rjmp nix;SPM_RDY       ;Store Program memory Ready Handler
83
nix:                    ;unbenutzte Interrupts
84
 rjmp nix
85
 reti                   ;zurück...
86
87
88
.include"LCD_4x27.inc"      ;LCD-Routinen für 4-Zeilen-LCDs mit HD44780
89
90
;Da nur wenige LCD Ausgabefunktionen benötigt werden, wurde auf das Einbinden
91
;der Ausgaberoutinensammlung verzichtet und die beiden benötigten Routinen
92
;und deren Macros hier heschrieben. Auf Registersicherung wurde verzichtet,
93
;da die Ausgabe nur in der Initialisierung bzw. der Mainloop erfolgt. 
94
;Die 8-Bit-Ausgaberoutine wurde so verändert, dass die Zahl immer drei
95
;Ausgabepositionen belegt, also eine feste Breite hat, Ist die erste Ziffer
96
;eine 0, so wird sie als Leerzeichen ausgegeben. Damit ist die Anzeige von
97
;00% bis 100% möglich, ohne dass die Ausgabeposition flattert.
98
99
.macro print83 ;Reg.
100
 mov xl,@0                  ;Quellregister kopieren
101
 rcall lcd_print83          ;Routine aufrufen
102
.endmacro
103
104
105
.macro printf   ;Startadresse des Strings im Flash als Label
106
                ;Gibt einen String aus dem Flash an LCD aus
107
                ;Ein Parameter beschreibt die Startadresse, das Ende ist $00
108
 ldi zh,high(2*@0)          ;Pointer
109
 ldi zl,low(2*@0)           ;setzen
110
 rcall lcd_printf           ;Aufruf...
111
.endmacro
112
113
114
lcd_print83:    ;gibt Wert in XL dreistellig aus (mit Führungsleerzeichen)
115
 ldi wl,-1+'0'              ;Hunderter-Stelle als ASCII-Zeichen, Zahl ist pos.
116
 inc wl                     ;Hunderter hoch und
117
 subi xl,100                ;100 subtrahieren bis zum Unterlauf
118
 brsh pc-2                  ;Unterlauf? nein, 2 Zeilen hoch
119
 cpi wl,'0'                 ;ja, ist Ziffer = "0"?
120
 brne pc+2                  ;nein, nicht verändern...
121
 ldi wl,' '                 ;ja, durch Leerzeichen ersetzen
122
 rcall lcd_data             ;Hunderter ausgeben...
123
 ldi wl,10+'0'              ;Zehner-Stelle als ASCII-Zeichen, Zahl ist neg.
124
 dec wl                     ;Zehner runter und
125
 subi xl,-10                ;10 addieren bis zum Überlauf
126
 brlo pc-2                  ;Überlauf? nein, 2 Zeilen hoch...
127
 rcall lcd_data             ;ja, Zehner Stelle ausgeben...
128
 ldi wl,'0'                 ;ASCII-0
129
 add wl,xl                  ;Einer addieren (Rest war ja positiv)
130
 rcall lcd_data             ;Einer ausgeben...
131
 ret                        ;zurück
132
133
134
lcd_printf:     ;Wird vom Makro aufgerufen. Gibt Flash-String an LCD aus.
135
 push wl
136
 lpm wl,z+                  ;Zeichen holen
137
 tst wl                     ;Ende-Kennung? 
138
 breq pc+3                  ;ja...
139
 rcall lcd_data             ;nein, ausgeben
140
 rjmp pc-4                  ;nochmal
141
 pop wl
142
 ret
143
144
;----------------------------------------------------------------------------
145
146
reset:
147
;Stackpointer initialisieren:
148
 ldi wl,low(ramend)         
149
 out SPL,wl
150
 ldi wl,high(ramend)
151
 out SPH,wl
152
;PWM-Ausgänge (LEDs) initialisieren:
153
 ldi wl, 0xff               ;Port für LEDs (PWM-Ausgänge)
154
 out lep-1,wl               ;= Ausgang (DDRx=PORTx-1)
155
;Tasten-Eingänge initialisieren:
156
 ldi wl, alltast            ;pull-ups für Tasten 
157
 out tap+2,wl               ;einschalten (PORTx=PINx+2)
158
;Die Initialisierung der LCD-Ports erfolgt in der LCD-Include-Datei!!!
159
160
;alle 8 PWMs erstmal auf 0
161
 clr soll0
162
 clr soll1
163
 clr soll2
164
 clr soll3
165
 clr soll4
166
 clr soll5
167
 clr soll6
168
 clr soll7
169
170
 clr null                   ;immer 0 
171
 clr tz0                    ;Definierte Startbedingung 
172
 clr tz1                    ;für Tastenentprellung
173
 clr tas
174
 clr tfl
175
 clr twz
176
 clr kanal                  ;mit Kanal 1 (0) beginnen
177
178
;Initialisierung Timer0
179
 ldi wl,1                   ;Vorteiler 1:1
180
 out tccr0,wl               ;für Timer0
181
 ldi wl,1<<toie0            ;Überlauf-Interrupt
182
 out timsk,wl               ;für Timer0 freigeben
183
 ldi wl,timerwert+12        ;Timer-Startwert, korregiert mit Int-Aufruf12
184
 mov tsw,wl                 ;definieren
185
 out tcnt0,tsw              ;und ausgeben
186
 sei                        ;Interrupts global freigeben
187
 rcall lcd_init             ;LCD initialisieren      
188
;Ende der Initialisierung, Programm 'fällt' jetzt in die Hauptschleife
189
190
locate 0,0                  ;feststehenden Text Zeile 0
191
printf txt_zeile0           ;ausgeben
192
locate 1,0                  ;feststehenden Text Zeile 1
193
printf txt_zeile1           ;ausgeben
194
locate 2,0                  ;feststehenden Text Zeile 2
195
printf txt_zeile2           ;ausgeben
196
locate 3,0                  ;feststehenden Text Zeile 3
197
printf txt_zeile3           ;ausgeben
198
199
200
mainloop:               ;Hauptschleife, Endlosschleife
201
;hier passiert:
202
;- LCD-Ausgabe,
203
;- Abfrage von Ereignissen und Reaktion darauf
204
205
 locate 0,0+8               ;Ausgabeposition Sollwert
206
 print83 soll0              ;Sollwert ausgeben
207
208
 locate 1,0+8               ;Ausgabeposition Sollwert
209
 print83 soll1              ;Sollwert ausgeben
210
211
 locate 2,0+8               ;Ausgabeposition Sollwert
212
 print83 soll2              ;Sollwert ausgeben
213
214
 locate 3,0+8               ;Ausgabeposition Sollwert
215
 print83 soll3              ;Sollwert ausgeben
216
217
.equ rsp=15      ;Position rechte Spalte
218
219
 locate 0,rsp+8             ;Ausgabeposition Sollwert
220
 print83 soll4              ;Sollwert ausgeben
221
222
 locate 1,rsp+8             ;Ausgabeposition Sollwert
223
 print83 soll5              ;Sollwert ausgeben
224
225
 locate 2,rsp+8             ;Ausgabeposition Sollwert
226
 print83 soll6              ;Sollwert ausgeben
227
228
 locate 3,rsp+8             ;Ausgabeposition Sollwert
229
 print83 soll7              ;Sollwert ausgeben
230
 rcall tasten               ;eventuelle Tastendrücke abarbeiten
231
232
 locate 1,13                ;Position Mitte zweite Zeile
233
 ldi wl,'1'                 ;Kanalnummer
234
 add wl,kanal               ;zur Ziffer wandeln
235
 rcall lcd_data             ;und ausgeben...
236
237
 rjmp mainloop              ;fertig, Endlosschleife...
238
239
tasten:                 ;UP, fragt entprellte Tasten ab
240
;zuerst die Kanaltasten:
241
 sbrc tfl,chanplus          ;Kanal-Plus-Taste betätigt? - nein...
242
 inc kanal                  ;ja, Kanalnummer erhöhen
243
 sbrc tfl,chanminus         ;Kanal-Minus-Taste betätigt? - nein...
244
 dec kanal                  ;ja, Kanalnummer vermindern
245
 ldi wl,7                   ;Wertebereich (Zählumfang) auf
246
 and kanal,wl               ;0..7 begrenzen (untere 3 Bits maskieren)
247
;jetzt die Dimmtasten:
248
 andi tfl,dimtast           ;alle Tasten außer den Dimmtasten rücksetzen
249
 brne dimm                  ;war eine Dimmtaste betätigt? - ja...
250
tasten_e:               ;Ende des UP
251
 ret                        ;nein, zurück...
252
253
dimm:                   ;ändert Sollwert des aktiven Kanals
254
 clr zh                     ;Pointer auf Sollwert des aktuellen
255
 mov zl,kanal               ;Kanals (Kanal als Index auf Array)
256
 ld wl,z                    ;Kopie des Sollwertes holen
257
 sbrs tfl,dimplus           ;Taste Dimm+? - ja...
258
 rjmp dimm1                 ;nein, weiter...
259
;Dimplus-Taste wurde betätigt
260
 subi wl,-step              ;ja, Sollwert vergrößern
261
 cpi wl,pwu                 ;PWM-Zählumfang überschritten?
262
 brcs dimm1                 ;nein...
263
 ldi wl,pwu                 ;ja, auf PWM-Zählumfang begrenzen
264
dimm1:
265
 sbrs tfl,dimminus          ;Taste Dimm-? - ja...
266
 rjmp dimm2                 ;nein, weiter...
267
;Dimminus-Taste wurde betätigt
268
 subi wl,step               ;ja, Sollwert vermindern
269
 brcc dimm2                 ;Unterlauf? nein...
270
 clr wl                     ;ja, auf 0 setzen
271
dimm2:
272
 cbr tfl,dimtast            ;Dimmtasten zurücksetzen (Job ist ja  erledigt)
273
 st z,wl                    ;Sollwert ins Array zurückschreiben
274
 rjmp tasten_e              ;fertig...
275
 
276
277
Tim0_OVF:                   ;ISR Timer0-Überlauf
278
 in sregtemp, sreg          ;Sreg sichern
279
 out tcnt0,tsw              ;Timer auf Startwert setzen
280
 inc pwz                    ;PWM-Treppenzähler erhöhen
281
 cpi pwz, pwu               ;PWM-Zählumfang erreicht?
282
 brne Time0_a               ;nein... (die 3 Punkte bedeuten bei mir Sprung)
283
;hier landet das Programm nur bei jeder hundertsten Runde
284
 clr pwz                    ;ja, von vorn zählen und Tasten abfragen
285
Tastenabfrage:  ;Entprellroutine (Algorithmus geklaut bei Peter Dannegger...)
286
 in temp,tap    ;Tastenport einlesen (gedrückt=L)
287
 com temp       ;invertieren (gedrückt=H)
288
 eor temp,tas   ;nur Änderungen werden H
289
 and tz0,temp   ;Prellzähler unveränderter Tasten löschen (Bit0)
290
 and tz1,temp   ;Prellzähler unveränderter Tasten löschen (Bit1)
291
 com tz0        ;L-Bit zählen 0,2,->1, 1,3,->0
292
 eor tz1,tz0    ;H-Bit zählen 0,2,->tz1 toggeln
293
 and temp,tz0   ;Änderungen nur dann erhalten, wenn im Prellzähler
294
 and temp,tz1   ;beide Bits gesetzt sind (Zählerstand 3)
295
 eor tas,temp   ;erhaltene Änderungen toggeln alten (gültigen) Tastenstatus
296
 and temp,tas   ;nur (neu) gedrückte Tastenbits bleiben erhalten
297
 or tfl,temp    ;und zugehörige Bits setzen (gelöscht wird nach Abarbeitung)
298
;tmp ist wieder frei, tas enthält den entprellten Tastenstatus,
299
;tfl die neu gerückten Tasten
300
Tastendauer:
301
 mov temp,tas       ;Tastenzustand kopieren
302
 andi temp,dimtast  ;nur Dimm-Tasten mit Wiederholfunktion stehen lassen
303
 tst temp           ;ist eine Taste betätigt?
304
 breq Tastendauer0  ;nein, Dauer auf Startwert...
305
 dec twz            ;ja, Zähler runter
306
 brne Tastenabfrage_e   ;Dauer abgelaufen? - nein...
307
 or tfl,temp        ;ja, noch aktive Tasten übernehmen
308
 ldi twz,twz1       ;und Zähler auf Wiederholwert setzen
309
Tastenabfrage_e:
310
 ;in "tfl" stehen jetzt wieder die Flags der länger betätigten Tasten
311
 ;sie werden nach Abarbeitung gelöscht
312
313
Time0_a:        ;Vergleich der einzelnen PWM-Werte mit dem PWM-Treppenzähler
314
                ;(Idee geklaut bei Peter Dannegger)
315
 cp pwz, soll7  ;Sollwert erreicht? (Ergebnis im Carry)
316
 rol temp       ;Carry-Bits "einsammeln", dieses wird bis Bit7 durchgeschoben
317
 cp pwz, soll6
318
 rol temp                   ;Bit 6
319
 cp pwz, soll5
320
 rol temp                   ;Bit 5
321
 cp pwz, soll4
322
 rol temp                   ;Bit 4
323
 cp pwz, soll3
324
 rol temp                   ;Bit 3
325
 cp pwz, soll2
326
 rol temp                   ;Bit 2
327
 cp pwz, soll1
328
 rol temp                   ;Bit 1
329
 cp pwz, soll0
330
 rol temp                   ;Bit 0
331
 com temp                   ;invertieren da low-aktive LED im STK500
332
 out lep, temp              ;Ausgabe
333
 out sreg, sregtemp         ;Sreg wiederherstellen
334
 reti                       ;ISR fertig...
335
336
Tastendauer0:       ;Reset Dauerzähler
337
 ldi twz,twz0           ;Tastendauerzähler auf Startwert
338
 rjmp Tastenabfrage_e   ;fertig...
339
340
341
txt_zeile0: .db "Kanal 1    %   Kanal 5    %",0
342
txt_zeile1: .db "Kanal 2    %   Kanal 6    %",0
343
txt_zeile2: .db "Kanal 3    %   Kanal 7    %",0
344
txt_zeile3: .db "Kanal 4    %   Kanal 8    %",0