Un disturbatore acustico con PIC12F683

Overview

Il progetto in questione è un semplice disturbatore acustico:  un circuito che emette dei suoni ad intervalli di tempo regolari. Tutti noi abbiamo probabilmente qualche amico\parente che và facilmente in paranoia, sopratutto se appassionato dell’occulto o impaurito da animali che si infiltrano negli appartamenti; e chi di voi non ha mai sfruttato tali caratteristiche per tirargli uno scherzo? Ecco, questo è il progettino che fà per voi! Il circuito richiede una manciata di componenti ed è molto piccolo per cui può essere facilmente nascosto e lasciato li ad eseguire il suo lavoro per giorni e giorni destando dapprima curiosità e poi sicuramente un certo nervosismo!

Potrebbe in ogni caso anche rivelarsi utile, modificando i tempi, per far rimanere le persone in uno stato di attenzione ed essere quindi utilizzato come un semplice sistema anti-sonnolenza per i guidatori.

Il firmware

Partiamo dall’idea di base: il cicalino deve suonare ad intervalli di tempo regolari.  Gli intervalli di tempo verranno scanditi dall’interrupt generato dall’ overflow sul Timer0, nell’ISR viene settato un flag, “catturato” nel main, che fa partire il suono:

void interrupt ISR (void)
	{
	if (T0IF) //overflow timer0?
		{
		//...
                flag_sound=1; // abilito il suono nel main
               //...
void main(void)
{
//...
while(1)
		{
		// l'ISR ha abilitato la routine per il suono
		if (flag_sound)
			{
                        //...

Quando suonare? A seconda dell’utilizzo, ho scelto dei tempi  a 15-30 minuti ed 1-2 ore; ho inoltre previsto una modalità test col tempo di 1 minuto. Non resta quindi che fare un paio di conti tenendo conto che nei tempi di attesa utilizzeremo un clock da 32KHz. Calcoleremo il valore del numero massimo di interrupt che ho chiamato semplicemente timer e il preload del Timer0 per il tempo rimanente inferiore ad un overflow (queste cose abbiamo già imparato a farle qui):

// prova per il timing (60 s) / (((4 / (32 khz)) * 256) * 256) = 7.32421875 =7 
// 256 * 0.32421875 = 83
// (15 * 60 s) / (((4 / (32 khz)) * 256) * 256) = 109.863281 =109 
// 256 * 0.863281=220.999936
// (30 * 60 s) / (((4 / (32 khz)) * 256) * 256) = 219.726562 = 219 
// 256 * 0.726562 = 185.999872
// (1 hour) / (((4 / (32 khz)) * 256) * 256) = 439.453125 = 439 
// 256 * 0.453125 = 116
// 2 ore
// (2 hour) / (((4 / (32 khz)) * 256) * 256) = 878.90625 = 876
// 256 * 0.90625 = 232

Come selezionare l’una o l’altra modalità? L’idea di base è un circuito miniaturizzato con il  minor numero possibile di componenti, quindi voglio farmi bastare un unico pulsante ma senza perdere la possibilità di poter resettare il sistema qualora qualcosa andasse storto. Utilizzerò quindi il solo pulsante di reset per eseguire la selezione della modalità di funzionamento! Come? Lo scopriamo tra un po’.

In aggiunta voglio anche mandare il sistema in sleep, ovvero in una modalità a basso consumo, quando il pic non deve eseguire nessun compito:  tale modalità viene eseguita dalla funzione SLEEP() presente nella libreria standard htc.h. L’unico modo per risvegliare il pic dallo sleep è con un reset hardware (ovvero MCLR portato a massa) oppure con un interrupt on change su GPIO.

La soluzione che ho ideato, per poter utilizzare il reset come selezione modalità, sfrutta l’eeprom interna. Innanzitutto azzero le prime 8 locazioni di eeprom (in realtà mi serve solo la locazione zero, ma la macro __EEPROM_DATA richiede comunque 8 bytes come già spiegato in un articolo precedente):

__EEPROM_DATA(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); //azzeriamo la memoria dell'e2prom

Utilizzo la locazione 0x00 dell’ eeprom per memorizzare lo stato del menù. All’avvio eseguo la lettura di tale locazione di memoria e la incremento di 1, memorizzo quindi il tutto nella variabile che ho chiamato stat:

stat=eei_read_byte(0)+1; //recupero lo stato precedente del menù, e passo alla prossima voce

Il nuovo valore di stat rappresenta in pratica la voce di menù successiva a quella precedente. Salvo quindi in eeprom il nuovo valore controllando di rimanere nel range di valori 1-6 e lo salvo nuovamente nell’eeprom:

if (stat==7)stat=1;      //controllo se sono fuori
eei_write_byte(stat,0);  //salvo i dati nell'e2prom

In breve: all’avvio il programma carica lo stato memorizzato nell’eeprom alla locazione 0x00, salvandola nella variabile stat; la incrementa e sovrascrive il valore. Resettando più volte il pic avremo che ad ogni riavvio, ciclicamente, saremo in una posizione diversa, ed ecco che anche il pulsante di reset può essere utilizzato per eseguire lo scorrimento di un menù!

Dal momento che sul circuito non vi sono led, display o altre spie potremo renderci conto della voce di menù nella quale ci troviamo facendo suonare il cicalino in maniera diversa ad ogni selezione: questo lo eseguo con un blocco Switch…Case:

// controllo in che posizione del menù mi trovo
	// ed emetto un suono diverso a seconda della voce selezionata
	switch(stat)
		{
		case 0x01:
		// prova per il timing
		// (60 s) / (((4 / (32 khz)) * 256) * 256) = 7.32421875
		// preload: 256 * 0.32421875 = 83
		suona(250,1);
		suona(250,1);
		suona(250,1);
		limit=7;
		pre=83;
		break;
 
		// 15 minuti
		// (15 * 60 s) / (((4 / (32 khz)) * 256) * 256) = 109.863281
		// preload: 	256 * 0.863281=220.999936
		case 0x02:
		suona(1,100);
		limit=109;
		pre=221;
		break;
 
		case 0x03:
		// 30 minuti
		// (30 * 60 s) / (((4 / (32 khz)) * 256) * 256) = 219.726562
		// preload: 256 * 0.726562 = 185.999872
		suona(1,100);
		suona(1,100);
		limit=219;
		pre=186;
		break;
 
		case 0x04:
		// 1 ora
		// (1 hour) / (((4 / (32 khz)) * 256) * 256) = 439.453125
		// preload: 256 * 0.453125 = 116
		suona(1,200);
		limit=439;
		pre=116;
		break;
 
		case 0x05:
		//	2 ore
		// (2 hour) / (((4 / (32 khz)) * 256) * 256) = 878.90625
		// preload:	256 * 0.90625 = 232
		suona(1,200);
		suona(1,200);
		limit=878;
		pre=232;
		break;
 
		case 0x06:// spento
		suona(1,500);
		SLEEP();
		break;
 
		default:// errore
		while(1) suona(50,100);
		break;
		}

La voce di menù 6, l’ultima, è quella che mette il pic in condizioni di riposo. In caso qualcosa andasse storto (es.: guasto eeprom interna, per cui si potrebbe avere un valore al di fuori del range 1-6), viene valutata la condizione indicata come “default” e il cicalino suona di continuo.

L’abbiamo capito: il pic suonerà più volte il “campanello”, quindi risulta utile utilizzare una funzione, che ho chiamato semplicemente suona: l’ho impostata in modo che accetti due valori in ingresso, quello di inizio e di fine, dopodichè genereremo un’onda quadra come farebbe un chirper. La funzione prevede anche di controllare se il suono è diretto verso l’alto o verso il basso.

Il problema sembrerebbe risolto, ma  non abbiamo calcolato una cosa: i consumi! Se il pic consumerà parecchio avremo bisogno di una fonte di alimentazione capace, ed un trasformatore di rete non è di certo la cosa più stealth di cui possiamo disporre. Voglio anche evitare di utilizzare pile AA / AAA che sono troppo ingombranti. Ho quindi optato per una batteria a bottone tipo CR2032. Iniziamo quindi ad impostare l’oscillatore interno, sul modello di pic che ho scelto (un pic12F683) possiamo farlo variare tra 32kHz e 8MHz. Ho detto proprio variare, quindi perchè non farlo funzionare a 8MHz quando dobbiamo fare operazioni utili e a 32KHz quando è in attesa (il che ci consente di abbattere i consumi), letteralmente standby? Inoltre disattivamo le resistenze di pullup interne che in ogni caso dissipano energia:

OSCCON= 0b0000001; //metto a 32kHz così arrivo a 30uA di consumo
TMR0=pre; // carico il timer 0 col valore calcolato nello switch/case
INTCON= 0b10100000; // abilito gli interrupt globali e l'interrupt su timer0
OPTION= 0b10000111; // pullup disabilitate, prescaler 1:256

In questo modo avremo creato un sistema che consuma meno di 30μA, e ci permetterà di far funzionare il sistema con una sola batteria per molti molti squittii\fischiettii.

Il circuito

Circuitalmente il tutto è ridotto all’osso: un pic12f683 (ovviamente sovradimensionato per tale utilizzo), un transistor BC337 o un equivalente NPN (questo è quello che avevo in casa) che ci aiuterà a sfruttare tutta la potenza della batteria per fischiare ad un volume più alto, un buzzer di tipo passivo, un pulsante e un paio di resistenze e una batteria cr2032. Ricordo che il pic è alimentabile da 2 a 5v, con stabilità dell’oscillatore interno crescenti nell’intorno dei 3v. Il tutto entra in una basetta di 1×3.5cm circa, perfettamente nascondibile in una libreria o incollabile sotto un tavolo.

La R1, in realtà, sul PIC12F683 può essere omessa in quanto MCLR, quando configurato per la sua normale funzione di Master Clear, ha una resistenza di pullup integrata, per cui R1 è stata lasciata sullo schema in caso vogliate utilizzare, ad esempio, un più economico 12F675.

Per qualsiasi problema o commento, commentate questo articolo o contattatemi a mezzo mail su lucagallucci [at] email.it .

Downloads

Il download comprende codice sorgente, progetto MPLAB, schema elettrico in formato Eagle e programma già compilato.

 

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)