UI-D-2WIRE-Up.asm


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.