1 | ;; Target: Atmel ATTiny13
|
2 | ;;
|
3 |
|
4 | .include "tn13def.inc"
|
5 |
|
6 | ;; Takt: 128 kHz intern
|
7 | ;;
|
8 |
|
9 | .equ XTAL = 128000
|
10 |
|
11 | ;; Register-Definition
|
12 | ;; (verschwenderisch, wird aber sonst nicht genutzt)
|
13 |
|
14 | .def sendenaktiv = r0
|
15 | .def vorherigeabfrage = r1
|
16 | .def fernversorgung = r2
|
17 | .def sendezaehler = r3
|
18 | .def multipliziert = r4
|
19 | .def varausgabe = r5
|
20 | .def mulzaehler = r6
|
21 | .def pinvar = r7
|
22 |
|
23 | .def temp1 = r16
|
24 | .def temp2 = r17
|
25 | .def temp3 = r18
|
26 |
|
27 | ;; Eingänge: 4 (PB0 - PB3)
|
28 | ;;
|
29 | ;; Ausgänge: 1 (PB4)
|
30 | ;;
|
31 |
|
32 | ;; Genutzte Interrupts:
|
33 | ;;
|
34 | ;; Timer0 Overflow (500 * 1/s @ 128000 Hz)
|
35 | ;; PinChange (Spannungsversorgung wird unterbrochen, "ich" darf senden)
|
36 | ;;
|
37 |
|
38 | .org 0x00
|
39 | rjmp init ;; Reset-Vektor
|
40 |
|
41 | .org 0x02 ;; Pin-Change
|
42 | rjmp pcint
|
43 |
|
44 | .org 0x03 ;; Timer0-Overflow
|
45 | rjmp timer
|
46 |
|
47 | .org 0x0A ;; Programm-Start
|
48 | init:
|
49 | ldi temp1, LOW(RAMEND)
|
50 | out SPL, temp1 ;; Stackpointer init
|
51 |
|
52 | ldi temp1, 0b00010000 ;; DDRB setzen,
|
53 | out DDRB, temp1 ;; nur PB4 als Ausgang.
|
54 |
|
55 | ldi temp1, 0b00000111 ;; Pullups an PB0-PB2
|
56 | out PORTB, temp1 ;; aktivieren.
|
57 |
|
58 | ldi temp1, 0x01 ;; Timer-Interrupt
|
59 | out TCCR0B, temp1 ;; Kein Vorteiler!
|
60 | ldi temp1, 0x02 ;; Timer Overflow Interrupt aktivieren
|
61 | out TIMSK0, temp1
|
62 |
|
63 | ldi temp1, 0x20 ;; PC-Interrupt aktivieren
|
64 | out GIMSK, temp1 ;;
|
65 | ldi temp1, 0x08 ;; Auf PCINT3 reagieren (PB3)
|
66 | out PCMSK, temp1
|
67 |
|
68 | sbis PORTB, PB3 ;; "fernversorgung" auf den richtigen Status
|
69 | ldi temp1, 0x00 ;; bringen. Falls diese schon wieder aus ist,
|
70 | sbic PORTB, PB3 ;; kann der Interrupt noch nicht ausgeführt
|
71 | ldi temp1, 0xFF ;; werden, aber es wird bereits der richtige Status
|
72 | mov fernversorgung, temp1 ;; "gespeichert" und das Programm geht weiter.
|
73 |
|
74 | sei ;; Enable interrupt handling
|
75 |
|
76 | rjmp main ;; Sprung zur Haupt-Endlos-Schleife
|
77 |
|
78 | ;; Soll-Funktion der Hauptschleife:
|
79 | ;; Eingänge lesen: Eine Änderung des Eingangs muss mindestens 3 Lesevorgänge
|
80 | ;; hintereinander stabil bleiben, um als gültig übernommen zu werden.
|
81 |
|
82 | main:
|
83 | ldi temp1, 0x00
|
84 | cp sendenaktiv, temp1 ;; Wurde bereits ein Sende-Vorgang
|
85 | brne main ;; ausgelöst? Ja: Wieder zur Hauptschleife.
|
86 |
|
87 | cbi PORTB, PB4 ;; Nein: Ausgang (wieder) auf 0 setzen.
|
88 |
|
89 | mov temp2, temp3 ;; Vorherigen PINB-Status in temp2 sichern.
|
90 | in temp3, PINB ;; Aktuellen PINB-Status einlesen
|
91 | andi temp3, 0x07 ;; Nur die unteren 3 Bits übernehmen (PB0-PB2)
|
92 | cp temp2, temp3 ;; Vorherigen PINB-Status mit jetzigem vergleichen.
|
93 | brne main ;; Stimmt nicht überein, also wieder zur Hauptschleife
|
94 |
|
95 | ldi temp2, 0xFF ;; Stimmt überein, also: Vorherigeabfrage positiv?
|
96 | cp vorherigeabfrage, temp2
|
97 | brne vorher ;; Nein? Springe zu "vorher".
|
98 | mov pinvar, temp3 ;; Ja: pinvar auf Einlese-Status setzen,
|
99 | rjmp main ;; und zur Hauptschleife zurück.
|
100 | vorher:
|
101 | mov vorherigeabfrage, temp2 ;; Dann positiv setzen,
|
102 | rjmp main ;; und zur Hauptschleife zurück.
|
103 |
|
104 | ;; Interrupt-Handling
|
105 | ;; PinChange-Interrupt:
|
106 | ;;
|
107 | pcint:
|
108 | ldi temp1, 0xFF ;; Wurde das Senden beits aktiviert? (Abfrage durch
|
109 | cp sendenaktiv, temp1 ;; Rückkopplung nötig)
|
110 | breq PCEnd ;; Ja: Springe zu PCEnd (Interrupt beenden)
|
111 | brne PCWei ;; Nein: Springe zu PCWei
|
112 |
|
113 | RemOff:
|
114 | ldi temp1, 0x00 ;; Spannungsversorgung wurde getrennt, Status in einem
|
115 | mov fernversorgung, temp1 ;; Register speichern, und für den Timer-Interrupt
|
116 | rjmp PCEnd ;; zugänglich machen. Dann zu PCEnd springen (Int. beenden)
|
117 |
|
118 | PCWei:
|
119 | sbis PORTB, PB3 ;; Senden noch nicht aktiv. "Prüfe", ob Versorgung beendet.
|
120 | rjmp RemOff ;; Spannung wurde entfernt -> Springe zu RemOff
|
121 | ldi temp1, 0xFF ;; Spannung wurde nicht entfernt, also fernversorgung weiterhin
|
122 | mov fernversorgung, temp1 ;; eingeschaltet lassen.
|
123 |
|
124 | PCEnd:
|
125 | reti ;; Interrupt korrekt verlassen.
|
126 |
|
127 | ;; Timer-Overflow-Interrupt:
|
128 | ;;
|
129 | timer:
|
130 | ldi temp1, 0x00
|
131 | cpse fernversorgung, temp1 ;; Interrupt verlassen, wenn "fernversorgung" eingeschaltet.
|
132 | reti
|
133 |
|
134 | ldi temp1, 0xFF
|
135 | cp sendenaktiv, temp1 ;; Andernfalls prüfen, ob bereits ein Sende-Vorgang aktiv ist.
|
136 | brne T1SNA ;; Springe zu T1SNA, wenn nicht aktiv.
|
137 | breq T1SA ;; Springe zu T1SA, wenn aktiv.
|
138 |
|
139 | T1SNA:
|
140 | ldi temp1, 0x00 ;; Nicht aktiv, also aktivieren.
|
141 | mov sendezaehler, temp1 ;; Gesendet wird Bit 0
|
142 | ldi temp1, 0xFF
|
143 | mov sendenaktiv, temp1 ;; "sendenaktiv" wird gesetzt.
|
144 | sbi PORTB, PB4 ;; Ausgabe wird 1 gesetzt. (Vor den Daten wird "1 1 0 0 1 1 1 1"
|
145 | inc sendezaehler ;; gesendet, zur Geschwindigkeitserkennung) - Und Anzahl der
|
146 | ;; gesendeten Bits um 1 erhöhen. (von 0 auf 1)
|
147 | reti ;; Interrupt verlassen, in 256 Takten gehts weiter.
|
148 |
|
149 | T1SA: ;; Aktiv, also passendes Bit "suchen" und senden.
|
150 | ldi temp1, 0x02
|
151 | cp sendezaehler, temp1 ;; Sendezähler kleiner 2?
|
152 | brsh Z1 ;; Größer od. gleich 2: weiter zu Z1
|
153 | sbi PORTB, PB4 ;; Ausgang (wieder) auf 1 setzen.
|
154 | inc sendezaehler ;; Anzahl der gesendeten Bits um 1 erhöhen. (von 1 auf 2)
|
155 | reti ;; Und wieder: Interrupt verlassen, in 256 Takten gehts weiter.
|
156 |
|
157 | Z1:
|
158 | ldi temp1, 0x04 ;; Größer gleich 2 aber auch kleiner als 4?
|
159 | cp sendezaehler, temp1 ;; [der vergleich...]
|
160 | brsh Z2 ;; Nein: Weiter zu Z2
|
161 | cbi PORTB, PB4 ;; Ja: Jetzt müssen "wir" 0 senden
|
162 | inc sendezaehler ;; Und wieder: Anzahl der gesendeten Bits um 1 erhöhen.
|
163 | ;; (von 2 auf 3 ODER von 3 auf 4 - wird 2 mal genutzt)
|
164 | reti ;; Und wieder: Interrupt verlassen, in 256 Takten gehts weiter.
|
165 |
|
166 | Z2:
|
167 | ldi temp1, 0x08 ;; Größer gleich 4 aber auch kleiner als 8?
|
168 | cp sendezaehler, temp1 ;; [der vergleich...]
|
169 | brsh Z3 ;; Nein: Weiter zu Z3
|
170 | sbi PORTB, PB4 ;; Ja: Jetzt müssen "wir" wieder 1 senden
|
171 | inc sendezaehler ;; Und wieder: Anzahl der gesendeten Bits um 1 erhöhen.
|
172 | ;; (4>5, 5>6, 6>7, 7>8 - wird 4 mal genutzt)
|
173 | reti ;; Und wieder: Interrupt verlassen, in 256 Takten gehts weiter.
|
174 |
|
175 | Z3:
|
176 | ldi temp1, 0xFF ;; Jetzt gehts um "Multiplizieren". Tiny13 hat kein Hardware-MUL,
|
177 | cp multipliziert, temp1 ;; als Manuell. Wurde das Bereits gemacht?
|
178 | breq IsMUL ;; Ja: Springe zu "IsMul"
|
179 | brne IsNMul ;; Nein: Springe zu "IsNMul"
|
180 |
|
181 | IsNMul:
|
182 | ldi temp1, 0x00
|
183 | mov varausgabe, temp1 ;; Ausgabe-Variable auf 0 setzen
|
184 | ldi temp1, 0x00
|
185 | mov mulzaehler, temp1 ;; Mul-Zähler auf 0 setzen
|
186 | Marke: ;; Sprung-Marke für den Mul-Zähler
|
187 | ldi temp1, 0x23 ;; Mul-Zähler auf 35 (0x23 HEX)?
|
188 | cp mulzaehler, temp1 ;; [der vergleich...]
|
189 | breq IsMul ;; "mulzaehler" = 35, also fertig - Springe zu "IsMul"
|
190 | add varausgabe, pinvar ;; Nicht fertig, zu varausgabe den Wert von "pinvar" addieren.
|
191 | inc mulzaehler ;; und den "mulzaehler" erhöhen. Damit "man" auch weiß, mit
|
192 | ;; welcher Zahl "pinvar" Multipliziert wurde.
|
193 | rjmp Marke ;; Sprung zur "Marke". Findet nicht mehr Statt, wenn Mul
|
194 | ;; einmal den Wert 0x23 (35 Dez.) erreicht hat.
|
195 |
|
196 | IsMul:
|
197 | ldi temp1, 0xF0 ;; Sendezaehler größer gleich 8, aber auch kleiner als 16?
|
198 | cp sendezaehler, temp1 ;; [der vergleich...]
|
199 | breq AllSent ;; Nein: Alles gesendet. Also den Status unter "AllSent" mitteilen.
|
200 | sbrc varausgabe, 7 ;; Bit7 von varausgabe "extrahieren".
|
201 | rjmp An ;; Registerbit ist "1", Senden.
|
202 | rjmp Aus ;; Registerbit ist "0", Senden.
|
203 | An:
|
204 | sbi PORTB, PB4 ;; Senden einer 1 für das gesetzte Register-Bit
|
205 | lsl varausgabe ;; "varausgabe" um 1 Bit nach links verschieben.
|
206 | rjmp Ende ;; und Interrupt am "Ende" verlassen.
|
207 | Aus:
|
208 | cbi PORTB, PB4 ;; Senden einer 0 für das gelöschte Register-Bit
|
209 | lsl varausgabe ;; "varausgabe" um 1 Bit nach links verschieben.
|
210 | rjmp Ende ;; und Interrupt am "Ende" verlassen.
|
211 |
|
212 | Ende:
|
213 | reti ;; Interrupt verlassen.
|
214 |
|
215 | AllSent: ;; Es wurde alles gesendet.
|
216 | ldi temp1, 0x00 ;; Also löschen wir
|
217 | mov multipliziert, temp1 ;; den "multipliziert"-Status
|
218 | mov sendenaktiv, temp1 ;; den "sendenaktiv"-Status und setzen
|
219 | mov sendezaehler, temp1 ;; den "sendezaehler" wieder auf 0.
|
220 | reti ;; Dann wird der Interrupt wieder verlassen.
|