1 | .include "tn12def.inc"
|
2 |
|
3 | .equ initialgotospeed=$40
|
4 | .equ normalgotospeed =$10
|
5 | .equ fastgotospeed =$08
|
6 | .equ veryfastgotospeed =$04
|
7 | .equ dotspeed =$20
|
8 | .equ dashspeed =$e0
|
9 | .equ pausespeed =dotspeed
|
10 | .equ outputpin =4
|
11 | .equ lobatpin =3
|
12 | .equ buttonpin =0
|
13 |
|
14 | .equ maxtastverh =100
|
15 | .equ maxpower =100
|
16 | .equ highpower =84 ; dim to 70% light - i.e. 84% power
|
17 | .equ medpower =63 ; dim to 40% light - i.e. 63% power
|
18 | .equ lowpower =31 ; dim to 10% light - i.e. 31% power
|
19 | .equ lowbatpower =15 ; when at lobat dim to minimal power
|
20 | ; consumption, but enough for reading
|
21 | ; instruments.
|
22 | .equ nopower =0 ; lamp off
|
23 |
|
24 | .def gotospeed=r18
|
25 | .def lobat =r19
|
26 | .def gdelay =r20
|
27 | .def gdelay2 =r21
|
28 | .def gdelay3 =r23
|
29 | .def newtastverh=r24
|
30 | .def tastmax =r25
|
31 | .def tastverh=r26
|
32 | .def ison =r27
|
33 | .def portbsh =r28
|
34 | .def temp =r29
|
35 | .def itemp =r30
|
36 |
|
37 | .ORG $000
|
38 | rjmp RESET
|
39 | .ORG $001
|
40 | rjmp EXT_INT0
|
41 | .ORG $002
|
42 | rjmp PIN_CHANGE
|
43 | .ORG $003
|
44 | rjmp TIM0_OVP
|
45 | .ORG $005
|
46 | rjmp ANA_CMP
|
47 |
|
48 | shortdelaysub:
|
49 | clr gdelay
|
50 | sdm2: DEC gdelay
|
51 | BRNE sdm2
|
52 | sdm3: DEC gdelay
|
53 | BRNE sdm3
|
54 | sdm4: DEC gdelay
|
55 | BRNE sdm4
|
56 | ret
|
57 | ;
|
58 | ; A simple macro for generating a short delay.
|
59 | ; This is used for blinking SOS
|
60 | ;
|
61 | .macro shortdelay
|
62 | .if 1 = 0
|
63 | clr gdelay
|
64 | sdm2: DEC gdelay
|
65 | BRNE sdm2
|
66 | sdm3: DEC gdelay
|
67 | BRNE sdm3
|
68 | sdm4: DEC gdelay
|
69 | BRNE sdm4
|
70 | .else
|
71 | RCALL shortdelaysub
|
72 | .endif
|
73 | .endmacro
|
74 |
|
75 | ;
|
76 | ; Delay for as long as a "dot" symbol should be on.
|
77 | ;
|
78 | .macro dotdelay
|
79 | ldi gdelay2,dotspeed
|
80 | dd2: shortdelay
|
81 | dec gdelay2
|
82 | brne dd2
|
83 | .endmacro
|
84 |
|
85 | ;
|
86 | ; Delay for as long as a "dash" symbol should be on.
|
87 | ;
|
88 | .macro dashdelay
|
89 | ldi gdelay2,dashspeed
|
90 | dad2: shortdelay
|
91 | dec gdelay2
|
92 | brne dad2
|
93 | .endmacro
|
94 |
|
95 | ;
|
96 | ; Delay for as long as a pause between symbols should be.
|
97 | ;
|
98 | .macro pausedelay
|
99 | ldi gdelay2,pausespeed
|
100 | pd2: shortdelay
|
101 | dec gdelay2
|
102 | brne pd2
|
103 | .endmacro
|
104 |
|
105 | ;
|
106 | ; Send a dot with the inter-symbol pause trailing
|
107 | ;
|
108 | .macro saydot
|
109 | ldi newtastverh,maxpower
|
110 | rcall soft_goto
|
111 | dotdelay
|
112 | ldi newtastverh,nopower
|
113 | rcall soft_goto
|
114 | pausedelay
|
115 | .endmacro
|
116 |
|
117 | ;
|
118 | ; Send a dash with the inter-symbol pause trailing
|
119 | ;
|
120 | .macro saydash
|
121 | ldi newtastverh,maxpower
|
122 | rcall soft_goto
|
123 | dashdelay
|
124 | ldi newtastverh,nopower
|
125 | rcall soft_goto
|
126 | pausedelay
|
127 | .endmacro
|
128 |
|
129 | ;
|
130 | ; Delay for a inter-character pause - minus the already done inter-symbol pause
|
131 | ;
|
132 | .macro newchardelay
|
133 | pausedelay
|
134 | .endmacro
|
135 |
|
136 | ;
|
137 | ; Send an s, including trailing inter-char pause
|
138 | ;
|
139 | .macro says
|
140 | saydot
|
141 | saydot
|
142 | saydot
|
143 | newchardelay
|
144 | .endmacro
|
145 |
|
146 | ;
|
147 | ; Send an o, including trailing inter-char pause
|
148 | ;
|
149 | .macro sayo
|
150 | saydash
|
151 | saydash
|
152 | saydash
|
153 | newchardelay
|
154 | .endmacro
|
155 |
|
156 | ;
|
157 | ; Send an a, including trailing inter-char pause
|
158 | ;
|
159 | .macro saya
|
160 | saydot
|
161 | saydash
|
162 | newchardelay
|
163 | .endmacro
|
164 |
|
165 | ;
|
166 | ; Send an e, including trailing inter-char pause
|
167 | ;
|
168 | .macro saye
|
169 | saydot
|
170 | newchardelay
|
171 | .endmacro
|
172 |
|
173 | TIM0_OVP:
|
174 | cpi ison,$00
|
175 | breq IS_OFF
|
176 | ldi ison,$00
|
177 | ldi itemp,$00
|
178 | SUB itemp,tastverh
|
179 | breq justret
|
180 | out TCNT0,itemp
|
181 | sbi PORTB,outputpin
|
182 | justret:
|
183 | reti
|
184 | IS_OFF:
|
185 | ldi ison,$ff
|
186 | ldi itemp,$00
|
187 | sub itemp,tastmax
|
188 | add itemp,tastverh
|
189 | breq justret
|
190 | cbi PORTB,outputpin
|
191 | out TCNT0,itemp
|
192 | reti
|
193 |
|
194 | EXT_INT0:
|
195 | reti
|
196 |
|
197 | PIN_CHANGE:
|
198 | reti
|
199 |
|
200 | ;
|
201 | ; The analog comparator triggered. This means we have a lobat condition
|
202 | ;
|
203 | ANA_CMP:
|
204 | SBIC ACSR,5
|
205 | rjmp on_lobat
|
206 | have_enough:
|
207 | cbi PORTB,lobatpin
|
208 | reti
|
209 | on_lobat:
|
210 | ser lobat
|
211 | sbi PORTB,lobatpin
|
212 | reti
|
213 |
|
214 | set_lobat:
|
215 | ser lobat
|
216 | sbi PORTB,lobatpin
|
217 | ret
|
218 |
|
219 | reset_lobat:
|
220 | clr lobat
|
221 | cbi PORTB,lobatpin
|
222 | ret
|
223 |
|
224 |
|
225 | soft_goto:
|
226 | cp tastverh,newtastverh
|
227 | breq sg_doret
|
228 | brlo goto_less
|
229 | dec tastverh
|
230 | rjmp redo_goto
|
231 | sg_doret:
|
232 | ret
|
233 | goto_less:
|
234 | inc tastverh
|
235 | redo_goto:
|
236 | mov gdelay2,gotospeed
|
237 | rg2: clr gdelay
|
238 | rg1: dec gdelay
|
239 | brne rg1
|
240 | dec gdelay2
|
241 | brne rg2
|
242 | rjmp soft_goto
|
243 |
|
244 |
|
245 | ;
|
246 | ; Wait for key. A looong keypress (about 6 seconds) enters SOS-Mode
|
247 | ;
|
248 |
|
249 | .macro sostimingdelay
|
250 | ldi gdelay3,$15
|
251 | down:
|
252 | dec gdelay3
|
253 | brne down
|
254 | .endmacro
|
255 |
|
256 | waitforkey:
|
257 | CLR gdelay2
|
258 | CLR gdelay
|
259 | wfk_loop:
|
260 | sostimingdelay
|
261 | dec gdelay
|
262 | BRNE skipdec2
|
263 | dec gdelay2
|
264 | BREQ have_sos ; YEAH - we really jump into something
|
265 | ; that doesn't return. SOS-Mode can only
|
266 | ; be left by a RESET.
|
267 | skipdec2:
|
268 | SBRC lobat,0 ; lobat clear?
|
269 | ret ; if lobat is set, break out
|
270 | SBIS PINB,buttonpin ; if Button is not pressed, skip to waitforkey2
|
271 | rjmp wfk_loop ; if Button is pressed, keep looping
|
272 | waitforkey2:
|
273 | SBRC lobat,0 ; lobat clear?
|
274 | ret ; if lobat is set, break out
|
275 | SBIC PINB,buttonpin ; if Button is pressed, ret
|
276 | rjmp waitforkey2 ; if Button is not pressed, keep looping
|
277 | ret
|
278 |
|
279 |
|
280 | waitforkey_nolobatbreak:
|
281 | CLR gdelay2
|
282 | CLR gdelay
|
283 | wfk_loop_nlbb:
|
284 | sostimingdelay
|
285 | dec gdelay
|
286 | BRNE skipdec3
|
287 | dec gdelay2
|
288 | BREQ have_sos ; YEAH - we really jump into something
|
289 | ; that doesn't return. SOS-Mode can only
|
290 | ; be left by a RESET.
|
291 | skipdec3:
|
292 | SBIS PINB,buttonpin ; if Button is not pressed, skip to waitforkey2
|
293 | rjmp wfk_loop_nlbb ; if Button is pressed, keep looping
|
294 | waitforkey_nlbb2:
|
295 | SBIC PINB,buttonpin ; if Button is pressed, ret
|
296 | rjmp waitforkey_nlbb2 ; if Button is not pressed, keep looping
|
297 | ret
|
298 |
|
299 | ;
|
300 | ; Blink SOS
|
301 | ;
|
302 | ; In this mode we don't give a f*** about the battery life
|
303 | ;
|
304 | have_sos:
|
305 | ldi gotospeed,veryfastgotospeed
|
306 | says ; Blink ... --- ...
|
307 | sayo
|
308 | says
|
309 | ldi temp,65 ; Wait about 10 seconds
|
310 | sos_delay:
|
311 | pausedelay
|
312 | dec temp
|
313 | brne sos_delay
|
314 | rjmp have_sos
|
315 |
|
316 | ; *************************************************************************
|
317 | ; Main program starts here
|
318 | ; *************************************************************************
|
319 |
|
320 | RESET:
|
321 | ;
|
322 | ; Initialize Variables
|
323 | ;
|
324 | CLR ison
|
325 | ldi tastverh,nopower
|
326 | LDI tastmax,maxtastverh
|
327 | ;
|
328 | ; Setup the Output pins
|
329 | ;
|
330 | LDI temp,(1<<outputpin)|(1<<lobatpin)
|
331 | OUT DDRB,temp
|
332 | ; activate pullup resistor on the
|
333 | ; pin the button is connected to
|
334 | LDI temp,(1<<buttonpin)
|
335 | OUT PORTB,temp
|
336 |
|
337 | ;
|
338 | ; Set up the timer/counter.
|
339 | ; ATTiny12 has an internal 1.2MHz clock.
|
340 | ; That makes for 18750Hz at CK/64.
|
341 | ; Using an 8 Bit counter, we can thus reach Frequencies between
|
342 | ; 73Hz and 18kHz for driving the lamp.
|
343 | ; For ease of calculation I chose 187Hz (tastmax=100).
|
344 | ;
|
345 | LDI temp,$03 ; CK/64
|
346 | OUT TCCR0,temp
|
347 | ;
|
348 | ; Enable timer interrupt.
|
349 | ;
|
350 | LDI temp,$02
|
351 | OUT TIMSK,temp
|
352 | SEI
|
353 |
|
354 | ;
|
355 | ; Now enable the analog comparator stuff.
|
356 | ;
|
357 | LDI temp,$48 ; $40=enable bandgap $08=Interrupt enable
|
358 | ; $00=int on toggle.
|
359 | OUT ACSR,temp
|
360 | ; The manual says not to do this, as it can cause interrupts while bits
|
361 | ; are being shuffled.
|
362 | ; As we are only setting a flag in the interrupt, which gets cleared after
|
363 | ; startup anyway - we don't care.
|
364 |
|
365 |
|
366 | softstart:
|
367 | ;
|
368 | ; Do a soft start of the lamp. Then reset the lobat entry.
|
369 | ; This is done at startup in order to reset any pending lobat
|
370 | ; interrupts.
|
371 | ; We check the button condition.
|
372 | ; If the lamp comes up with the button active, either the button is
|
373 | ; stuck, or the user is requesting "emergency full power".
|
374 | ; As a safe default, we keep the lamp at 100% if that happens.
|
375 | ;
|
376 |
|
377 | ldi gotospeed,initialgotospeed
|
378 | ldi newtastverh,lowpower
|
379 | rcall soft_goto;
|
380 |
|
381 | ldi gotospeed,normalgotospeed
|
382 | ldi newtastverh,maxpower
|
383 | rcall soft_goto;
|
384 |
|
385 | rcall reset_lobat
|
386 |
|
387 | SBIS PINB,buttonpin ; if Button is not pressed, skip emergency mode
|
388 | rjmp emergency_full
|
389 |
|
390 | ;
|
391 | ; If we started up in alobat situation and are not in emergency mode,
|
392 | ; jump directly to lobat.
|
393 | ;
|
394 | SBIC ACSR,5 ; Is the AC output clear? Then all is well.
|
395 | rjmp have_lobat ; otherwise indicate lobat.
|
396 | rjmp ss2
|
397 |
|
398 | ;
|
399 | ; usually we come back here. The lamp starts up soft as well,
|
400 | ; but we assume lobat has been cleared before.
|
401 | ; Notice, that detecting lobat is an edge-triggered action.
|
402 | ; So if we are on lobat here, and lobat flag has been cleared,
|
403 | ; we are toast.
|
404 | ;
|
405 |
|
406 | ;
|
407 | ; While in normal operating mode, we wait for button press.
|
408 | ; the button press fuction will also return, if a lobat condition
|
409 | ; is detected. This macro will jump to "have_lobat", if lobat
|
410 | ; condition is active.
|
411 | ;
|
412 | .macro testandjumplobat
|
413 | tst lobat
|
414 | brne have_lobat
|
415 | .endmacro
|
416 |
|
417 | .macro waitforkey_and_lobat
|
418 | rcall waitforkey
|
419 | testandjumplobat
|
420 | .endmacro
|
421 |
|
422 | softstart2:
|
423 | ldi newtastverh,maxpower
|
424 | rcall soft_goto;
|
425 |
|
426 | ss2:
|
427 | waitforkey_and_lobat
|
428 |
|
429 | ; dim to high power setting
|
430 |
|
431 | ldi newtastverh,highpower
|
432 | rcall soft_goto;
|
433 | waitforkey_and_lobat
|
434 |
|
435 | ; dim to medium power setting
|
436 |
|
437 | ldi newtastverh,medpower
|
438 | rcall soft_goto
|
439 | waitforkey_and_lobat
|
440 |
|
441 | lopower:
|
442 | ; dim to low power setting
|
443 |
|
444 | ldi newtastverh,lowpower
|
445 | rcall soft_goto
|
446 | waitforkey_and_lobat
|
447 |
|
448 | ; dim to medium power setting
|
449 |
|
450 | ldi newtastverh,medpower
|
451 | rcall soft_goto;
|
452 | waitforkey_and_lobat
|
453 |
|
454 | ; dim to high power setting
|
455 |
|
456 | ldi newtastverh,highpower
|
457 | rcall soft_goto;
|
458 | waitforkey_and_lobat
|
459 |
|
460 | ; jump to start - brings us back to 100%
|
461 | rjmp softstart2
|
462 |
|
463 |
|
464 | ;
|
465 | ; We have a lobat condition.
|
466 | ; First notify the user by morsing A A A (like Attention Accu Alert)
|
467 | ; then dim the light to 20% Power, which probably gives about 4% Light.
|
468 | ;
|
469 | have_lobat:
|
470 | rcall set_lobat ; reset the lobat condition.
|
471 | ldi newtastverh,lowbatpower
|
472 | rcall soft_goto ; bring us to minimum light.
|
473 | ldi gotospeed,fastgotospeed
|
474 | saya
|
475 | ldi gotospeed,normalgotospeed
|
476 | ldi newtastverh,lowbatpower
|
477 | rcall soft_goto ; bring us to minimum light.
|
478 | rcall waitforkey_nolobatbreak
|
479 | ; if the user presses a button, he wants
|
480 | ; more light.
|
481 | rcall reset_lobat ; reset the lobat condition.
|
482 | SBIC ACSR,5 ; Is the AC output clear? In that case we
|
483 | ; might have enough power for a higher
|
484 | ; setting.
|
485 | rjmp have_lobat ; otherwise indicate lobat.
|
486 | rjmp lopower ; give him lopower first.
|
487 |
|
488 | emergency_full:
|
489 | ldi newtastverh,nopower
|
490 | rcall soft_goto ; bring us to minimum light.
|
491 | ldi newtastverh,maxpower
|
492 | rcall soft_goto ; bring us to minimum light.
|
493 | forever:
|
494 | rjmp forever
|