SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | Copyright 2011 Dustin L. Westaby | |
3 | ||
4 | ---------------------------------------------------------------------- | |
5 | Stairway Light Controller for Attiny2313 | |
6 | ---------------------------------------------------------------------- | |
7 | Title: stairway.c | |
8 | Author: Dustin Westaby | |
9 | Date Created: 01/19/12 | |
10 | - | Last Modified: |
10 | + | Last Modified: |
11 | - | Purpose: Monitor proximity and motion sensors and animate stairway |
11 | + | Purpose: Monitor proximity and motion sensors and animate stairway |
12 | lighting. | |
13 | ||
14 | Compiled with AVR-GCC WinAVR | |
15 | ||
16 | Revisions List: | |
17 | 01/19/12 Initial draft | |
18 | ||
19 | ---------------------------------------------------------------------- | |
20 | Fuses: | |
21 | ---------------------------------------------------------------------- | |
22 | BrownOut Disabled | |
23 | CKDIV8 | |
24 | Int RC Osc 8Mhz + 64ms | |
25 | ||
26 | ---------------------------------------------------------------------- | |
27 | Inputs: | |
28 | ---------------------------------------------------------------------- | |
29 | pin port function | |
30 | ---------------------------------------------------------------------- | |
31 | 1 RST Unused | |
32 | 2 PD0 Motion Sensor (digital) (active low with pullup 10k) | |
33 | - | 23 PC0 Prox Sensor Low (digital) 5 feet range |
33 | + | 23 PC0 Prox Sensor Low (digital) 5 feet range |
34 | - | 24 PC1 Prox Sensor High (digital) |
34 | + | 24 PC1 Prox Sensor High (digital) |
35 | 4 PD2 Override button (digital) External Interrupt 0 | |
36 | ||
37 | ---------------------------------------------------------------------- | |
38 | Ouputs: | |
39 | ---------------------------------------------------------------------- | |
40 | pin port function | |
41 | ---------------------------------------------------------------------- | |
42 | 14 PB0 Lighting Channel | |
43 | 15 PB1 Lighting Channel | |
44 | 16 PB2 Lighting Channel | |
45 | 17 PB3 Lighting Channel | |
46 | 18 PB4 Lighting Channel | |
47 | 19 PB5 Lighting Channel | |
48 | 9 PB6 Lighting Channel | |
49 | 10 PB7 Lighting Channel | |
50 | - | |
50 | + | |
51 | ||
52 | - | The Prox sensors are analog, uses a comparator to convert to digital |
52 | + | The Prox sensors are analog, uses a comparator to convert to digital |
53 | and a pot to select the cutoff range. | |
54 | ||
55 | */ | |
56 | ||
57 | //-------------------------------------- | |
58 | // Global Variables | | |
59 | //-------------------------------------- | |
60 | // 8 MHz Internal Oscillator DIV8 (used for delay subroutines) | |
61 | // One CPU Cycle = 1us | |
62 | #define F_CPU 8000000UL/8 | |
63 | ||
64 | enum { up, down }; | |
65 | enum { on, off }; | |
66 | enum { low, high }; | |
67 | ||
68 | //-------------------------------------- | |
69 | // Includes | | |
70 | //-------------------------------------- | |
71 | #include <avr/io.h> | |
72 | #include <util/delay.h> | |
73 | //#include <avr/sleep.h> | |
74 | #include <inttypes.h> | |
75 | ||
76 | ||
77 | //-------------------------------------- | |
78 | // Global Constants | | |
79 | //-------------------------------------- | |
80 | ||
81 | int START_CH = PB0; //lowest channel bit | |
82 | int NUM_OF_CH = 6; | |
83 | int ALL_ON = 0xFF; | |
84 | int ALL_OFF = 0x00; | |
85 | ||
86 | //-------------------------------------- | |
87 | - | // Delay Subroutines | |
87 | + | // Delay Subroutine | |
88 | //-------------------------------------- | |
89 | - | //These functions are from the delay.h include, the calls to delay functions |
89 | + | //This function is from the delay.h include, the calls to delay functions |
90 | //are re-written here to allow for longer waits. | |
91 | - | void delay_ms(uint16_t ms) { |
91 | + | void delay_ms(uint16_t ms) |
92 | { | |
93 | while ( ms ) | |
94 | { | |
95 | _delay_ms(1); | |
96 | ms--; | |
97 | } | |
98 | } | |
99 | - | void delay_us(uint16_t us) { |
99 | + | |
100 | - | while ( us ) |
100 | + | |
101 | // Other Functions | | |
102 | - | _delay_us(1); |
102 | + | |
103 | - | us--; |
103 | + | |
104 | void standby_sequence(int count) | |
105 | { | |
106 | // Description: | |
107 | // This function animates a back and forth motion | |
108 | // Approx 4 transitions per second | |
109 | ||
110 | // Example: | |
111 | // 0 1 2 3 4 5 6 7 8 Channels | |
112 | // 0 1 0 1 0 1 0 1 0 Odd Count | |
113 | // 1 0 1 0 1 0 1 0 1 Even Count | |
114 | - | int i; |
114 | + | |
115 | int i; | |
116 | - | //determine if count is even or odd |
116 | + | |
117 | - | PORTB = ALL_OFF; |
117 | + | //determine if count is even or odd |
118 | - | if (count % 2 == 0) |
118 | + | PORTB = ALL_OFF; |
119 | - | { |
119 | + | if (count % 2 == 0) |
120 | - | //every other bit, even |
120 | + | { |
121 | - | for (i=START_CH; i <= NUM_OF_CH; i+=2) |
121 | + | //every other bit, even |
122 | - | { |
122 | + | for (i=START_CH; i <= NUM_OF_CH; i+=2) |
123 | - | PORTB |= (1 << i); |
123 | + | { |
124 | - | } |
124 | + | PORTB |= (1 << i); |
125 | - | } |
125 | + | } |
126 | - | else |
126 | + | } |
127 | - | { |
127 | + | else |
128 | - | //every other bit, odd |
128 | + | { |
129 | - | for (i=(START_CH+1); i <= NUM_OF_CH; i+=2) |
129 | + | //every other bit, odd |
130 | - | { |
130 | + | for (i=(START_CH+1); i <= NUM_OF_CH; i+=2) |
131 | - | PORTB |= (1 << i); |
131 | + | { |
132 | - | } |
132 | + | PORTB |= (1 << i); |
133 | - | } |
133 | + | } |
134 | } | |
135 | ||
136 | ||
137 | } | |
138 | ||
139 | void animate_sequence(int direction, int onoff) | |
140 | - | int time = 100; |
140 | + | |
141 | - | int i; |
141 | + | int time = 100; |
142 | int i; | |
143 | - | if(direction == up) |
143 | + | |
144 | - | { |
144 | + | if(direction == up) |
145 | - | if (onoff == on ) |
145 | + | { |
146 | - | { |
146 | + | if (onoff == on ) |
147 | - | //rotates through. |
147 | + | { |
148 | - | PORTB = ALL_OFF; |
148 | + | // Animates by rotating through. |
149 | - | for (i=START_CH; i < NUM_OF_CH; i++) |
149 | + | PORTB = ALL_OFF; |
150 | - | { |
150 | + | for (i=START_CH; i < NUM_OF_CH; i++) |
151 | - | PORTB |= (1 << i); |
151 | + | { |
152 | - | delay_ms(time); |
152 | + | PORTB |= (1 << i); |
153 | - | } |
153 | + | delay_ms(time); |
154 | } | |
155 | - | } |
155 | + | |
156 | - | else |
156 | + | } |
157 | - | { |
157 | + | else |
158 | - | //rotates through. |
158 | + | { |
159 | - | PORTB = ALL_ON; |
159 | + | // Animates by rotating through. |
160 | - | for (i=START_CH; i < NUM_OF_CH; i++) |
160 | + | PORTB = ALL_ON; |
161 | - | { |
161 | + | for (i=START_CH; i < NUM_OF_CH; i++) |
162 | - | PORTB &= ~(1 << i); |
162 | + | { |
163 | - | delay_ms(time); |
163 | + | PORTB &= ~(1 << i); |
164 | - | } |
164 | + | delay_ms(time); |
165 | } | |
166 | - | } |
166 | + | |
167 | } | |
168 | - | } |
168 | + | |
169 | - | else |
169 | + | } |
170 | - | { |
170 | + | else |
171 | - | if (onoff == on ) |
171 | + | { |
172 | - | { |
172 | + | if (onoff == on ) |
173 | - | //reverse rotates through. |
173 | + | { |
174 | - | PORTB = ALL_OFF; |
174 | + | // Animates by reverse rotating through. |
175 | - | for (i=( START_CH + NUM_OF_CH - 1); i >= 0; i--) |
175 | + | PORTB = ALL_OFF; |
176 | - | { |
176 | + | for (i=( START_CH + NUM_OF_CH - 1); i >= 0; i--) |
177 | - | PORTB |= (1 << i); |
177 | + | { |
178 | - | delay_ms(time); |
178 | + | PORTB |= (1 << i); |
179 | - | } |
179 | + | delay_ms(time); |
180 | - | } |
180 | + | } |
181 | - | else |
181 | + | } |
182 | - | { |
182 | + | else |
183 | - | //reverse rotates through. |
183 | + | { |
184 | - | PORTB = ALL_ON; |
184 | + | // Animates by reverse rotating through. |
185 | - | for (i=( START_CH + NUM_OF_CH - 1); i >= 0; i--) |
185 | + | PORTB = ALL_ON; |
186 | - | { |
186 | + | for (i=( START_CH + NUM_OF_CH - 1); i >= 0; i--) |
187 | - | PORTB &= ~(1 << i); |
187 | + | { |
188 | - | delay_ms(time); |
188 | + | PORTB &= ~(1 << i); |
189 | - | } |
189 | + | delay_ms(time); |
190 | - | } |
190 | + | } |
191 | - | } |
191 | + | } |
192 | } | |
193 | ||
194 | } | |
195 | ||
196 | - | int low_read() |
196 | + | int read_prox(int pin) |
197 | { | |
198 | // This function allows for some debouncing | |
199 | - | if (bit_is_set(PIND, PD0)) |
199 | + | |
200 | - | { |
200 | + | if (bit_is_set(PIND, pin)) |
201 | - | delay_ms(1); |
201 | + | { |
202 | - | if (bit_is_set(PIND, PD0)) |
202 | + | delay_ms(1); |
203 | - | { |
203 | + | if (bit_is_set(PIND, pin)) |
204 | - | delay_ms(5); |
204 | + | { |
205 | - | return 1; |
205 | + | return 1; |
206 | - | } |
206 | + | } |
207 | - | } |
207 | + | } |
208 | ||
209 | - | return 0; |
209 | + | return 0; |
210 | } | |
211 | ||
212 | - | int high_read() |
212 | + | |
213 | { | |
214 | ||
215 | - | if (bit_is_set(PIND, PD1)) |
215 | + | //[tbd] read motion sensor |
216 | - | { |
216 | + | |
217 | - | delay_ms(1); |
217 | + | return 0; |
218 | - | if (bit_is_set(PIND, PD1)) |
218 | + | |
219 | - | { |
219 | + | |
220 | - | delay_ms(5); |
220 | + | |
221 | - | return 1; |
221 | + | |
222 | - | } |
222 | + | |
223 | - | } |
223 | + | // Set direction registers |
224 | // sensors data direction | |
225 | - | return 0; |
225 | + | // lighting data direction |
226 | ||
227 | DDRA = 0b11111111; | |
228 | DDRB = 0b11111111; | |
229 | DDRD = 0b00000000; | |
230 | ||
231 | - | //[tbd] read motion sensor |
231 | + | // Enable Wake Interrupts |
232 | //[TBD] | |
233 | - | return 0; |
233 | + | |
234 | // Set power down mode | |
235 | //[tbd] | |
236 | ||
237 | } | |
238 | ||
239 | - | // Set direction registers |
239 | + | |
240 | - | // sensors data direction |
240 | + | |
241 | - | // lighting data direction |
241 | + | |
242 | //-------------------------------------- | |
243 | - | DDRA = 0b11111111; |
243 | + | |
244 | - | DDRB = 0b11111111; |
244 | + | |
245 | - | DDRD = 0b00000000; |
245 | + | // Local Variables |
246 | int low_store = 0, high_store = 0, sens_store; | |
247 | int trigger_direction; | |
248 | - | // Enable Wake Interrupts |
248 | + | int counterA, counterB; |
249 | - | //[TBD] |
249 | + | int motion_store = 0; |
250 | - | |
250 | + | int TIMEOUT_MAX = 117; // approx >30 seconds, (30*1000/255) ~= 117 |
251 | - | // Set power down mode |
251 | + | |
252 | - | //[tbd] |
252 | + | // Pin position of Prox Sensors |
253 | int LOWPIN = PD0; | |
254 | int HIGHPIN = PD1; | |
255 | ||
256 | // Initialize registers | |
257 | init_cpu(); | |
258 | ||
259 | // Turn off LEDs | |
260 | PORTB = 0x00; | |
261 | ||
262 | - | int low_store = 0, high_store = 0; |
262 | + | // Loop forever |
263 | - | int trigger_direction; |
263 | + | // TBD: Replace with timeout to sleep and save power |
264 | - | int counterA, counterB; |
264 | + | while(1) |
265 | - | int motion_store = 0; |
265 | + | { |
266 | - | int TIMEOUT_MAX = 117; //~30 seconds |
266 | + | low_store = 0; |
267 | high_store = 0; | |
268 | - | init_cpu(); |
268 | + | counterA = 0; |
269 | counterB = 0; | |
270 | - | //turn off LEDs |
270 | + | motion_store = 0; |
271 | - | PORTB = 0x00; |
271 | + | sens1_store = 0; |
272 | sens2_store = 0; | |
273 | - | while(1) |
273 | + | |
274 | - | { |
274 | + | // Wait for trigger on any sensor |
275 | - | low_store = 0; |
275 | + | while((low_store != 1) && |
276 | - | high_store = 0; |
276 | + | (high_store != 1) && |
277 | - | counterA = 0; |
277 | + | (motion_store != 1)) |
278 | - | counterB = 0; |
278 | + | { |
279 | - | motion_store = 0; |
279 | + | |
280 | // Read the sensor data and store local | |
281 | - | //wait for either ADC to match (ADC0 > ADC2) | (ADC1 > ADC3) |
281 | + | low_store = read_prox(LOWPIN); |
282 | - | while((low_store != 1) && (high_store != 1) && (motion_store != 1)) |
282 | + | high_store = read_prox(HIGHPIN); |
283 | - | { |
283 | + | motion_store = motion_read(); |
284 | - | |
284 | + | |
285 | - | //read the sensor data and store local |
285 | + | } |
286 | - | low_store = low_read(); |
286 | + | |
287 | - | high_store = high_read(); |
287 | + | // Determine which condition fired, so that the other may be watched later |
288 | - | motion_store = motion_read(); |
288 | + | if (low_store == 1) |
289 | { | |
290 | - | } |
290 | + | // Low sensor fired |
291 | - | |
291 | + | trigger_direction = low; |
292 | ||
293 | - | //Determine which condition fired, so that the other may be watched later |
293 | + | // Play animations for low to high |
294 | - | if (low_store == 1) |
294 | + | animate_sequence(up, on); |
295 | - | { |
295 | + | |
296 | - | //low sensor fired |
296 | + | } |
297 | - | trigger_direction = low; |
297 | + | else if (high_store == 1) |
298 | { | |
299 | - | // play animations for low to high |
299 | + | // High sensor fired |
300 | - | animate_sequence(up, on); |
300 | + | trigger_direction = high; |
301 | ||
302 | - | //turn on leds in low to high sequence |
302 | + | // Play animations for high to low |
303 | animate_sequence(down, on); | |
304 | - | //wait for high sensor |
304 | + | |
305 | - | while((high_read() != 1) && (counterB <= TIMEOUT_MAX)) |
305 | + | } |
306 | - | { |
306 | + | else |
307 | - | counterA++; |
307 | + | { |
308 | - | delay_ms(1); |
308 | + | //[tbd] motion detected animation |
309 | - | if (counterA >= 255) |
309 | + | } |
310 | - | { |
310 | + | |
311 | - | counterA = 0; |
311 | + | // Wait for other sensor or Timeout Counter |
312 | - | counterB++; |
312 | + | while((counterB <= TIMEOUT_MAX) && (sens1_store != 1)) |
313 | - | } |
313 | + | { |
314 | - | |
314 | + | |
315 | - | if ((motion_read() == 1) || (low_read() == 1)) |
315 | + | // Determine which is next sensor to watch |
316 | - | { |
316 | + | if (trigger_direction == low) |
317 | - | //motion detected, reset timer, turn lights on |
317 | + | { |
318 | - | counterB = 0; |
318 | + | sens1_store = read_prox(HIGHPIN); |
319 | - | PORTB = ALL_ON; |
319 | + | sens2_store = read_prox(LOWPIN); |
320 | - | } |
320 | + | } |
321 | - | |
321 | + | else if (trigger_direction == high) |
322 | - | if (counterB > (2*TIMEOUT_MAX/3)) |
322 | + | { |
323 | - | { |
323 | + | sens1_store = read_prox(LOWPIN); |
324 | - | //play standby animation (timeout is 2/3s complete) |
324 | + | sens2_store = read_prox(HIGHPIN); |
325 | - | standby_sequence(counterB); |
325 | + | } |
326 | - | } |
326 | + | motion_store = motion_read(); |
327 | ||
328 | - | } |
328 | + | // Determine if timeout counter should be reset |
329 | if ((motion_store == 1) || (sens2_store == 1)) | |
330 | - | //turn off LEDs |
330 | + | { |
331 | - | animate_sequence(up, off); |
331 | + | // Motion detected, reset timer |
332 | counter_high = 0; | |
333 | - | } |
333 | + | |
334 | - | else if (high_store == 1) |
334 | + | // Turn lights on |
335 | - | { |
335 | + | PORTB = ALL_ON; |
336 | - | //high sensor fired |
336 | + | } |
337 | - | trigger_direction = high; |
337 | + | |
338 | // Timeout Counters, 1 tick >= 1ms. | |
339 | - | //play animations for high to low |
339 | + | counter_low++; |
340 | - | animate_sequence(down, on); |
340 | + | delay_ms(1); |
341 | if (counter_low >= 255) | |
342 | - | //wait for low sensor |
342 | + | { |
343 | - | //also timeout |
343 | + | counter_low = 0; |
344 | - | while((low_read() != 1) && (counterB <= TIMEOUT_MAX)) |
344 | + | counter_high++; |
345 | - | { |
345 | + | } |
346 | - | counterA++; |
346 | + | |
347 | - | delay_ms(1); |
347 | + | // Determine if timeout is 2/3rds complete |
348 | - | if (counterA >= 255) |
348 | + | if (counter_high > (2*TIMEOUT_MAX/3)) |
349 | - | { |
349 | + | { |
350 | - | counterA = 0; |
350 | + | // Play standby animation |
351 | - | counterB++; |
351 | + | standby_sequence(counter_high); |
352 | - | } |
352 | + | } |
353 | - | |
353 | + | |
354 | - | if ((motion_read() == 1) || (high_read() == 1)) |
354 | + | } // End wait for Timeout |
355 | - | { |
355 | + | |
356 | - | //motion detected, reset timer, turn lights on |
356 | + | // Turn off LEDs in proper sequence |
357 | - | counterB = 0; |
357 | + | if (trigger_direction == low) |
358 | - | PORTB = ALL_ON; |
358 | + | { |
359 | - | } |
359 | + | animate_sequence(up, off); |
360 | - | |
360 | + | } |
361 | - | if (counterB > (2*TIMEOUT_MAX/3)) |
361 | + | else if (trigger_direction == high) |
362 | - | { |
362 | + | { |
363 | - | //play standby animation (timeout is 2/3s complete) |
363 | + | animate_sequence(down, off); |
364 | - | standby_sequence(counterB); |
364 | + | } |
365 | - | } |
365 | + | |
366 | // Small delay before lights are allowed to trigger again | |
367 | - | |
367 | + | delay_ms(2000); |
368 | - | } |
368 | + | |
369 | } // End Inf Loop | |
370 | - | //turn off LEDs |
370 | + | |
371 | - | animate_sequence(down, off); |
371 | + | |
372 | ||
373 | - | } |
373 | + |