/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* this firmware is for a cat repeller * it uses: * - andruino nano a micro-controller board * - HC-SR501 PIR motion detector * - E18-D80NK-N adjustable infrared sensor switch * - piezo buzzer */ #include // Standard Integer Types #include // Standard IO facilities #include // General utilities #include // Boolean #include // Strings #include // AVR device-specific IO definitions #include // Convenience functions for busy-wait delay loops #include // Interrupts #include // Watchdog timer handling #include // Program Space Utilities #include // Power Management and Sleep Modes #include "uart.h" // basic UART functions #include "main.h" // main definitions /* help strings */ const char help_00[] PROGMEM = "commands:\n"; const char help_01[] PROGMEM = "\thelp display this help\n"; const char help_02[] PROGMEM = "\tbeep T F beep for T ms at F Hz\n"; PGM_P const help_table[] PROGMEM = { help_00, help_01, help_02 }; /* global variables */ char uart_in[25]; // user input from USART volatile uint16_t ms = 0; // to count down the ms /* flags, set in the interrupts and handled in the main program */ volatile bool uart_flag = false; // UART input data is available volatile bool command_flag = false; // a command has been input volatile bool countdown_flag = false; // set when the ms countdown reached 0 volatile bool fridge_flag = false; // when the fridge switch changed volatile bool motion_flag = false; // when the PIR detected motion volatile bool barrier_flag = false; // when the light barrier got cut /* different melodies to play * pair of time in ms and tone in Hz * 0 ms to end * 0xffff ms to restart/loop */ #ifdef DEBUG const uint16_t MELODY_REPEL[] PROGMEM = {100,4000,100,0,100,3000,100,0,100,3000,100,0,100,3000,100,0,100,3000,100,0,500,5000,500,3000,500,5000,500,3000,500,5000,500,3000,0xffff}; // try to scare the cat const uint16_t MELODY_WARN[] PROGMEM = {100,4000,3000,0,500,4000,500,5000,500,4000,500,5000,500,4000,500,5000,0xffff}; // warn human opened fridge (anyone if left open) #else const uint16_t MELODY_REPEL[] PROGMEM = {100,4000,100,0,100,23000,100,0,100,23000,100,0,100,23000,100,0,100,23000,100,0,500,25000,500,23000,500,25000,500,23000,500,25000,500,23000,0xffff}; // try to scare the cat const uint16_t MELODY_WARN[] PROGMEM = {100,4000,30000,0,500,4000,500,5000,500,4000,500,5000,500,4000,500,5000,0xffff}; // warn human opened fridge (anyone if left open) #endif const uint16_t MELODY_ALARM[] PROGMEM = {500,5000,500,4000,0xffff,0xffff}; // sound alarm because cat opened the frigde const uint16_t* melody = NULL; // the current melody to play uint8_t melody_i = 0; // the current position in melody /* switch off LED */ void led_off(void) { LED_PORT &= ~(1<0) { // end of line (ignore empty lines) command_flag = true; // notify a command is ready uart_in_i = 0; // reset input } } else if (uart_in_i0) { ms--; // count down } if (0==ms) { // always verify, also when not counting down countdown_flag = true; // warn count down has finished } } /* PCI2 Interrupt Vector for PCINT[23:16]/PORTD */ ISR(PCINT2_vect) { static uint8_t fridge_state = 0; static uint8_t motion_state = 0; static uint8_t barrier_state = 0; if ((fridge_state&(1< Hz */ void set_tone (uint32_t freq) { // use prescale 1 to allow high frequencies and precision const uint16_t PRESCALE = 1; const uint8_t PRESCALE_CS = 1; // minimum frequency (formula 16.9.4 in ATmega328P datasheet) const uint32_t FREQ_MIN = (F_CPU/(PRESCALE*(1+(1UL<<16)))); // maximum frequency (min OCR1A is 0x0003) const uint32_t FREQ_MAX = (F_CPU/(PRESCALE*(1+3))); TCCR1B &= ~((1< FREQ_MAX) { printf("frequency to high. maximum: %lu Hz\n",FREQ_MAX); } else { ICR1 = (F_CPU/(PRESCALE*freq))-1; // set frequency OCR1A = ICR1/2; // set 50% duty cycle OCR1B = ICR1/2; // set 50% duty cycle TCCR1B |= (PRESCALE_CS< Hz for