/* 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