Come può un Arduino emettere una frequenza portante specifica (cioè 56 kHz)?


9

Sto lavorando a un progetto di ottica di spazio libero per inviare dati in modalità wireless tra due punti. Per fare ciò sto usando un LED IR collegato ad un Arduino Uno che pulsa con una frequenza portante a 56 kHz per il trasmettitore e un secondo Arduino con un modulo rivelatore IR a 56 kHz per il ricevitore.

Ho provato a usare delayMicroseconds () tra i comandi pin high e pin low per creare la frequenza portante. Questo tipo di funzionamento funziona, ma la frequenza non è sempre la stessa e qualsiasi ulteriore ritardo nell'impulso del segnale (ovvero il tempo necessario per chiamare la funzione e decrementare) può modificarlo.

Leggendo il foglio dati per ATmega328 sembra che ci sia un modo per impostare un impulso più accurato usando i timer del chip. È possibile e, in tal caso, come si crea un impulso a 56 kHz utilizzando i timer?


Qual è la precisione di cui hai bisogno per la tua frequenza a 56KHz? Vale a dire quale gamma di frequenza è accettabile nel tuo progetto? Chiedo perché usando solo i timer Arduino, la precisione ha dei limiti.
jfpoilpret,

Da 55,5 kHz a 56,5 kHz sarebbe l'ideale per mantenere un alto livello di reattività nel rivelatore.
jlbnjmn,

Risposte:


10

È infatti possibile generare un segnale a 56 kHz con un timer Arduino .

Un timer in realtà può essere visto come un registro speciale, nell'MCU, che contiene un valore (che inizia da 0) che viene incrementato ad una frequenza che è la frequenza di clock MCU (16 MHz su Arduino Uno), possibilità divisa per un fattore chiamato prescaler . Quando quel valore raggiunge un limite, chiamato Confronta corrispondenza , che specifichi, allora accadono due cose:

  • Il valore del registro timer viene reimpostato su 0.
  • Un ISR funzione di callback (interrupt routine di servizio) viene chiamato (è possibile definire in modo che punti al proprio codice).

L'idea è di utilizzare quell'ISR per modificare l'output di un pin logico ogni volta che viene chiamato ( HIGH, quindi LOW, quindi HIGH...).

Ora, per generare un'onda quadra a 56 kHz, avrai bisogno che il tuo ISR venga chiamato 56000 * 2volte al secondo ( * 2perché devi cambiare il valore di uscita due volte per periodo).

Puoi scegliere il valore prescaler desiderato per un timer tra il seguente elenco:

  • 1 (la frequenza di clock non è divisa, quindi 16 MHz)
  • 8 (la frequenza di clock è divisa per 8, quindi 2 MHz)
  • 64
  • 256
  • 1024

Esistono due dimensioni di timer / contatori su Arduino Uno (in realtà sono chiamati timer / contatore ): 8 bit e 16 bit.

Su Arduino Uno (ATmega328P), hai complessivamente tre timer, ma alcuni potrebbero essere usati dalla libreria principale di Arduino o altre librerie usate nei tuoi schizzi (dovrai verificarlo da solo):

  • timer0 (8 bit)
  • timer1 (16 bit)
  • timer2 (8 bit): questo ha più opzioni di prescaling (1, 8, 32, 64, 128, 256 e 1024)

Ora devi generare un'onda a 56 kHz da 16 MHz, quindi, senza prescaling, dovrai contare per:

16000000 / (56000 * 2) - 1 = 141.857( - 1perché un timer conta da 0 a questo valore e si reimposta solo dopo che è stato raggiunto)

Da questo calcolo, possiamo trarre due osservazioni:

  1. 141.857 non è un numero intero e quindi non sarai in grado di generare un'onda di esattamente 56 kHz.
  2. Senza prescaling, è necessario un timer a 16 bit poiché 285 non è rappresentabile come intero senza segno a 8 bit.

Da adesso hai due opzioni:

  1. Usa un timer a 16 bit ( timer1 ), usa prescaler = 1 e seleziona 142come Confronta confronto; che ti darà la seguente frequenza:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Usa un timer a 8 bit ( timer0 ), usa prescaler = 8 e seleziona 17come Match Match; ciò darà meno precisione con la seguente frequenza: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hzche è ancora all'interno dell'intervallo richiesto.

Ora, riguardo a come scrivere il tuo schizzo per questo, ti consiglio di dare un'occhiata a questo istruttore che è molto completo e molto interessante da leggere.

Naturalmente, anche il foglio dati completo di ATmega328P è importante se vuoi capire, nei minimi dettagli, cosa stai facendo.

Alcune note importanti:

  • Un ISR viene eseguito con interruzioni disabilitate e deve quindi essere il più breve possibile. In particolare, ci sono diverse funzioni della libreria Arduino che non devono essere chiamate da un ISR.
  • L'orologio Arduino Uno non è molto preciso (utilizza un risonatore in ceramica anziché un quarzo, che sarebbe stato molto più preciso), quindi questo significa che la frequenza di uscita si sposterà ulteriormente.

2
Anche quando viene raggiunto il limite specificato, l' hardware può attivare / disattivare un pin. Pertanto non è necessario utilizzare gli ISR. Ci sarà sempre jitter con un ISR perché un'istruzione non può essere interrotta una volta iniziata. Tuttavia, l'hardware attiverà sempre il pin alla velocità desiderata.
Nick Gammon

È piuttosto sorprendente che Arduino Uno utilizzi un risuonatore ceramico, ma una fonte per questo è Arduino UNO FAQ (vicino a "Uno usa un risonatore o un cristallo per l'orologio del processore?" ).
Peter Mortensen,

3

Ho trovato tone()utile per generare impulsi ad alta frequenza su qualsiasi pin. Dovrebbe essere in grado di gestire 56 KHz. (Modifica: come notato da jfpoilpret, il più vicino che potresti effettivamente ottenere su un Arduino a 16 MHz è di circa 55,944 KHz)

La difficoltà sarà ovviamente combinarla con il tuo segnale dati. Non credo che potresti farlo nel software senza ricorrere a codice di basso livello. Dovrebbe essere piuttosto facile nell'hardware, dal momento che è digitale.

Tutto quello che dovresti fare è emettere il tuo segnale dati su un altro pin e poi combinarlo con il corriere usando un gate AND. Il segnale combinato può andare direttamente al trasmettitore IR.

Se non hai una porta AND a portata di mano, è abbastanza semplice crearne una tua usando una coppia di transistor. Basta cercare online "transistor e gate".


I ricevitori hanno spesso uscite attive basse in generale. Se si collega la parte superiore del LED a 56 khz e la parte inferiore al pin dati, quando il pin dati si abbassa si ottiene l'output IR, il che dovrebbe rendere basso il ricevitore. No e cancello necessari, solo un led e una resistenza. L'unico problema è limitato a qualunque pin io corrente possa guidare.
EternityForest

2

La risposta accettata di jfpoilpret è scritta molto bene, perfettamente valida e nel 99% dei casi farò esattamente quello che spiega. Le sue soluzioni rientrano nei parametri definiti, quindi dovrebbero funzionare molto bene. Ma cosa c'è di meglio di " molto bene "? Perfezione! Dopotutto, la domanda riguarda la generazione di un valore esatto. Come detto abbastanza vicino è buono nella maggior parte dei casi (probabilmente tutti), e anche quando hai a che fare con qualcosa come un orologio quando 1 secondo deve essere 1 secondo, devi ancora subire le imperfezioni delle parti ereditate.

Quello che suggerirò non è sempre possibile. In alcuni casi, è possibile, ma con molta più seccatura e fatica di questo caso. Vale la pena dipendere caso per caso. Il mio obiettivo è principalmente quello di mostrare un'alternativa per riferimenti futuri che sia migliore in casi piuttosto marginali. Questo è scritto pensando agli utenti principianti di Arduino che non hanno una vasta esperienza nell'elettronica.

Per le persone più avanzate questo probabilmente sembrerà troppo dettagliato e stupito. Ma credo che quelle stesse persone probabilmente lo sappiano già e non abbiano bisogno di questa risposta. Ciò è applicabile anche a tutti i microcontrollori, a tutti i produttori e alle architetture. Ma per altri microcontrollori dovrai consultare la scheda tecnica corretta per scoprire registri e nomi e valori di rivendita adeguati.

Nel tuo caso, hai bisogno di una frequenza specifica e la cosa bella è che è possibile ottenere esattamente 56 kHz in modo molto semplice (senza contare le imperfezioni pratiche delle parti). Quindi anche questo è un esempio perfetto.

La generazione di un segnale dipende dai timer e dalla sorgente di clock del microcontrollore, come spiegato bene da jfpoilpret. La sua risposta affronta il problema di un solo punto di vista e che sta armeggiando con i timer. Ma puoi giocherellare anche con la sorgente di clock, o ancora meglio con entrambi per sinergia e risultati fantastici. Modificando i parametri dell'ambiente, in questo caso hackerando il sistema e sostituendo l'origine del clock, possiamo affrontare un problema specifico con molta, molta più facilità e semplicità.

In primo luogo ricordare, a causa della commutazione dello stato del pin, è necessario eseguire l'ISR due volte più della frequenza del segnale. Questo è 112.000 volte al secondo. 56.000 e 16.000.000 non si sommano molto bene come già sottolineato. Dobbiamo cambiare la frequenza del segnale o la frequenza di tatto. Affrontiamo per ora una frequenza del segnale immutabile e troviamo una migliore velocità di clock.

Sarebbe molto semplice scegliere un orologio con un ordine di grandezza maggiore di 56 kHz (o 112 kHz, ma è praticamente lo stesso), poiché aggiungi solo zeri e questo tipo di matematica è più semplice per la maggior parte delle persone. Purtroppo tutto in questo mondo è una sorta di compromesso con qualcosa. Non tutti i valori funzioneranno.

Il primo esempio è con una velocità del generatore di tatto troppo bassa.

Se scegli un orologio a 56.000 Hz non sarai in grado di fare nulla poiché dovrai chiamare l'ISR ad ogni ciclo e non puoi fare nient'altro. È assolutamente inutile. Se scegli una velocità 10 volte più veloce (560 kHz), avrai 9 (10 cicli affinché il timer raggiunga il suo valore massimo - un ciclo per chiamare la funzione ISR) cicli di microcontrollore per fare il tuo lavoro e questo abbastanza possibile non può essere sufficiente. Spesso semplicemente hai bisogno di più potere computazionale.

Se si sceglie un valore troppo grande, d'altra parte, come 56 MHz il microcontrollore semplicemente non può funzionare con esso. È troppo veloce. Quindi, semplicemente scegliendo il valore più grande nel negozio non lo taglierà neanche.

Arduino Uno R3 originale ha un clock di serie a 16 MHz, quindi tutto ciò che è più lento è garantito per funzionare. Il valore successivo che è un ordine di grandezza maggiore di 56 e inferiore a 16 MHz è 5,6 MHz. Ciò porterà a poter chiamare l'ISR ogni 50 cicli e creerà la frequenza del timer perfetta di 112.000 Hz. E il tuo segnale sarà esattamente 56 kHz. Avrai 49 cicli MCU per eseguire il tuo programma tra le chiamate ISR, ma è ancora circa 1/3 della velocità dell'orologio originale. Si può usare il 112 come base e usare un clock a 11.2 MHz e questo darà circa 2/3 del risonatore a 16 MHz di serie. La funzione ISR verrà chiamata ogni 100 cicli e genererà comunque un segnale perfetto a 56 kHz.

Tuttavia esistono due problemi principali con questi valori.

  • Il primo problema dipende fortemente dalle tue esigenze: sacrifichi circa 1/3 (con 11,2 MHz) della tua massima potenza computazionale per ottenere la frequenza esatta del segnale che utilizza un valore di registro facile da trovare (OCR iirc ). Potresti star bene o no.

  • Il secondo problema è un duro spettacolo : è molto facile trovare valori, ma molto spesso semplicemente non esistono come una sorgente di clock prodotta. Questa è la pagina web del risonatore di Farnell che manca semplicemente di 5,6 MHz e 11,2 MHz.

Per aggirare questo, possiamo esaminare i valori di risonatore disponibili e scoprire qualcos'altro che può essere usato per generare esattamente i valori desiderati. Se dividiamo 56 per 4 otteniamo 14 e per fortuna c'è un risonatore a 14 MHz. Questo ci offre una velocità molto più elevata e una maggiore potenza e un valore di registro altrettanto facile da trovare. Per chiamare l'ISR 112.000 volte al secondo, dobbiamo inserire il valore decimale 124 o 0x7C esadecimale nel registro OCR, quindi con il conteggio di 124 cicli + 1 per chiamare l'ISR, otteniamo il valore desiderato desiderato.

NB

  1. ISR - routine di servizio di interrupt (questo è il codice che viene eseguito solo su interrupt generati)
  2. Quanto può essere grande il tuo programma dipende dalla dimensione della memoria! Non ha nulla a che fare con la velocità di clock e non ha nulla a che fare con la frequenza con cui si chiama ISR.
  3. Quando il microcontrollore si avvia con il comando di programma, viene incrementato un contatore. Se viene generato un interrupt, viene chiamato l'ISR e questo valore viene memorizzato in un registro speciale. Al termine del codice ISR, il valore del contatore del programma viene ripristinato da questo registro speciale e il programma continua da dove era stato interrotto come se non fosse mai accaduto.

    Farò un esempio estremamente stupito. Se sei un purista, ti avverto: possono verificarsi sanguinamento del naso e degli occhi.

    Immagina di dover camminare da qualche parte a qualche parte. Le istruzioni dettagliate sul percorso sono il tuo programma principale e i suoi comandi. La velocità con cui cammini o corri, dipende dalla tua "velocità di clock", ma non dalle istruzioni del percorso (30 passi avanti, 1 giro 90 gradi a sinistra, 10 passi avanti, 45 gradi a destra, ecc.) Sono sempre gli stessi . Ora immagina un bambino o un avido politico locale corrotto che ti scioglie le scarpe di tanto in tanto. Questo è l'evento che genera un interrupt. Quindi ti fermi dopo l'ultimo passo, ti inginocchi e leghi di nuovo la scarpa. Questo è il tuo programma ISR.

    Quindi prosegui dal punto in cui ti sei fermato; non inizi dall'inizio. Quando cammini senza preoccupazioni nel mondo e con tutto il tempo, non ti importa nemmeno se devi allacciarti le scarpe ogni altro passo. Se invece lo fai con vincoli di tempo, come correre a 100 metri alle Olimpiadi (o correre da un predatore affamato che mangia carne), fermarsi e allacciarsi le scarpe può avere conseguenze terribili. Lo stesso vale per i microcontrollori. Anche se esegui solo una riga di codice, il tuo programma continuerà, anche se lentamente. Se non ti interessa affatto la velocità, non sarà un problema. Se devi fare un po 'di tempo, come usare altre azioni dipendenti dal timer, l'interferenza può essere molto indesiderata e problematica.

  4. Meno è meglio! Un orologio più veloce non è sempre migliore. I dispositivi con clock più lento consumano molta meno energia. Questo può essere un punto cruciale in un dispositivo a batteria.

  5. I cicli necessari sono derivati ​​da queste formule:
    (velocità di clock / (valore prescaler * frequenza di chiamata ISR necessaria)) - 1


TLDR: dissaldare l'oscillatore ceramico a 16 MHz e sostituirlo con un altro che consenta esattamente 56 kHz per divisione intera (es. 14 MHz e divisione per 250).
Peter Mortensen,

0

È possibile accendere e spegnere il corriere semplicemente alternando la modalità pin del corriere tra output e input. L'ho usato per controllare una pompa di calore attraverso la porta a infrarossi (telecomando) a 37 KHz.


0

Non è necessario utilizzare un ISR per creare il corriere. Basta impostare un timer per produrre un'uscita PWM del 50% alla frequenza portante richiesta. L'ISR ha quindi solo il compito di modulare il vettore - in genere a intervalli di 0,5 o 1 ms - un tasso molto più comodo. Nella mia esperienza un errore del 5% nella frequenza portante è tollerato dalla maggior parte dei ricevitori IR. Ho usato un EtherMega 2560 di Freetronics (che ha molti timer) ma sono sicuro che anche altre CPU faranno altrettanto.


In che modo viene quindi implementata esattamente la modulazione del vettore? Cambiare la modalità per il pin di acquisizione dell'uscita del timer tra input (vettore spento) e output (vettore acceso)?
Peter Mortensen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.