1 | .include "tn13def.inc"
|
2 |
|
3 | ; ==== MISC ====
|
4 |
|
5 | .def rZero = r0
|
6 | .def rSregSave = r2
|
7 | .def rDummy = r6
|
8 | .def rTimeCnt = r7
|
9 | .def rTmp = r16
|
10 | .def rTmpB = r17
|
11 | .def rLEDTime = r19
|
12 | .def rTimeout = r20
|
13 | .def rVCC = r21
|
14 |
|
15 | .equ LED_RED = PB1
|
16 | .equ LED_REDGND = PB2
|
17 | .equ VCC_OUT = PB3
|
18 | .equ VCC_DIV10_ADC = PB4
|
19 |
|
20 | ; ==== CODE ====
|
21 | .cseg
|
22 | .org 0
|
23 | rjmp reset
|
24 |
|
25 | .org OVF0addr
|
26 | rjmp timer0
|
27 |
|
28 | .org WDTaddr
|
29 | rjmp watchdogInt
|
30 |
|
31 | ;==========
|
32 | initTimer0:
|
33 | ldi rTmp, (1 << WGM00) | (1 << WGM01) | (1 << COM0A1) ;// mode 3, fast pwm, update at top
|
34 | out TCCR0A, rTmp
|
35 | ldi rTmp, 0b00000010 ;// div 8 => 586 ticks
|
36 | out TCCR0B, rTmp
|
37 |
|
38 | out OCR0A, rZero
|
39 |
|
40 | ldi rTmp, 0b00000010 ;// TOIE0, activate interrupt
|
41 | out TIMSK0, rTmp
|
42 |
|
43 | ret
|
44 |
|
45 | ;==========
|
46 | initWatchDog:
|
47 | cli
|
48 | wdr
|
49 | ; Clear WDRF in MCUSR
|
50 | in rTmp, MCUSR
|
51 | andi rTmp, (0xff - (1<<WDRF))
|
52 | out MCUSR, rTmp
|
53 |
|
54 | ;// set watchdog in interrupt mode
|
55 | cpi rVCC, 50
|
56 | brlo lowerVoltageHigherWDTime
|
57 | ldi rTmp, (1<<WDTIE)|(1<<WDCE)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0) ;//2sec. (1<<WDP2)|(1<<WDP1)|(1<<WDP0)
|
58 | rjmp voltageCheckWDTEnd
|
59 | lowerVoltageHigherWDTime:
|
60 | ldi rTmp, (1<<WDTIE)|(1<<WDCE)|(1<<WDP3) ;//4sec. (1<<WDP2)|(1<<WDP1)|(1<<WDP0)
|
61 | voltageCheckWDTEnd:
|
62 | out WDTCR, rTmp
|
63 |
|
64 | sei
|
65 | ret
|
66 |
|
67 | ;==========
|
68 | watchdogInt:
|
69 | reti
|
70 |
|
71 | ; ==== main() ====
|
72 | reset:
|
73 | ldi rTmp, LOW(RAMEND)
|
74 | out SPL, rTmp
|
75 |
|
76 | clr rZero
|
77 |
|
78 | ldi rTmp, (1<<LED_RED)|(1<<LED_REDGND)|(1<<VCC_OUT)
|
79 | out DDRB, rTmp
|
80 |
|
81 | out PORTB, rZero
|
82 |
|
83 | ldi rTmp, (1<<ACD)
|
84 | out ACSR, rTmp ;// deactivate analog comp.
|
85 |
|
86 | ldi rTmp,(1<<SE)|(0<<SM0)|(0<<SM1)
|
87 | out MCUCR, rTmp
|
88 |
|
89 | rcall initTimer0
|
90 |
|
91 | sei ;// activate interrupts
|
92 |
|
93 | ldi rLEDTime, 8
|
94 | mainLoop:
|
95 |
|
96 | sbi PORTB, VCC_OUT ;// VCC (for voltage sensing with 1:10 voltage divider) on
|
97 |
|
98 | ;// enable idle sleep mode
|
99 | in rTmp, MCUCR
|
100 | andi rTmp, ~((1<<SM1)|(1<<SM0))
|
101 | out MCUCR, rTmp
|
102 |
|
103 | ;// get battery voltage by ADC
|
104 | ldi rTmp, (1<<ADLAR) | (1<<REFS0) | 2 ;// internal ref. 1,1V, ADC2
|
105 | out ADMUX, rTmp
|
106 | ldi rTmp, (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0)
|
107 | out ADCSRA, rTmp
|
108 |
|
109 | sbi ADCSRA, ADSC
|
110 | adcWait:
|
111 | sbic ADCSRA, ADSC
|
112 | rjmp adcWait
|
113 | in rVCC, ADCH ;// ADC result
|
114 |
|
115 | cbi PORTB, VCC_OUT ;// VCC (for voltage sensing) off
|
116 | cbi ADCSRA, ADEN ;// ADC off
|
117 |
|
118 | cpi rVCC, 42 ;// is Vbat lower than 2.0V? (div: 10kOhm:1kOhm)
|
119 | brsh voltageNotLowerThan2
|
120 | sbi PORTB, LED_RED ;// ON
|
121 | sleep
|
122 | cbi PORTB, LED_RED ;// OFF
|
123 | ldi rTmp, 100
|
124 | rcall sleepMs
|
125 | sbi PORTB, LED_RED ;// ON
|
126 | sleep
|
127 | cbi PORTB, LED_RED ;// OFF
|
128 | rjmp voltageCheckEnd
|
129 | voltageNotLowerThan2:
|
130 |
|
131 | cpi rVCC, 50 ;// is Vbat lower than 2.4V? (div: 10kOhm:1kOhm) [52<=>2.5V; 50<=>2.4V; ]
|
132 | brsh voltageNotLowerThan2_5
|
133 | sbi PORTB, LED_RED ;// ON
|
134 | sleep
|
135 | sleep
|
136 | sleep
|
137 | cbi PORTB, LED_RED ;// OFF
|
138 | rjmp voltageCheckEnd
|
139 | voltageNotLowerThan2_5:
|
140 |
|
141 | cpi rVCC, 63 ;// is Vbat lower than 3V? (div: 10kOhm:1kOhm)
|
142 | brsh voltageNotLowerThan3
|
143 | sbi PORTB, LED_RED ;// ON
|
144 | sleep
|
145 | sleep
|
146 | cbi PORTB, LED_RED ;// OFF
|
147 | rjmp voltageCheckEnd
|
148 | voltageNotLowerThan3:
|
149 |
|
150 | cpi rVCC, 84 ;// is Vbat lower than 4V? (div: 10kOhm:1kOhm)
|
151 | brsh voltageNotLowerThan4
|
152 | sbi PORTB, LED_RED ;// ON
|
153 | sleep
|
154 | cbi PORTB, LED_RED ;// OFF
|
155 | rjmp voltageCheckEnd
|
156 | voltageNotLowerThan4:
|
157 |
|
158 | ;// higer than 4
|
159 |
|
160 | sbi PORTB, LED_RED ;// ON
|
161 | sleep
|
162 | cbi PORTB, LED_RED ;// OFF
|
163 | ldi rTmp, 250
|
164 | rcall sleepMs
|
165 | sbi PORTB, LED_RED ;// ON
|
166 | sleep
|
167 | cbi PORTB, LED_RED ;// OFF
|
168 | ldi rTmp, 250
|
169 | rcall sleepMs
|
170 | sbi PORTB, LED_RED ;// ON
|
171 | sleep
|
172 | cbi PORTB, LED_RED ;// OFF
|
173 |
|
174 | voltageCheckEnd:
|
175 |
|
176 | rcall initWatchDog
|
177 | ;// enable power down sleep mode
|
178 | in rTmp, MCUCR
|
179 | ori rTmp, (1<<SM1)
|
180 | out MCUCR, rTmp
|
181 |
|
182 | sleep
|
183 |
|
184 | rjmp mainLoop
|
185 |
|
186 | ;==========
|
187 | timer0:
|
188 | ;// 586 per second
|
189 | in rSregSave,sreg
|
190 | push rTmp
|
191 |
|
192 | tst rTimeout
|
193 | breq timeoutZero
|
194 | dec rTimeout
|
195 | timeoutZero:
|
196 |
|
197 | inc rTimeCnt
|
198 |
|
199 | pop rTmp
|
200 | out sreg,rSregSave
|
201 | reti
|
202 |
|
203 | ;==========
|
204 | sleepMs:
|
205 | tst rTmp
|
206 | breq sleepMsExit
|
207 | sleepMsLoop:
|
208 | sleep ;// 1 sleep cycle is ~0,002 s ( 1/586 s )
|
209 | dec rTmp
|
210 | breq sleepMsExit
|
211 | dec rTmp
|
212 | brne sleepMsLoop
|
213 | sleepMsExit:
|
214 | ret
|