- 28 mar 2018, 18:00
#5623
ROTARY PULSE TO DTMF TONE
Tempo fa ho scoperto che in un cassetto degli oggetti ormai catalogati come obsoleti, c'era ancora un bel telefono della SIP dei primi anni '80 il famigerato "bigrigio", per intenderci è il modello AUSO S62, così ho deciso di convertirlo rivisitandolo in chiave moderna consapevole del fatto che avrei trovato in rete uno schema o un codice funzionante, purtroppo nonostante ci siano alcuni siti che pubblichino queste modifiche, ognuno utilizza quello che ha a disposizione, perciò nulla di veramente pronto o funzionale senza perderci del tempo per adattarlo alle mie esigenze...
!!!ATTENZIONE!!!
Prima di costruire un circuito per niente, testare se il proprio telefono funziona anche senza generatore di toni DTMF, il mio inizialmente non andava (solo squillo e niente voce), poi ho scoperto che scollegando il cavo blu e unendolo al bianco internamente al telefono la linea è ottima (vedere schema modifiche più avanti), tutt'ora sono collegato alla presa FSX del router solo con il filtro ADSL e senza nessun circuito elettronico, ovvio che così non abbiamo il supporto delle funzioni speciali contenute nel codice, a Voi dunque l'ardua scelta...
Girando per il WEB, ho poi trovato alcune cose scritte in C per AVR, precisamente c'è un progetto che tutti conoscono con Attiny45 a questo LINK, il codice è scritto bene ed un video mostra il reale funzionamento dell'apparecchio dopo l'aggiunta del semplice circuito, insomma, pensavo che traslandolo lo avrei potuto programmare in un PIC16F628A senza dover acquistare per forza di cose il uP in questione o installare tutta la parte di programmazione oltre a dover reperire o costruire il suo programmatore hardware etc...
Premetto che prima di affrontare questi lavori, faccio sempre una ricerca per vedere se qualcuno lo ha già fatto di suo, ma ancora una volta scopro un tizio che ha iniziato un progetto analogo con il PIC16F628A dotandolo di un display LCD che riconosce i numeri composti e fa un effetto shift per poi piazzarli in sequenza, anche se facendo in questo modo bisogna poi aggiungere un'alimentazione esterna per non caricare la linea cosa che tra l'altro non mi serve, ad ogni modo, sperando che lo abbia portato a termine, provo a connettermi alla sua pagina online che però risulta sempre chiusa per manutenzione, rileggendo i commenti sul sito di boris0 me lo trovo in fondo che chiede come generare i toni e come collegare il circuito al telefono, a quel punto mi sono reso conto che non era in grado di finalizzare il progetto...
Nulla di fatto, in tutto il WEB nessuno ha mai usato un PIC16F628A o similari per fare questo lavoro anche se ci sono state numerose richieste e solleciti vari ai quali gli Autori non hanno mai risposto che poi è come dire giustamente "ad ognuno il suo", altri progetti sono su ghitub per Arduino ma anche in questo frangente sono solo per riconoscere gli impulsi o per formare un numero completo prima di inviarlo in sequenza, no no, eccheccazz. non ci siamo ancora, quindi mi armo di tutto il necessario e comincio a traslare il codice pensando di risolvere in poco tempo, grave errore, qui invece comincia il calvario dopo aver letto quasi per intero il datasheet dell'Attiny45...
In pratica a parte tutti i settaggi che sono abbastanza simili, quel piccoletto contiene moduli e registri per poter fare dei veri Miracoli Elettronici, le sostanziali differenze ve le elencherò in seguito dopo aver raccontato tutta la lunga storia sempre per chi è veramente interessato, quello che ho scoperto mi ha fatto dare ragione ad un mio conoscente che mi diceva sempre che non ci sono paragoni tra AVR e PIC e probabilmente non aveva poi torto...
Ho cominciato con l'eliminare le impostazioni dei suoi registri sostituendole con quelle del PIC16F628A e già a questo punto mi sono ritrovato senza parole: il clock non ha un prescaler 1:4 come nei PIC ma è liberamente impostabile nell'inizializzazione che era settata a 1:1, quindi primo scoglio da superare senza dover utilizzare quarzi da 16MHz per pareggiare i conti, il suo codice utilizza un quarzo 4MHz con moltiplicatore PLL 2:1 programmando il codice come 8MHz, perciò decido di farlo funzionare a 8MHz anche per avere in seguito il PWM a 62500Hz senza perdere risoluzione negli 8bit massimi del medesimo, il codice originale ne usa uno a 15625Hz solo perché al suo interno è presente un vero e proprio generatore di segnali che ne semplifica di molto l'utilizzo, ha anche un comparatore di fase contemporaneamente utilizzabile sullo stesso pin di uscita del PWM che è impostabile anche in modalità invertita, e già, ora come lo traduco nel PIC che non lo ha???
Pensa che ti ripenso, il PIC lo ha, ma non si può impostare insieme al PWM, o uno o l'altro e mai insieme, quindi non serve a molto in questo caso, però mi ricordo di aver creato tanto tempo fa un generatore di onde sinusoidali con questo PIC16F628A, quindi ritrovo il progetto e mi ritorna in mente che anche lui ha una funzione match (corrispondenza) sul periodo che genera un Interrupt e che può servire allo scopo, ottimo, risolta anche questa che era il problema principale per generare i toni corretti...
A questo punto mi sono leggermente impantanato, l'AVR con 4MHz puri genera 4 istruzioni al micro-secondo, io con 8Mhz solamente due, quindi dovevo rivedere tutti i calcoli per far quadrare i conti, infatti senza modifiche i toni erano sballati e con frequenze più gravi del dovuto, la formula presente per la conversione necessaria mi dava valori fuori range, oltretutto per risparmiare memoria sia la sinusoide che le frequenze erano state messe in costanti char, usando un PWM a 62500Hz, avrei dovuto moltiplicarli per 4 per far tornare i conti, ma anche qui non si doveva sforare gli 8bit, pena le frequenze generate erano molto random, questa cosa mi ha "portato via il sonno" per alcuni giorni, alla fine comunque ho avuto ragione io, moltiplico per due le costanti originali, eseguo il calcolo di inserimento nella sinusoide delle due frequenze e poi invio il risultato al registro CCPR1L moltiplicandolo ancora per due, ovvio che per fare questo viene utilizzato lo shift a sinistra dei bit (byte << 1) e non il segno di moltiplicazione, facendo poi (int >> 2) & 0xFF si impone inesorabilmente a 8bit il PWM, Eureka, funziona!!!
Confrontando le due forme d'onda dei due progetti, la mia è una sinusoide centrata nell'intervallo dei 5V con l'aggiunta di un offset software ed ha un suono molto dolce, l'altra invece è tagliata e più simile ad un'onda triangolare che parte dal basso anche se viene regolarmente riconosciuta, con piccole modifiche nel codice si possono variare i timbri delle frequenze, qui va un po' a gusto personale...
In seguito ho rimosso l'offset perché alcuni segnali acustici contenuti nel programma erano fortemente attenuati e la cosa non mi piaceva tanto, ad ogni modo sono riuscito a generarli senza far cadere la linea come invece accade nel progetto originale, risultano solo leggermente lontani rispetto ai toni ma sono comunque ben comprensibili...
Mi sono scordato della prima fase che poi è quella più importante, il riconoscimento degli impulsi del disco combinatore, anche questa non veniva mai riconosciuta pur interrogando le porte da Interrupt, qui scopro davvero l'acqua calda: l'AVR ha un registro a parte che mantiene lo stato degli ingressi ed è subito disponibile se richiamato con una funzione abbastanza complessa inclusa nella sua libreria, mentre il PIC16F628A ha un piccolo difetto se così si può dire, se tenti di leggere o scrivere una porta impostata come ingresso che genera un Interrupt, i flag relativi vengono automaticamente resettati, questo accade per la presenza di registri condivisi che devono essere liberati per eseguire ulteriori operazioni, anche provando a salvare lo stato dell'intera porta, non si ha mai un quadro corretto della situazione, manca sempre uno dei due flag necessari al riconoscimento...
Questa è la MACRO bit_is_set originale per leggere lo stato dei pin in ingresso che con i PIC non sortisce alcunché:
Lo so cosa state pensando, perché non hai fatto il polling delle porte come fanno tutti e che è più semplice???
No, quelle cose sono per i programmatori in erba, se si vuole creare un codice robusto bisogna tentare di risolvere questi problemi in maniera più consona, il fatto che nessuno dei tentativi di salvare lo stato attuale riusciva a preservare i valori, poi ad un certo punto mi si è accesa la lampadina: ho quasi tutta la PORTA libera, perché non usarla come memoria dello stato degli ingressi creando uno PSEUDO-REGISTRO di 2 bit a specchio???
Appena fatta questa modifica, tutti gli impulsi sono stati riconosciuti al volo senza esitazione pur riducendo l'intervallo di composizione numero valido alla metà, però credetemi che è stata l'ultima spiaggia prima di gettare la spugna, ma i problemi non sono ancora terminati qui, TO BE CONTINUED...
Nel codice originale non si usano dei delay per non bloccare il micro, l'unico è di 100us per consentire al loop principale di captare lo stato degli ingressi, per il resto c'è una routine che mette il uP in modalità IDLE che è una variante dello sleep mode, la differenza sta nel fatto che il processore va in modalità basso consumo in contemporanea parte un TIMER che lo risveglia ogni 15ms, questa finezza è stata aggiunta sempre per non caricare la linea, però il PIC non ha questa modalità, quindi adesso come fare???
Se lo metto in sleep poi si resetta e perdo la memorizzazione dei numeri precedenti, ora cosa mi invento per creare una cosa simile???
Mmmmmmm, qui il cervello ha cominciato a rimuginare facendo un ripasso di tutte le possibili funzionalità che spesso non si usano quasi mai, IDEONA, provo col WDT (Watch Dog Timer), il come è ancora tutto da vedere ma non ho altro oltre al TIMER1 che funziona anche in sleep e può generare l'Interrupt di risveglio, il TMR0 non è in grado di farlo, anche se a noi serve un TIMER da 8bit e non da 16bit, quindi lo trasformo utilizzando solo la parte alta (HIGH BYTE)...
La cosa interessante del WDT, e che se usato in contemporanea allo sleep, il PIC non si resetta ma riprende dall'istruzione successiva alla sua pulizia del flag (CLRW WDT), ogni 18ms se non viene eseguita il WDT resetta automaticamente il micro e noi non vogliamo che accada, ci serve solo un misuratore esatto del trascorrere del tempo per generare il delay senza tenere impegnato totalmente il processore, leggendo il codice tutto diverrà più chiaro, anche questa modifica ha richiesto varie sedute di esperimenti incrociati...
Ad ogni modo, alla fine della composizione il uP va in vera modalità sleep consumando qualche uA appena, in stato di funzionamento si raggiunge a malapena il mA, quindi tutto secondo le norme richieste dalle compagnie telefoniche per non incorrere in problemi legali...
Beh, non è stata una passeggiata fare questa traduzione, le peculiari differenze dei due chip hanno creato non pochi problemi per adattare il codice, ho dovuto dare sfoggio di tutte le risorse mentali per poter giungere ad un risultato soddisfacente, ma i problemi non sono ancora finiti...
Lo schema originariamente usato è minimalista, l'uscita PWM confluisce in un filtro passa-basso RC che pilota la base di un transistor NPN che ha una resistenza da 330\(\Omega\)sull'emettiore per simulare l'impedenza telefonica che generalmente è di 300\(\Omega\), il uP è alimentato attraverso una resistenza da 2k, uno zener da 5.1V e due condensatori, uno ceramico per i disturbi ed uno elettrolitico per stabilizzare la tensione proveniente dalla linea telefonica, purtroppo ho letto le recensioni di chi lo ha realizzato e non sempre sono state positive, i problemi riscontrati sono principalmente alcuni che non lo rendono un dispositivo universale, ad ogni tipo di apparecchio o linea bisogna comunque intervenire sul circuito:
1) La resistenza da 2k a volte è troppo alta e non permette l'avvio del uP
2) Lo zener che non dovrebbe quasi intervenire carica la linea
3) La ricezione vocale è piuttosto deteriorata
4) Il transistor riportato non va bene per tutti i telefoni
5) Con certi dischi datati gli impulsi non corrispondono, presenza di rimbalzi o velocità del combinatore elevata
Il progetto originale come si legge nell'articolo, è collegato ad un adattatore Elettronico (ATA), quindi le tensioni che arrivano al circuito sono al massimo di 48V in bussata, che scendono a 5V con linea occupata e 0V a riposo, quelli che lo hanno testato direttamente sulle linee, si sono spesso lamentati nel riscontrare parecchi disturbi, eppure il tizio lo ha specificato bene nell'articolo, comunque ci sono alcuni stratagemmi per poterlo rendere un dispositivo adatto a tutte le situazioni con piccole migliorie...
Un Collega del quale non posso per ora fare il nome (privacy), ha realizzato un circuito simile custom per se stesso, a parte il software che può essere scritto in vari modi, è riuscito ad ottimizzare tutta la parte relativa la caricamento della linea, l'uso di un trasformatorino audio 1:1 da 600/600\(\Omega\) per linea telefonica risolve egregiamente il problema della qualità vocale in ricezione (DATASHEET), un ulteriore interruttore elettronico taglia fuori il uP quando non serve e gli impulsi sono riconosciuti non direttamente dal disco combinatore, ma dalla linea stessa che chiude e apre tot volte in base al numero composto, questo fa si che non dovete neppure smontare il telefono, il circuito si istalla direttamente sulla presa volendo, se avrò il consenso lo pubblicherò direttamente qui o lo farà direttamente lui in persona...
Bene, come di consueto prima di programmare un PIC, passo dalla fase di test con il simulatore per vedere se tutto funziona, però come simulare un combinatore a disco telefonico non presente nelle librerie???
Altra idea, due switch digitali pilotati da uno SCRIPT studiato apposta per l'occasione, si inserisce il numero di telefono nella stringa e in uscita si odono i toni DTMF corrispondenti, ecco il codice in EasyHDL che è una variante del BASIC:
DIAL/MUTE (NA)
PULSE (NC)
In pratica DIAL parte un secondo prima simulando l'alzata della cornetta poi in sequenza gli impulsi PULSE, il DIAL è alto e diventa basso solo mentre vengono generati gli impulsi...
Per simulare la chiamata rapida bisogna salvare il numero nella EEPROM all'indirizzo 0x00, poi si aggiungono questi due SCRIPT ai generatori, ricordatevi di estendere il tempo se usate l'analisi audio grafica:
DIAL (NA)
PULSE (NC)
Qui il risultato della simulazione:
Nello schema non ci sono condensatori anti-rimbalzo, mentre nella realtà è sempre meglio aggiungerli, il valore non è critico è può variare da 10nF a 100nF a seconda dello stato dei contatti e della velocità di rotazione, nelle numerose varianti proposte di questo codice, un po' tutti hanno dovuto escogitare stratagemmi atti a prevenire strani comportamenti durante la composizione, Io per esempio ho dovuto ridurre di metà il valore di alcuni ritardi software, con quelli originali a volte il numero non veniva riconosciuto e ne veniva composto un altro adiacente, perciò preparatevi a dover intervenire per adattarlo alle vostre esigenze personali...
Un ulteriore intoppo è la presenza della memorizzazione di sette numeri di chiamata rapida, questa sezione è definita come Funzioni Speciali nel codice, tutti dati sono memorizzati nella EEPROM del uP e possono essere richiamati tenendo per 2 secondi il numero scelto con il selettore senza rilasciarlo, in AVR queste funzioni sono già pronte in libreria, con mikroC invece c'è solo la lettura e la scrittura di un byte alla volta, qui serviva una routine per leggere e scrivere un array bidimensionale da 126 char in blocco e controllando che non venga scritto un numero uguale già in memoria passandolo come puntatore, anche questo ha richiesto del tempo per essere aggiunta, ridotta e ottimizzata nel sorgente...
Il codice riconosce oltre ai numeri da 0 a 9 e *# (no ABCD per telefoni non prettamente Italiani), la stringa completa quindi è: "1234567890*#", avendo utilizzato tutte le combinazioni possibili sul disco non si poteva generare facilmente anche le 4 lettere senza incasinare il codice che già di suo non è proprio semplice nonostante lo sembri a prima vista...
Per concludere in bellezza e visto che mancava nel codice originale (anche per l'abbondanza di pin liberi), ho aggiunto due JUMPER che opportunamente configurati possono interfacciare il circuito a quasi tutti i telefoni a disco esistenti, per i pochi modelli rimanenti di fattura moderna, bisogna per forza mettere mano al codice e lascio a qualcuno di disponibile il compito, lo scopo iniziale del progetto era quello di dar vita ai vecchi telefoni non più utilizzati, quindi quest'ultimo argomento esula da tutto...
4 TIPI DI TELEFONI A DISCO ESISTENTI E DI USO COMUNE:
A) Standard - 0987654321
B) Svedese - 9876543210
C) Zelandese - 0123456789
D) Antico - 1234567890
Differenze sostanziali:
Fortunatamente in quegli anni i telefoni contenevano al loro interno lo schema dei collegamenti con alcuni suggerimenti in caso di modifiche, io lo conservo ancora come una reliquia e l'ho scannerizzato per Voi, eccolo, a parte qualche solco segnato dal tempo è ancora perfettamente leggibile:
SCHEMA TELEFONO S62:
SCHEMA DEL CIRCUITO:
SCHEMA DI COLLEGAMENTO DEL CIRCUITO AL TELEFONO (diciture in rosso):
ISTRUZIONI SMONTAGGIO/MONTAGGIO:
1) Capovolgere il telefono e svitare le due viti poste lateralmente per estrarre il contenitore
2) Svitare le quattro viti dei cavi di collegamento del DISCO COMBINATORE numerate da 1 a 4
3) Unire il cavetto rosso con il blu e collegarli a massa
4) Collegare il cavetto marrone al pin RB4 ed il cavetto bianco al pin RB5 del PIC16F628A
5) Collegare il circuito nei punti 3 e 4 del telefono dove il 3 è il "positivo" per l'alimentazione
6) Collegare il telefono alla linea per testare l'effettivo funzionamento
Nello schema si vedono due simboli dei contatti NA ed NO (cid e cld), quelli sono propri del Disco Combinatore chiamato a volte anche DC, in questo schema non devono trarre in inganno visto che sono stati letteralmente tolti e quindi non devono essere calcolati nell'analisi circuitale...
NOTA. Io nella realtà ho usato un transistor MPSA45A con una Vce da 350V, il 2N3904 arriva solo a 60V ed è leggermente tirato per poter essere montato su tutti i telefoni, quindi tenete conto di metterne uno consono al vostro impianto misurando le variazioni di tensione ai capi del medesimo...
A seguire una schermata fotografica degli esperimenti:
Questi sono i codici sorgenti del progetto rivisitato per PIC16F628A e tradotto in Italiano:
file RotaryPulseToTone.c
file RotaryPulseToTone.h
IMPOSTAZIONI DI COMPILAZIONE:
LIBRERIE:
L'unica libreria utilizzata è quella per leggere e scrivere nella EEPROM, quindi deselezionate tutte le altre e spuntate solo quella...
NON CERCATE DI UTILIZZARE L'OSCILLATORE INTERNO PER RISPARMIARE SUI COMPONENTI, QUELLI CHE LO HANNO FATTO SI SONO PENTITI RISCONTRANTO IRREGOLARITA' SIA NEL RICONOSCIMENTO DEGLI IMPULSI CHE NELLA GENERAZIONE DEI TONI, LO SCHEMA DEVE ESSERE RISPETTATO COSI' COM'E', IL QUARZO DA 8MHZ (HS) E' D'OBBLIGO...
COMPORRE I CARATTERI SPECIALI:
Per comporre l'asterisco (*) ed il cancelletto (#), bisogna selezionare i numeri 1 e 2 ruotarli e tenerli premuti fino a che si ode un suono bitonale acuto, rilasciandoli verrà composto il carattere speciale con la giusta tonalità...
COMPOSIZIONE RAPIDA:
Per comporre un numero in memoria come selezione rapida, scegliere un numero da 3 a 9 ruotare e tenere fermo per 2s fino a che si ode un suono bitonale acuto, a questo punto rilasciare il disco, se la cella memoria è piena verrà composto il numero selezionato, altrimenti non si udirà nulla...
MEMORIZZAZIONE NUMERO:
Per memorizzare un numero nella EEPROM, selezionare lo ZERO (0) e ruotarlo tenendolo fermo fino a che non si ode un suono bitonale acuto, a questo punto rilasciandolo si udirà una specie di musichetta che significa che siamo entrati in modalità di programmazione, ora scegliere una cella di memoria da 3 a 9 ruotare e rilasciare si udirà un breve segnale che indica che possiamo comporre il numero, una volta fatto selezioniamo di nuovo lo ZERO (0) ruotiamo e teniamolo premuto fino al segnale acustico per poi rilasciarlo, un altro motivetto confermerà la memorizzazione del numero...
Nota: durante la composizione del numero non si udiranno i toni DTMF per non far partire la telefonata, un semplice BEEP monotonale scandisce questa fase senza interferire con la linea telefonica...
CANCELLAZIONE DI UN MUMERO IN MEMORIA:
Per cancellare un numero in memoria basta seguire la fase di memorizzazione senza comporre nessun numero, confermando con lo ZERO (0) la memoria verrà sovrascritta con un valore di -1 (0xFF)...
SEGNALAZIONE ERRORI:
Se durante l'utilizzo si ode un suono lungo, vuol dire che c'è stato un errore o qualcosa è andato storto, per azzerarlo basta riagganciare per qualche secondo in modo da resettare il uP...
Data la presenza di 5 pin ancora liberi (no RA0, RA1 e RB<6:7>), si potrebbe alimentarlo esternamente per aggiungere dei LEDs di segnalazione creando così una sorta di avvisatore ottico dei vari stati, a me ne è servito solo uno per scandire il riconoscimento dei numeri composti, per il resto lascio sempre a Voi il compito di personalizzare il codice con nuovi ed utili gadget...
P.S. Eventuali suggerimenti o idee per migliorare ulteriormente il programma saranno sempre ben accette, astenersi per cortesia dal criticare cose che non si comprendono a fondo o solo per il gusto di parlare del benamato nulla, il mettere a punto il tutto ha richiesto parecchio impegno e lavoro per non parlare del molto tempo speso per ottimizzare e testare tutte le parti del circuito , se proprio non vi gusta in rete lo vendono ad una cinquantina di €uro, al limite attendo con ansia la vostra preziosa versione...
GioRock - Mar 2018
Tempo fa ho scoperto che in un cassetto degli oggetti ormai catalogati come obsoleti, c'era ancora un bel telefono della SIP dei primi anni '80 il famigerato "bigrigio", per intenderci è il modello AUSO S62, così ho deciso di convertirlo rivisitandolo in chiave moderna consapevole del fatto che avrei trovato in rete uno schema o un codice funzionante, purtroppo nonostante ci siano alcuni siti che pubblichino queste modifiche, ognuno utilizza quello che ha a disposizione, perciò nulla di veramente pronto o funzionale senza perderci del tempo per adattarlo alle mie esigenze...
!!!ATTENZIONE!!!
Prima di costruire un circuito per niente, testare se il proprio telefono funziona anche senza generatore di toni DTMF, il mio inizialmente non andava (solo squillo e niente voce), poi ho scoperto che scollegando il cavo blu e unendolo al bianco internamente al telefono la linea è ottima (vedere schema modifiche più avanti), tutt'ora sono collegato alla presa FSX del router solo con il filtro ADSL e senza nessun circuito elettronico, ovvio che così non abbiamo il supporto delle funzioni speciali contenute nel codice, a Voi dunque l'ardua scelta...
Girando per il WEB, ho poi trovato alcune cose scritte in C per AVR, precisamente c'è un progetto che tutti conoscono con Attiny45 a questo LINK, il codice è scritto bene ed un video mostra il reale funzionamento dell'apparecchio dopo l'aggiunta del semplice circuito, insomma, pensavo che traslandolo lo avrei potuto programmare in un PIC16F628A senza dover acquistare per forza di cose il uP in questione o installare tutta la parte di programmazione oltre a dover reperire o costruire il suo programmatore hardware etc...
Premetto che prima di affrontare questi lavori, faccio sempre una ricerca per vedere se qualcuno lo ha già fatto di suo, ma ancora una volta scopro un tizio che ha iniziato un progetto analogo con il PIC16F628A dotandolo di un display LCD che riconosce i numeri composti e fa un effetto shift per poi piazzarli in sequenza, anche se facendo in questo modo bisogna poi aggiungere un'alimentazione esterna per non caricare la linea cosa che tra l'altro non mi serve, ad ogni modo, sperando che lo abbia portato a termine, provo a connettermi alla sua pagina online che però risulta sempre chiusa per manutenzione, rileggendo i commenti sul sito di boris0 me lo trovo in fondo che chiede come generare i toni e come collegare il circuito al telefono, a quel punto mi sono reso conto che non era in grado di finalizzare il progetto...
Nulla di fatto, in tutto il WEB nessuno ha mai usato un PIC16F628A o similari per fare questo lavoro anche se ci sono state numerose richieste e solleciti vari ai quali gli Autori non hanno mai risposto che poi è come dire giustamente "ad ognuno il suo", altri progetti sono su ghitub per Arduino ma anche in questo frangente sono solo per riconoscere gli impulsi o per formare un numero completo prima di inviarlo in sequenza, no no, eccheccazz. non ci siamo ancora, quindi mi armo di tutto il necessario e comincio a traslare il codice pensando di risolvere in poco tempo, grave errore, qui invece comincia il calvario dopo aver letto quasi per intero il datasheet dell'Attiny45...
In pratica a parte tutti i settaggi che sono abbastanza simili, quel piccoletto contiene moduli e registri per poter fare dei veri Miracoli Elettronici, le sostanziali differenze ve le elencherò in seguito dopo aver raccontato tutta la lunga storia sempre per chi è veramente interessato, quello che ho scoperto mi ha fatto dare ragione ad un mio conoscente che mi diceva sempre che non ci sono paragoni tra AVR e PIC e probabilmente non aveva poi torto...
Ho cominciato con l'eliminare le impostazioni dei suoi registri sostituendole con quelle del PIC16F628A e già a questo punto mi sono ritrovato senza parole: il clock non ha un prescaler 1:4 come nei PIC ma è liberamente impostabile nell'inizializzazione che era settata a 1:1, quindi primo scoglio da superare senza dover utilizzare quarzi da 16MHz per pareggiare i conti, il suo codice utilizza un quarzo 4MHz con moltiplicatore PLL 2:1 programmando il codice come 8MHz, perciò decido di farlo funzionare a 8MHz anche per avere in seguito il PWM a 62500Hz senza perdere risoluzione negli 8bit massimi del medesimo, il codice originale ne usa uno a 15625Hz solo perché al suo interno è presente un vero e proprio generatore di segnali che ne semplifica di molto l'utilizzo, ha anche un comparatore di fase contemporaneamente utilizzabile sullo stesso pin di uscita del PWM che è impostabile anche in modalità invertita, e già, ora come lo traduco nel PIC che non lo ha???
Pensa che ti ripenso, il PIC lo ha, ma non si può impostare insieme al PWM, o uno o l'altro e mai insieme, quindi non serve a molto in questo caso, però mi ricordo di aver creato tanto tempo fa un generatore di onde sinusoidali con questo PIC16F628A, quindi ritrovo il progetto e mi ritorna in mente che anche lui ha una funzione match (corrispondenza) sul periodo che genera un Interrupt e che può servire allo scopo, ottimo, risolta anche questa che era il problema principale per generare i toni corretti...
A questo punto mi sono leggermente impantanato, l'AVR con 4MHz puri genera 4 istruzioni al micro-secondo, io con 8Mhz solamente due, quindi dovevo rivedere tutti i calcoli per far quadrare i conti, infatti senza modifiche i toni erano sballati e con frequenze più gravi del dovuto, la formula presente per la conversione necessaria mi dava valori fuori range, oltretutto per risparmiare memoria sia la sinusoide che le frequenze erano state messe in costanti char, usando un PWM a 62500Hz, avrei dovuto moltiplicarli per 4 per far tornare i conti, ma anche qui non si doveva sforare gli 8bit, pena le frequenze generate erano molto random, questa cosa mi ha "portato via il sonno" per alcuni giorni, alla fine comunque ho avuto ragione io, moltiplico per due le costanti originali, eseguo il calcolo di inserimento nella sinusoide delle due frequenze e poi invio il risultato al registro CCPR1L moltiplicandolo ancora per due, ovvio che per fare questo viene utilizzato lo shift a sinistra dei bit (byte << 1) e non il segno di moltiplicazione, facendo poi (int >> 2) & 0xFF si impone inesorabilmente a 8bit il PWM, Eureka, funziona!!!
Confrontando le due forme d'onda dei due progetti, la mia è una sinusoide centrata nell'intervallo dei 5V con l'aggiunta di un offset software ed ha un suono molto dolce, l'altra invece è tagliata e più simile ad un'onda triangolare che parte dal basso anche se viene regolarmente riconosciuta, con piccole modifiche nel codice si possono variare i timbri delle frequenze, qui va un po' a gusto personale...
In seguito ho rimosso l'offset perché alcuni segnali acustici contenuti nel programma erano fortemente attenuati e la cosa non mi piaceva tanto, ad ogni modo sono riuscito a generarli senza far cadere la linea come invece accade nel progetto originale, risultano solo leggermente lontani rispetto ai toni ma sono comunque ben comprensibili...
Mi sono scordato della prima fase che poi è quella più importante, il riconoscimento degli impulsi del disco combinatore, anche questa non veniva mai riconosciuta pur interrogando le porte da Interrupt, qui scopro davvero l'acqua calda: l'AVR ha un registro a parte che mantiene lo stato degli ingressi ed è subito disponibile se richiamato con una funzione abbastanza complessa inclusa nella sua libreria, mentre il PIC16F628A ha un piccolo difetto se così si può dire, se tenti di leggere o scrivere una porta impostata come ingresso che genera un Interrupt, i flag relativi vengono automaticamente resettati, questo accade per la presenza di registri condivisi che devono essere liberati per eseguire ulteriori operazioni, anche provando a salvare lo stato dell'intera porta, non si ha mai un quadro corretto della situazione, manca sempre uno dei due flag necessari al riconoscimento...
Questa è la MACRO bit_is_set originale per leggere lo stato dei pin in ingresso che con i PIC non sortisce alcunché:
Codice: Seleziona tutto
#define _BV(bit) (1<<(bit))
#define _SFR_MEM_ADDR(sfr) ((unsigned int) &(sfr))
#define _SFR_ADDR(sfr) _SFR_MEM_ADDR(sfr)
#define _MMIO_BYTE(mem_addr) (*(volatile unsigned char *)(mem_addr))
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
#define bit_is_set (sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
Lo so cosa state pensando, perché non hai fatto il polling delle porte come fanno tutti e che è più semplice???
No, quelle cose sono per i programmatori in erba, se si vuole creare un codice robusto bisogna tentare di risolvere questi problemi in maniera più consona, il fatto che nessuno dei tentativi di salvare lo stato attuale riusciva a preservare i valori, poi ad un certo punto mi si è accesa la lampadina: ho quasi tutta la PORTA libera, perché non usarla come memoria dello stato degli ingressi creando uno PSEUDO-REGISTRO di 2 bit a specchio???
Appena fatta questa modifica, tutti gli impulsi sono stati riconosciuti al volo senza esitazione pur riducendo l'intervallo di composizione numero valido alla metà, però credetemi che è stata l'ultima spiaggia prima di gettare la spugna, ma i problemi non sono ancora terminati qui, TO BE CONTINUED...
Nel codice originale non si usano dei delay per non bloccare il micro, l'unico è di 100us per consentire al loop principale di captare lo stato degli ingressi, per il resto c'è una routine che mette il uP in modalità IDLE che è una variante dello sleep mode, la differenza sta nel fatto che il processore va in modalità basso consumo in contemporanea parte un TIMER che lo risveglia ogni 15ms, questa finezza è stata aggiunta sempre per non caricare la linea, però il PIC non ha questa modalità, quindi adesso come fare???
Se lo metto in sleep poi si resetta e perdo la memorizzazione dei numeri precedenti, ora cosa mi invento per creare una cosa simile???
Mmmmmmm, qui il cervello ha cominciato a rimuginare facendo un ripasso di tutte le possibili funzionalità che spesso non si usano quasi mai, IDEONA, provo col WDT (Watch Dog Timer), il come è ancora tutto da vedere ma non ho altro oltre al TIMER1 che funziona anche in sleep e può generare l'Interrupt di risveglio, il TMR0 non è in grado di farlo, anche se a noi serve un TIMER da 8bit e non da 16bit, quindi lo trasformo utilizzando solo la parte alta (HIGH BYTE)...
La cosa interessante del WDT, e che se usato in contemporanea allo sleep, il PIC non si resetta ma riprende dall'istruzione successiva alla sua pulizia del flag (CLRW WDT), ogni 18ms se non viene eseguita il WDT resetta automaticamente il micro e noi non vogliamo che accada, ci serve solo un misuratore esatto del trascorrere del tempo per generare il delay senza tenere impegnato totalmente il processore, leggendo il codice tutto diverrà più chiaro, anche questa modifica ha richiesto varie sedute di esperimenti incrociati...
Ad ogni modo, alla fine della composizione il uP va in vera modalità sleep consumando qualche uA appena, in stato di funzionamento si raggiunge a malapena il mA, quindi tutto secondo le norme richieste dalle compagnie telefoniche per non incorrere in problemi legali...
Beh, non è stata una passeggiata fare questa traduzione, le peculiari differenze dei due chip hanno creato non pochi problemi per adattare il codice, ho dovuto dare sfoggio di tutte le risorse mentali per poter giungere ad un risultato soddisfacente, ma i problemi non sono ancora finiti...
Lo schema originariamente usato è minimalista, l'uscita PWM confluisce in un filtro passa-basso RC che pilota la base di un transistor NPN che ha una resistenza da 330\(\Omega\)sull'emettiore per simulare l'impedenza telefonica che generalmente è di 300\(\Omega\), il uP è alimentato attraverso una resistenza da 2k, uno zener da 5.1V e due condensatori, uno ceramico per i disturbi ed uno elettrolitico per stabilizzare la tensione proveniente dalla linea telefonica, purtroppo ho letto le recensioni di chi lo ha realizzato e non sempre sono state positive, i problemi riscontrati sono principalmente alcuni che non lo rendono un dispositivo universale, ad ogni tipo di apparecchio o linea bisogna comunque intervenire sul circuito:
1) La resistenza da 2k a volte è troppo alta e non permette l'avvio del uP
2) Lo zener che non dovrebbe quasi intervenire carica la linea
3) La ricezione vocale è piuttosto deteriorata
4) Il transistor riportato non va bene per tutti i telefoni
5) Con certi dischi datati gli impulsi non corrispondono, presenza di rimbalzi o velocità del combinatore elevata
Il progetto originale come si legge nell'articolo, è collegato ad un adattatore Elettronico (ATA), quindi le tensioni che arrivano al circuito sono al massimo di 48V in bussata, che scendono a 5V con linea occupata e 0V a riposo, quelli che lo hanno testato direttamente sulle linee, si sono spesso lamentati nel riscontrare parecchi disturbi, eppure il tizio lo ha specificato bene nell'articolo, comunque ci sono alcuni stratagemmi per poterlo rendere un dispositivo adatto a tutte le situazioni con piccole migliorie...
Un Collega del quale non posso per ora fare il nome (privacy), ha realizzato un circuito simile custom per se stesso, a parte il software che può essere scritto in vari modi, è riuscito ad ottimizzare tutta la parte relativa la caricamento della linea, l'uso di un trasformatorino audio 1:1 da 600/600\(\Omega\) per linea telefonica risolve egregiamente il problema della qualità vocale in ricezione (DATASHEET), un ulteriore interruttore elettronico taglia fuori il uP quando non serve e gli impulsi sono riconosciuti non direttamente dal disco combinatore, ma dalla linea stessa che chiude e apre tot volte in base al numero composto, questo fa si che non dovete neppure smontare il telefono, il circuito si istalla direttamente sulla presa volendo, se avrò il consenso lo pubblicherò direttamente qui o lo farà direttamente lui in persona...
Bene, come di consueto prima di programmare un PIC, passo dalla fase di test con il simulatore per vedere se tutto funziona, però come simulare un combinatore a disco telefonico non presente nelle librerie???
Altra idea, due switch digitali pilotati da uno SCRIPT studiato apposta per l'occasione, si inserisce il numero di telefono nella stringa e in uscita si odono i toni DTMF corrispondenti, ecco il codice in EasyHDL che è una variante del BASIC:
DIAL/MUTE (NA)
Codice: Seleziona tutto
// STRINGA NUMERO TELEFONICO
STRING sTN = "1234567890"
// FREQUENZA IMPUSLI 10Hz
FLOAT BITTIME = 100m
// Dichiarazione variabili
INT i, k, j
STRING s = "LLLLLLLLLL"
// Conversione da Numero a Stringa
FOR i = 1 TO LEN(sTN)
s = s + "LL"
j = ASC(SUBSTR(sTN, i)) - 48
IF j = 0 THEN j = 10
FOR k = 1 TO j
s = s + "HH"
NEXT k
s = s + "LL"
NEXT i
// Condizione Iniziale
OUT = 0
SLEEP FOR 1000m
// USCITA VARIBILE
FOR i = 1 TO LEN(s)
IF SUBSTR(s, i) = "L" THEN
OUT = 0
ELSE
OUT = 1
ENDIF
SLEEP FOR BITTIME
NEXT i
PULSE (NC)
Codice: Seleziona tutto
// STRINGA NUMERO TELEFONICO
STRING sTN = "1234567890"
// FREQUENZA IMPUSLI 10Hz
FLOAT BITTIME = 100m
// Dichiarazione variabili
INT i, k, j
STRING s
// Conversione da Numero a Stringa
FOR i = 1 TO LEN(sTN)
s = s + "HH"
j = ASC(SUBSTR(sTN, i)) - 48
IF j = 0 THEN j = 10
FOR k = 1 TO j
s = s + "HL"
NEXT k
s = s + "HH"
NEXT i
// Condizione Iniziale
OUT = 1
SLEEP FOR 2000m
// USCITA VARIBILE
FOR i = 1 TO LEN(s)
IF SUBSTR(s, i) = "L" THEN
OUT = 0
ELSE
OUT = 1
ENDIF
SLEEP FOR BITTIME
NEXT i
In pratica DIAL parte un secondo prima simulando l'alzata della cornetta poi in sequenza gli impulsi PULSE, il DIAL è alto e diventa basso solo mentre vengono generati gli impulsi...
Per simulare la chiamata rapida bisogna salvare il numero nella EEPROM all'indirizzo 0x00, poi si aggiungono questi due SCRIPT ai generatori, ricordatevi di estendere il tempo se usate l'analisi audio grafica:
DIAL (NA)
Codice: Seleziona tutto
// Define data to be output
STRING s = "LLLLLLLLLLLLHHHHHHHHHHHHHHHHHHHHLLLLLLLLLLLLLLLLLLLLLLLLLLLLHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHLLLLLLLLLLLLLLLLLLLLLLLLHHHHHHLL"
FLOAT BITTIME=100m
// Declare working variables
INT i
// Top level
OUT = 0
SLEEP FOR 1000m
FOR i = 1 TO LEN(s)
IF SUBSTR(s, i) = "L" THEN
OUT = 0
ELSE
OUT = 1
ENDIF
SLEEP FOR BITTIME
NEXT i
PULSE (NC)
Codice: Seleziona tutto
// Define data to be output
STRING s = "HHHLHLHLHLHLHLHLHLHLHLHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHLHLHLHH"
FLOAT BITTIME=100m
// Declare working variables
INT i
// Top level
OUT = 1
SLEEP FOR 2000m
FOR i = 1 TO LEN(s)
IF SUBSTR(s, i) = "L" THEN
OUT = 0
ELSE
OUT = 1
ENDIF
SLEEP FOR BITTIME
NEXT i
Qui il risultato della simulazione:
Nello schema non ci sono condensatori anti-rimbalzo, mentre nella realtà è sempre meglio aggiungerli, il valore non è critico è può variare da 10nF a 100nF a seconda dello stato dei contatti e della velocità di rotazione, nelle numerose varianti proposte di questo codice, un po' tutti hanno dovuto escogitare stratagemmi atti a prevenire strani comportamenti durante la composizione, Io per esempio ho dovuto ridurre di metà il valore di alcuni ritardi software, con quelli originali a volte il numero non veniva riconosciuto e ne veniva composto un altro adiacente, perciò preparatevi a dover intervenire per adattarlo alle vostre esigenze personali...
Un ulteriore intoppo è la presenza della memorizzazione di sette numeri di chiamata rapida, questa sezione è definita come Funzioni Speciali nel codice, tutti dati sono memorizzati nella EEPROM del uP e possono essere richiamati tenendo per 2 secondi il numero scelto con il selettore senza rilasciarlo, in AVR queste funzioni sono già pronte in libreria, con mikroC invece c'è solo la lettura e la scrittura di un byte alla volta, qui serviva una routine per leggere e scrivere un array bidimensionale da 126 char in blocco e controllando che non venga scritto un numero uguale già in memoria passandolo come puntatore, anche questo ha richiesto del tempo per essere aggiunta, ridotta e ottimizzata nel sorgente...
Il codice riconosce oltre ai numeri da 0 a 9 e *# (no ABCD per telefoni non prettamente Italiani), la stringa completa quindi è: "1234567890*#", avendo utilizzato tutte le combinazioni possibili sul disco non si poteva generare facilmente anche le 4 lettere senza incasinare il codice che già di suo non è proprio semplice nonostante lo sembri a prima vista...
Per concludere in bellezza e visto che mancava nel codice originale (anche per l'abbondanza di pin liberi), ho aggiunto due JUMPER che opportunamente configurati possono interfacciare il circuito a quasi tutti i telefoni a disco esistenti, per i pochi modelli rimanenti di fattura moderna, bisogna per forza mettere mano al codice e lascio a qualcuno di disponibile il compito, lo scopo iniziale del progetto era quello di dar vita ai vecchi telefoni non più utilizzati, quindi quest'ultimo argomento esula da tutto...
4 TIPI DI TELEFONI A DISCO ESISTENTI E DI USO COMUNE:
A) Standard - 0987654321
B) Svedese - 9876543210
C) Zelandese - 0123456789
D) Antico - 1234567890
Differenze sostanziali:
Fortunatamente in quegli anni i telefoni contenevano al loro interno lo schema dei collegamenti con alcuni suggerimenti in caso di modifiche, io lo conservo ancora come una reliquia e l'ho scannerizzato per Voi, eccolo, a parte qualche solco segnato dal tempo è ancora perfettamente leggibile:
SCHEMA TELEFONO S62:
SCHEMA DEL CIRCUITO:
SCHEMA DI COLLEGAMENTO DEL CIRCUITO AL TELEFONO (diciture in rosso):
ISTRUZIONI SMONTAGGIO/MONTAGGIO:
1) Capovolgere il telefono e svitare le due viti poste lateralmente per estrarre il contenitore
2) Svitare le quattro viti dei cavi di collegamento del DISCO COMBINATORE numerate da 1 a 4
3) Unire il cavetto rosso con il blu e collegarli a massa
4) Collegare il cavetto marrone al pin RB4 ed il cavetto bianco al pin RB5 del PIC16F628A
5) Collegare il circuito nei punti 3 e 4 del telefono dove il 3 è il "positivo" per l'alimentazione
6) Collegare il telefono alla linea per testare l'effettivo funzionamento
Nello schema si vedono due simboli dei contatti NA ed NO (cid e cld), quelli sono propri del Disco Combinatore chiamato a volte anche DC, in questo schema non devono trarre in inganno visto che sono stati letteralmente tolti e quindi non devono essere calcolati nell'analisi circuitale...
NOTA. Io nella realtà ho usato un transistor MPSA45A con una Vce da 350V, il 2N3904 arriva solo a 60V ed è leggermente tirato per poter essere montato su tutti i telefoni, quindi tenete conto di metterne uno consono al vostro impianto misurando le variazioni di tensione ai capi del medesimo...
A seguire una schermata fotografica degli esperimenti:
Questi sono i codici sorgenti del progetto rivisitato per PIC16F628A e tradotto in Italiano:
file RotaryPulseToTone.c
Codice: Seleziona tutto
//*****************************************************************************
// Title : Pulse to tone (DTMF) converter
// Author : Boris Cherkasskiy
// Created : 2011-10-24
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// DTMF generator logic is loosely based on the AVR314 app note from Atmel
//
//*****************************************************************************
//*****************************************************************************
// PIC16F628A VERSION TRANSLATED BY GioRock 2018
// https://www.elettronica.cc/
//*****************************************************************************
file RotaryPulseToTone.h
Codice: Seleziona tutto
//*****************************************************************************
// Title : Pulse to tone (DTMF) converter
// Author : Boris Cherkasskiy
// Created : 2011-10-24
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// DTMF generator logic is loosely based on the AVR314 app note from Atmel
//
//*****************************************************************************
//*****************************************************************************
// PIC16F628A VERSION TRANSLATED BY GioRock 2018
// https://www.elettronica.cc/
//*****************************************************************************
IMPOSTAZIONI DI COMPILAZIONE:
LIBRERIE:
L'unica libreria utilizzata è quella per leggere e scrivere nella EEPROM, quindi deselezionate tutte le altre e spuntate solo quella...
NON CERCATE DI UTILIZZARE L'OSCILLATORE INTERNO PER RISPARMIARE SUI COMPONENTI, QUELLI CHE LO HANNO FATTO SI SONO PENTITI RISCONTRANTO IRREGOLARITA' SIA NEL RICONOSCIMENTO DEGLI IMPULSI CHE NELLA GENERAZIONE DEI TONI, LO SCHEMA DEVE ESSERE RISPETTATO COSI' COM'E', IL QUARZO DA 8MHZ (HS) E' D'OBBLIGO...
COMPORRE I CARATTERI SPECIALI:
Per comporre l'asterisco (*) ed il cancelletto (#), bisogna selezionare i numeri 1 e 2 ruotarli e tenerli premuti fino a che si ode un suono bitonale acuto, rilasciandoli verrà composto il carattere speciale con la giusta tonalità...
COMPOSIZIONE RAPIDA:
Per comporre un numero in memoria come selezione rapida, scegliere un numero da 3 a 9 ruotare e tenere fermo per 2s fino a che si ode un suono bitonale acuto, a questo punto rilasciare il disco, se la cella memoria è piena verrà composto il numero selezionato, altrimenti non si udirà nulla...
MEMORIZZAZIONE NUMERO:
Per memorizzare un numero nella EEPROM, selezionare lo ZERO (0) e ruotarlo tenendolo fermo fino a che non si ode un suono bitonale acuto, a questo punto rilasciandolo si udirà una specie di musichetta che significa che siamo entrati in modalità di programmazione, ora scegliere una cella di memoria da 3 a 9 ruotare e rilasciare si udirà un breve segnale che indica che possiamo comporre il numero, una volta fatto selezioniamo di nuovo lo ZERO (0) ruotiamo e teniamolo premuto fino al segnale acustico per poi rilasciarlo, un altro motivetto confermerà la memorizzazione del numero...
Nota: durante la composizione del numero non si udiranno i toni DTMF per non far partire la telefonata, un semplice BEEP monotonale scandisce questa fase senza interferire con la linea telefonica...
CANCELLAZIONE DI UN MUMERO IN MEMORIA:
Per cancellare un numero in memoria basta seguire la fase di memorizzazione senza comporre nessun numero, confermando con lo ZERO (0) la memoria verrà sovrascritta con un valore di -1 (0xFF)...
SEGNALAZIONE ERRORI:
Se durante l'utilizzo si ode un suono lungo, vuol dire che c'è stato un errore o qualcosa è andato storto, per azzerarlo basta riagganciare per qualche secondo in modo da resettare il uP...
Data la presenza di 5 pin ancora liberi (no RA0, RA1 e RB<6:7>), si potrebbe alimentarlo esternamente per aggiungere dei LEDs di segnalazione creando così una sorta di avvisatore ottico dei vari stati, a me ne è servito solo uno per scandire il riconoscimento dei numeri composti, per il resto lascio sempre a Voi il compito di personalizzare il codice con nuovi ed utili gadget...
P.S. Eventuali suggerimenti o idee per migliorare ulteriormente il programma saranno sempre ben accette, astenersi per cortesia dal criticare cose che non si comprendono a fondo o solo per il gusto di parlare del benamato nulla, il mettere a punto il tutto ha richiesto parecchio impegno e lavoro per non parlare del molto tempo speso per ottimizzare e testare tutte le parti del circuito , se proprio non vi gusta in rete lo vendono ad una cinquantina di €uro, al limite attendo con ansia la vostra preziosa versione...
GioRock - Mar 2018
Nulla va lasciato al caso se non si vuol mirar fumanti scintille... ![Shocked :shock:](./images/smilies/icon_eek.gif)
![Shocked :shock:](./images/smilies/icon_eek.gif)