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 | + |