/*
- * Asking Riddles at the Entrance to Garage
+ * The Sphinx -- A Device for Asking Riddles at the Entrance to the Garage
*
* (c) 2017 Martin Mares <mj@ucw.cz>
*/
*
* +-------------------+
* | RESET* VCC |
- * button | PB3 SCK |
+ * button* | PB3 SCK |
* output | PB4 MISO |
* | GND PB0=MOSI | diagnostic LED*
* +-------------------+
+ *
+ * Note that MOSI is used for programming, so the LED is connected
+ * via jumper, which must be open during programming.
*/
#define F_CPU 1200000UL
+#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>
typedef uint8_t byte;
+typedef uint16_t u16;
#define B(x) (1U<<(x))
}
}
+static byte out_pulse;
+#define OUT_PULSE_WIDTH 100
+static byte debounce;
+#define DEBOUNCE_THRESHOLD 3
+static byte pressed;
+static u16 press_timer;
+#define LONG_PRESS 500
+static byte second_timer;
+static byte unlocked;
+#define UNLOCK_SECONDS 20
+
+ISR(TIM0_COMPA_vect)
+{
+ if (out_pulse) {
+ if (!--out_pulse)
+ PORTB &= ~B(PB4);
+ }
+
+ if (!second_timer) {
+ second_timer = 100;
+ if (unlocked)
+ unlocked--;
+ }
+ second_timer--;
+
+ if (PINB & B(PB3)) {
+ // Switch open
+ if (debounce)
+ debounce--;
+ else
+ pressed = 0;
+ } else {
+ // Switch closed
+ if (debounce < DEBOUNCE_THRESHOLD)
+ debounce++;
+ else
+ pressed = 1;
+ }
+
+ if (unlocked) {
+ if (!(second_timer & 7))
+ PORTB ^= B(PB0);
+ if (pressed) {
+ if (out_pulse < 2)
+ out_pulse = 2;
+ PORTB |= B(PB4);
+ unlocked = UNLOCK_SECONDS;
+ }
+ } else {
+ if (!pressed) {
+ PORTB |= B(PB0);
+ press_timer = 0;
+ } else {
+ PORTB &= ~B(PB0);
+ if (press_timer < LONG_PRESS) {
+ press_timer++;
+ if (press_timer == LONG_PRESS) {
+ out_pulse = OUT_PULSE_WIDTH;
+ PORTB |= B(PB4);
+ unlocked = UNLOCK_SECONDS;
+ }
+ }
+ }
+ }
+}
+
int main(void)
{
- DDRB |= B(PB0); // PB0: output
- DDRB |= B(PB4); // PB4: output
- PORTB &= ~B(PB3); // PB3: input, no pullup
+ // PB0: output for diagnostic LED
+ DDRB |= B(PB0);
+
+ // PB3: button input, needs pull up
+ PORTB |= B(PB3);
+
+ // PB4: output to control the gate
+ PORTB &= ~B(PB4);
+ DDRB |= B(PB4);
for (byte i=0; i<5; i++) {
PORTB &= ~B(PB0);
- sleep(100);
+ sleep(50);
PORTB |= B(PB0);
- sleep(100);
+ sleep(50);
}
+#if 0
+ // Copy mode
for (;;) {
sleep(10);
if (PINB & B(PB3)) {
- PORTB &= ~B(PB0);
- PORTB |= B(PB4);
- } else {
PORTB |= B(PB0);
PORTB &= ~B(PB4);
+ } else {
+ PORTB &= ~B(PB0);
+ PORTB |= B(PB4);
}
}
+#endif
+
+ // Set up timer interrupt
+ TCCR0A = 0x02; // No OC pins, clear on compare
+ TCCR0B = 0x05; // Run at CLK_IO / 1024
+ OCR0A = 11; // Approximately once in 10ms
+ TIMSK0 = B(OCIE0A); // Interrupt on compare
+ sei();
+ // Sleep well, my little sphinx
for (;;) {
- set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
}
}