UI-D-2WIRE.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, 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.