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
|