/* GONG MELODY GENERATOR
*Questo dispositivo consente di implementare la funzionalità "GONG" su una
*qualsiasi centrale anti intrusione. Detta funzionalità consiste nella
*emissione di una melodia ogni qualvolta un ingresso passa da chiuso
*(verso GND) ad aperto. Gli ingressi previsti sono due: Door e Window.
*Essi si riferiscono rispettivamente al sensore montato sul portoncino di
*ingresso ed alla serie di sensori installati nella protezione perimetrale
*delle finestre. La riproduzione della melodia associata all'ingresso
*"Door" viene inibita per 30 minuti ogni volta che lo stesso passa da
*riposo ad intervenuto. Il timer è del tipo retriggerabile.
*La routine di gestione dei timer può gestire 4 timer ma ne è utilizzato
*soltanto uno. La riproduzione della melodia prende spunto da un lavoro di
*David Johnson-Davies - www.technoblogy.com - "Digital Music Box v2" 16/3/2016
*/
// ATtiny85 Gong generator for anti intrusion system
// Author: Giuseppe Fiordaliso
// ATMEL ATTINY 85
//
// +- \/-+
// RST non usato PB5 1|* |8 Vcc
// Uscita LED(L) PB3 2| |7 PB2 Sensori Finestre
// Uscita B.F. PB4 3| |6 PB1 Sensore Porta
// GND 4| |5 PB0 Inserzione/Disins.
// +-----+
//
#include <avr/io.h>
#define abl PB0 // PIN 5 Inserzione / Disinserzione dispositivo
#define gate_pin PB1 // PIN 6 Sensore portoncino ingresso (NC)
#define window_pin PB2 // PIN 7 Linea sensori Finestre (NC)
#define LED PB3 // PIN 2 Uscita LOW durante il suono del Gong
// utile per comandare lo stand-by
// di un amplificatore tipo LM4819
#define speakerPin PB4 // PIN 3 Uscita bassa frequenza suono melodia
//
int Scale[] = {
680, 721, 764, 809, 857, 908, 962, 1020, 1080, 1144, 1212, 1284,
1361, 1442, 1528, 1618, 1715, 1817, 1925, 2039, 2160, 2289, 2425, 2569,
2722, 2884, 3055, 3237, 3429, 3633, 3849, 4078 };
const int Channels = 4;
const int Tempo = 4; // 4 = 4 beats per second (3 = 0,125 sec, 4 = 0,25 sec, 5 = 0,5 sec, 6 = 1 sec - min = 0, max = 8)
const int Decay = 10; // Length of note decay; max 10
volatile unsigned int Acc[Channels];
volatile unsigned int Freq[Channels];
volatile unsigned int Amp[Channels];
//
/*
// Play Big Ben
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000100000000000100000000000000, // F F
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b10000000000000000001000000000000, // G C
0b00000000000000000000000000000000, //
0b00000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b10000000000010000000000000000000, // C C
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b00000100000000000000010000000000, // A F
0b00000000000000000000000000000000, //
0b00000000000000000100000000000000, // F
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000100000000000000010000000000, // A F
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b10000000000000000100000000000000, // F C
0b00000000000000000000000000000000, //
0b00000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b10000000000010000000000000000000, // C C
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b00000100000000000000010000000000, // A F
0b00000000000000000000000000000000, //
0b00000000000000000100000000000000, // F
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
*/
/*
// Play Happy Birthday
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000001000000000000,
0b00000000000000000001000000000000,
0b10000000000000000000010000000000,
0b00000000000000000000000000000000,
0b00001001000000000001000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000010000000,
0b00000000000000000000000000000000,
0b00100000000000000000000100000000,
0b00000000000000000000000000000000,
0b00000101000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000001000000000000,
0b00000000000000000001000000000000,
0b10000000000000000000010000000000,
0b00000000000000000000000000000000,
0b00000101000000000001000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000100000,
0b00000000000000000000000000000000,
0b10000000000000000000000010000000,
0b00000000000000000000000000000000,
0b00001001000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000001000000000000,
0b00000000000000000001000000000000,
0b10000000000000000000000000000001,
0b00000000000000000000000000000000,
0b00100000000000000000000000001000,
0b00000000000000000000000000000000,
0b00001000000000000000000010000000,
0b00000000000000000000000000000000,
0b00000100000000000000000100000000,
0b00000000000000000000000000000000,
0b00000000000000000000010000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000100,
0b00000000000000000000000000000100,
0b00000001000000000000000000001000,
0b00000000000000000000000000000000,
0b00000000000000000000000010000000,
0b00000000000000000000000000000000,
0b00000101000000000000000000100000,
0b00000000000000000000000000000000,
0b10001001000000000000000010000000,
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
*/
const uint32_t tuneDoor[] PROGMEM = {
// Play Big Ben
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00001000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b10000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00100000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000100000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00000000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000010000000000000000000, // C
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
/*
// Play close encounters melody
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000100000000, // B
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G<
0b00000000000000000000000000000000, //
0b00000000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000001000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C
0b00000000000000000000000000000000, //
0b10000000000000000000000000000000, // C<
0b00000000000000000000000000000000, //
0b00000001000000000000000000000000, // G<
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
//
*/
/*
const uint32_t tuneWindow[] PROGMEM = {
// Play per un pugno di dollari
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D>
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000001000000000000, // G
0b00000000000000000000000000000000, //
0b00000000000000100000000000000000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
*/
/*
* C O N T I N U A Z I O N E
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D
0b00000000000000000000000000001000, // E
0b00000000000000000000000000100000, // D
0b00000000000000000000000000100000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000001000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000000000100, // F
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, // A
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000100000, // D
0b00000000000000000000000000001000, // E
0b00000000000000000000000000100000, // D
0b00000000000000000000000000100000, // D
0b00000000000000000000000000000000, //
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000000000010000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000010000000000, //
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0xFF}; // End of tune
*/
const uint32_t tuneWindow[] PROGMEM = {
// Play Morricone clock melody
// C -> DO, D -> RE, E -> MI, F -> FA, G ->SOL, A -> LA, B -> SI,
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000010000000000100000000, // C B
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000000001000010000000000, // E A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000010000000000100000000, // C B
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000000001000010000000000, // E A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
//
//_*_*__*_*_*__*_*__*_*_*__*_*__*_
//C D EF G A BC D EF G A BC D EF G
0b00000000000010000000000100000000, // C B
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000000001000010000000000, // E A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000010000000000100000000, // C B
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000010000000, // C>
0b00000000000000000000000000000000, //
0b00000000000000001000010000000000, // E A
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000001000000000000000, // E
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
0b00000000000000000000000000000000, //
//
0xFF}; // End of tune
//
//Globals persist throughout tune
int TunePtr = 0, Chan = 0;
//
#define abl PB0 // PIN 5 ATtiny85
#define door_pin PB1 // PIN 6 ATtiny85
#define window_pin PB2 // PIN 7 ATtiny85
#define LED PB3 // PIN 2 ATtiny85
#define speakerPin PB4 // PIN 3 ATtiny85
// RESET non collegato PIN 1 ATtiny85
// + 5 V PIN 8 ATtiny85
// GND PIN 4 ATtiny85
//
// ************* DICHIARAZIONE VARIABILI PER LA GESTIONE DEI TIMER ************
//
volatile boolean tickFlag;
boolean ledState;
const int NTIMER = 5; // Numero di timer che si vogliono gestire
unsigned int timerpreset[NTIMER];
boolean startimer[NTIMER];
boolean runtimer[NTIMER];
boolean stoptimer[NTIMER];
boolean endtimer[NTIMER];
boolean abortimer[NTIMER];
unsigned int timercounter[NTIMER];
//
// ************* DICHIARAZIONE VARIABILI DEL PROGRAMMA ************
//
boolean Inserito;
boolean Open_door;
boolean Open_window;
boolean prev_Open_door;
boolean prev_Open_window;
boolean playDoor_flag;
boolean playWindow_flag;
volatile boolean playMelody_flag;
//
// ************* DICHIARAZIONE VARIABILI DEL PLAYER ************
//
const uint32_t *puntatore;
// ************** S E T U P ************
void setup() {
// Abilita il PLL a 64 MHz e lo usa come sorgente di clock per il Timer1
PLLCSR = 1<<PCKE | 1<<PLLE;
// Setta il Timer 1 per utilizzarlo come generatore PWM
TIMSK = 0; // Timer interrupts OFF
TCCR1 = 1<<CS10; // 1:1 prescaler asincrono
GTCCR = 1<<PWM1B | 2<<COM1B0; // PWM basato su OCR1B, azzera l'uscita associata ad OC1B all'eguaglianza
// OC1B ->PB4
OCR1B = 128;
// DDRB = 1<<DDB4; // Enable PWM output on pin 4
// Set up Timer/Counter0 for 20kHz interrupt to output samples.
TCCR0A = 3<<WGM00; // Fast PWM
TCCR0B = 1<<WGM02 | 2<<CS00; // 1/8 prescale
OCR0A = 99; // Divide by 100
TIMSK = 1<<OCIE0A; // Enable compare match, disable overflow
// Set up Watchdog timer for 4 Hz interrupt for note output.
WDTCR = 1<<WDIE | Tempo<<WDP0; // imposta interrupt su Watchdog e prescaler WDT col valore di "Tempo"
//
pinMode(abl, INPUT_PULLUP);
pinMode(door_pin, INPUT_PULLUP);
pinMode(window_pin, INPUT_PULLUP);
pinMode(LED, OUTPUT);
//
timerpreset[0]=6666; // Tempo di inibizione gong porta di ingresso. (6666/54)/60 = 30 minuti
timerpreset[1]=37; // 37 = 10 secondi
timerpreset[2]=37; // 37 = 10 secondi
timerpreset[3]=37; // 37 = 10 secondi
timerpreset[4]=37; // 37 = 10 secondi
}
//
// ********************* L O O P ********************
//
void loop() {
timermanager(); // Routine di gestione dei timer
Inserito = digitalRead(abl); // Leggi ingresso di inserzione dispositivo
if (Inserito){ // Se inserito analizza lo stato degli ingressi Door e Window
prev_Open_door = Open_door; // Salva lo stato del ciclo precedente di Door
prev_Open_window = Open_window; // Salva lo stato del ciclo precedente di Window
Open_door = digitalRead(door_pin); // Leggi lo stato attuale di Door
Open_window = digitalRead (window_pin); // Leggi lo stato attuale di Window
Open_door = digitalRead (door_pin); // Leggi lo stato attuale di Door
if (Open_window && !prev_Open_window){ // Se Window passa da riposo ad intervenuto
if (!playMelody_flag){ // e non è in corso il Play di una melodia
puntatore = tuneWindow; // dai lo start al play di tuneWindow
playMelody();
}
}
if (Open_door && !prev_Open_door){ // La melodia relativa all'ingresso Door
if (!runtimer[0]){ // viene avviata quando il relativo ingresso
puntatore = tuneDoor; // passa da riposo ad intervenuto e non è in
playMelody(); // corso il conteggio del tempo di inibizione
} // suoneria. Dopo il Play viene avviato detto tempo
startimer[0] = true; // che attualmente è impostato a 30 minuti.
} // Il conteggio del timer viene riavviato ad
} // ogni intervento dell'ingresso Door.
else { // Se il dispositivo è disinserito
playDoor_flag = false; // resetta tutti i flag
playWindow_flag = false;
playMelody_flag = false;
abortimer[0]=true;
}
if (!playMelody_flag) // Se stai riproducendo una melodia, attiva
digitalWrite (LED, HIGH); // l'uscita di abilitazione dell'amplificatore
} // di B.F.
//
// ********************** END LOOP ************************
//
//
// ********************** playMelody ************************
void playMelody (){
digitalWrite (LED, LOW);
playMelody_flag = true;
TunePtr = 0, Chan = 0;
DDRB = DDRB | 0X10;
}
//
// ********************** timermanager ***********************
/*
* ROUTINE DI GESTIONE DEI TIMER "timermanager"
* La routine gestisce un numero di timer definito da
* "NTIMER". Il timer viene avviato settando a TRUE
* nel corso del programma il startimer[] corrispondente.
* La routine in questo caso carica timercounter[] con il
* valore di timerpreset[] e provvede poi a decrementarlo
* ogni volta che sono trascorsi i ms specificati da steptick
* quindi resetta startimer[], e setta runtimer[] per tutto
* il tempo in cui timercounter è > 0.
* Quando timercounter[] arriva a zero viene settato endtimer[]
* e viene resettato runtimer[]. E' a cura del programma
* chiamante resettare poi endtimer[].
*/
//
void timermanager(){
// tickFlag viene settato dalla routine di servizio del WDT che scandisce anche la successione delle note
// della melodia. Nel caso di "Tempo = 4" questo avviene 4 volte al secondo. Per l'esattezza in un minuto 54 volte
if (tickFlag){
tickFlag = false;
for (int i=0; i<NTIMER; i++){
if (startimer[i]==true){ // Controlla se c'è lo start del timer
timercounter[i] = (timerpreset[i]+1); // Se si carica il contatore con il
startimer[i]=false; // valore di preset.
runtimer[i]=true; // Resetta startimer e setta runtimer
}
if (abortimer[i]){ // se è richiesto l'abort azzera conteggio
timercounter[i] = 0; // e resetta la richiesta di abort
runtimer[i] = false;
abortimer[i] = false;
}
if (!stoptimer[i]){ // Se è richiesto lo stop salta aalla fine
if (timercounter[i]>0) { // Se timercounter è maggiore di zero
timercounter[i]--; // decrementalo di uno quindi verifica se è
if (timercounter[i] == 0){ // arrivato a zero. In tal caso setta endtimer[]
runtimer[i] = false; // e resetta runtimer[].
endtimer[i] = true;
}
}
}
}
}
}
// **************** ROUTINE DI SERVIZIO ALL'INTERRUPT DEL WDT ****************
// Watchdog interrupt plays notes
ISR(WDT_vect) {
sei(); // Abilita interrupt
/* L'interruzione del watchdog ripristina automaticamente il timer del watchdog
* in modo da provocare un reset al successivo interrupt; per evitare ciò è necessario
* impostare il bit di interruzione prima dell'interruzione successiva: */
WDTCR |= 1<<WDIE;
unsigned long Chord = pgm_read_dword(&puntatore[TunePtr]); // Analizza un nuovo step della sequenza
tickFlag = true;
if (Chord == 0xFF){
DDRB = DDRB & 0x2F ;
playMelody_flag = false;
return; // Se in questo step c'è "0XFF" allora sei a fine melodia
}
TunePtr++; // Altrimenti incrementa puntatore allo step successivo
// Analizza i singoli bit ovvero le singole note dello step
for (int Note = 0; Note < 32; Note++) { // 32 sono i bit che identificano ciascuna nota
if ((Chord & 0x80000000) != 0) { // Analizza il primo bit da sinistra e se è a 1
Freq[Chan] = Scale[Note]; // assegna il valore corrispondente di scale[]
Amp[Chan] = 1<<(Decay+5);
Chan = (Chan + 1) % Channels; // Incrementa il canale in modo circolare (o, 1, 2, 3, 0, 1 ...)
}
Chord = Chord<<1; // shifta di 1 a sx per analizzare il bit successivo
}
}
//
// ************* ROUTINE DI SERVIZIO ALL'INTERRUPT DEL TIMER 0 *************
// Genera le onde quadre per le frequenze dei quattro canali
ISR(TIMER0_COMPA_vect) {
signed char Temp, Mask, Env, Note, Sum=0;
for (int c = 0; c < Channels; c++) {
Acc[c] = Acc[c] + Freq[c];
// L'inviluppo di ciascuna nota viene generato da un contatore
Amp[c] = Amp[c] - (Amp[c] != 0); // di ampiezza per ciascun canale, Amp [c], che viene ridotto
// fino a raggiungere lo zero.
Temp = Acc[c] >> 8; // L'onda quadra viene generata testando il bit superiore
Mask = Temp >> 7; // dell'accumulatore per ciascun canale, Acc [c]
// Mask è impostato su 0x00 se il bit è zero o 0xFF se è uno:
Env = Amp[c] >> Decay; // Infine, la nota è impostata su + o - dell'ampiezza corrente dell'inviluppo, Env
Note = (Env ^ Mask) + (Mask & 1); // Lo stesso che scrivere: "if (Mask != 0) Note = Env; else Note = - Env;"
Sum = Sum + Note;
}
OCR1B = Sum + 128; // Compare register di TIMER 1
}