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