LA CAMPANA

C'è chi ha letto questa notizia prima di te.
Iscriviti per ricevere gli ultimi articoli.
E-mail
Nome
Cognome
Come vuoi leggere The Bell
Niente spam
  • Trasferimento

Le candele elettroniche economiche sembrano essere ovunque ultimamente. Non ho prestato loro molta attenzione fino a quando ho notato che in realtà usano un LED speciale - con un controller "lampeggiante" incorporato. Ora è una questione completamente diversa: a chi non piacciono i LED misteriosi? Mezz'ora dopo avevo già raccolto una manciata di tremolanti LED di fabbricazione cinese.

Naturalmente, la domanda più interessante è come funzionano? Considerando che costano letteralmente pochi centesimi l'uno, non possono esserci componenti elettronici costosi all'interno. A questo proposito, sorge un'altra domanda: questi LED sono davvero peggiori delle numerose "candele" sui microcontrollori, quali schemi sono pieni su Internet?

Il dispositivo è relativamente semplice. Il pacchetto standard da 5 mm ospita il cristallo LED e il microcircuito, che è leggermente più grande del primo per dimensioni. Il circuito del controller è collegato a entrambi i terminali positivo e negativo. Il terzo ponticello collega ad esso l'anodo del LED, mentre il catodo "si trova" sul terminale negativo.

Il blog di Evil Mad Scientist ha recentemente pubblicato una storia su LED simili. Lì è stato mostrato come "cantano" se convertono i cambiamenti di luminosità in suono. E anche - come controllare un diodo più potente con il loro aiuto. Questi trucchi si basano sul fatto che il LED assorbe più corrente quando il controller lo accende più luminoso. Un LED normale in serie con uno tremolante mostra cambiamenti di luminosità molto simili. In altre parole, la caduta di tensione attraverso il resistore aggiuntivo cambia in proporzione alla luminosità.


Questo è quello che ho usato per estrarre il segnale di controllo del controller e portarlo all'analizzatore logico (vedi lo schema sopra). Regolando il resistore variabile, mi sono assicurato che l'analizzatore percepisse i picchi di corrente come "zeri" e "uno", e il LED funzionasse normalmente.


Il diagramma sopra mostra i cambiamenti nella luminosità del diodo per circa un minuto, registrati a una frequenza di campionamento di 1 MHz. Gli intervalli sono evidenti quando il LED è costantemente acceso e periodi in cui la sua luminosità è in qualche modo modulata. Il LED non si spegne mai per molto tempo. Questo ha senso, poiché anche una vera candela brilla per la maggior parte del tempo, attenuandosi per brevi periodi di sfarfallio.


Uno sguardo più attento rivela che il segnale è modulato a larghezza di impulso. Ciò significa che abbiamo un circuito digitale, senza trucchi analogici.

Curiosamente, la frequenza del segnale è di circa 440 Hz, come un diapason standard ( nota LA della prima ottava - ca. trad. ). Coincidenza? O lo sviluppatore ha semplicemente preso il generatore da uno schema musicale? Quindi c'è del vero nelle storie sulla "musicalità" di questi LED. Ogni "frame" di luminosità costante è esattamente di 32 cicli di clock e dura circa 72 ms. Ciò corrisponde a 13-14 fotogrammi al secondo.

Ho scritto un piccolo programma per determinare la luminosità in ogni fotogramma dal ciclo di lavoro del segnale PWM. Il programma legge un flusso di campioni dall'analizzatore logico e genera una serie di numeri reali, uno per ogni frame.


Il grafico della luminosità rispetto al tempo suggerisce alcune riflessioni: i cambiamenti di luminosità sono casuali, discreti e hanno una distribuzione non uniforme. Sembra che ci siano 16 livelli di luminosità, i 4 inferiori dei quali sono usati molto raramente. Solo 13 su 3600 letture corrispondono a loro.


Costruire un istogramma rivela l'intera immagine: infatti, vengono utilizzati solo 12 livelli di luminosità. Esattamente la metà dei fotogrammi ha la massima luminosità, il resto dei valori è distribuito in modo approssimativamente uguale.

Come può essere implementato nell'hardware? È probabile che venga utilizzato un generatore di numeri casuali distribuito uniformemente, che viene passato attraverso una semplice funzione di generatore. La distribuzione che osserviamo richiede almeno 12x2 \u003d 24 livelli discreti. La metà di questi vengono visualizzati in uno. Questo è curioso, poiché è probabile che il generatore produca numeri binari. Il numero più logico sarebbe 5 bit e questi sono 32 stati. La visualizzazione di una variabile casuale discreta a 32 livelli e 24 livelli senza modificare la distribuzione non è così facile come sembra. Inoltre, non dimentichiamo che questo non è affatto uno schema critico e lo sviluppatore probabilmente non ha avuto molto tempo per una bella soluzione. Pertanto, ha applicato il tipo più semplice di hack.

L'unico modo semplice che mi viene in mente è semplicemente scartare i valori non adatti e prendere il numero casuale successivo. I valori indesiderati possono essere facilmente separati dalla maschera di bit. Poiché il circuito è sincrono, c'è solo un numero finito di tentativi fino all'inizio del frame successivo. Se il controller non soddisfa il numero di tentativi specificato, si bloccherà sul valore "sbagliato". Ricordi i rari difetti nel grafico della luminosità?

Un'implementazione ANSI-C potrebbe essere simile a questa:
tentativi di caratteri \u003d 0; carbonizzare; while (tentativi ++ 15) out \u003d 15; // la metà superiore dell'intervallo corrisponde alla luminosità massima

Quanti tentativi si stanno facendo? Secondo le statistiche, la quota a \u003d 0,25 tutti i numeri devono essere scartati e rigenerati. La probabilità di cosa n non verrà fatto alcun tentativo di selezionare il numero "corretto", uguale un.
n \u003d 1 0,25 n \u003d 2 0,0625 n \u003d 3 0,015625 n \u003d 4 0,003906

La quota di livelli di luminosità anormalmente bassi è 13/3600=0,0036 , che si abbina bene con l'opzione n \u003d 4... Quindi, MAX_ATTEMPTS \u003d\u003d 4.

Si noti che una soluzione più semplice sarebbe quella di utilizzare semplicemente il valore del frame precedente se è stato rilevato un numero non valido. Questa opzione potrebbe essere esclusa in base all'autocorrelazione (vedi sotto). Probabilmente la soluzione più semplice - cambiare il circuito PWM - non è stata utilizzata qui.

L'ultimo pezzo del puzzle è lo stesso generatore di numeri casuali. Un modo tipico per generare sequenze casuali nei circuiti digitali consiste nell'usare registri a scorrimento a retroazione lineare. Tale registro produce una sequenza di bit pseudo-casuale, che verrà ripetuta non più tardi di dopo 2 x -1 zecca dove x - registrare la larghezza di bit. Una delle caratteristiche di tali sequenze (e delle buone sequenze pseudocasuali in generale) è che la loro funzione di autocorrelazione è uguale a uno solo nel punto 0 e in coordinate che sono multipli della lunghezza della sequenza. In tutti gli altri intervalli, è zero.


Ho calcolato l'autocorrelazione dell'intera sequenza di valori. L'auto-similarità non è stata trovata fino a 3500 frame (solo 1200 sono mostrati nel grafico sopra), il che significa che lo sfarfallio è unico per almeno 4 minuti. Non è chiaro se è stata osservata un'ulteriore ripetizione della sequenza o se l'analizzatore logico dell'autore semplicemente non ha consentito la registrazione più a lungo - ca. trad. Poiché sono necessari almeno 5 bit di dati casuali per ogni frame (e anche di più dato il meccanismo per scartare i numeri indesiderati), la sequenza pseudocasuale è lunga almeno 17500 bit. Ciò richiederà un registro di almeno 17 bit o un generatore di numeri casuali hardware reale. In ogni caso, è interessante quanta attenzione è stata prestata durante lo sviluppo per garantire che il pattern di sfarfallio non si ripetesse.

In conclusione, risponderemo alle domande poste all'inizio dell'articolo. Lo sfarfallio del LED si è rivelato molto più difficile di quanto mi aspettassi (inoltre non mi aspettavo di passare 4 ore su di esso). Molte implementazioni di microcontrollori di candele inviano semplicemente bit dal generatore di numeri pseudo-casuali all'uscita PWM. Il LED acquistato utilizza un algoritmo di dimmerazione più sofisticato. Naturalmente, è stata prestata una certa attenzione allo sviluppo dell'algoritmo e, allo stesso tempo, è stato utilizzato un cristallo con un'area quasi la più piccola possibile. Un centesimo è ben speso.

Qual è il miglior algoritmo di sfarfallio? Può essere migliorato?

Aggiornamento: finalmente mi sono preso il tempo di scrivere un emulatore. Un programma scritto in ANSI-C che emula il comportamento di questo LED,

Stiamo scrivendo il primo programma!

La maggior parte inizia lampeggiando LED e non siamo diversi. Se un microcontrollore, anche il più veloce, non "comunica" con il mondo esterno, il suo valore si riduce a zero. Abbiamo bisogno del microcontrollore per ricevere le informazioni, elaborarle secondo un dato algoritmo e fornire il risultato in una forma che sia per noi comprensibile.

Algoritmo, (per conto del matematico persiano al-Khwarizmi) - un insieme esatto di istruzioni che descrivono l'ordine delle azioni dell'esecutore per ottenere il risultato della risoluzione di un problema in un certo tempo.
Per scrivere correttamente i programmi, è necessario capire come funziona il microcontrollore, cosa che faremo, ma per ora comporremo il primo programma in assembler.

In generale, puoi scrivere un programma in qualsiasi editor di testo, proprio come scriveresti una lettera a un amico, per esempio. Dopodiché, il testo deve essere compilato (a volte si dice - assemblato) ad es. tradurre in una forma che il processore possa capire. In precedenza, l'estensione del file di testo .txt veniva rinominata .asm ed elaborata da un programma speciale chiamato compilatore. L'essenza del lavoro del compilatore è tradurre caratteri scritti leggibili dall'uomo in codice macchina (nel codice di zero e uno) e creare un nuovo file con estensione .hex

Cosa fare con questo file .hex? Ed è necessario che il programmatore scriva il codice del programma nella ROM (memoria di sola lettura) del microcontrollore. Useremo il programma invece del programmatore Proteusche modula un vero e proprio circuito funzionante.
NEL AVR Studio 5 editor, compilatore, debugger e programmatore tutto in uno!

Direttiva - questa è una ricetta per l'editore con cui lavoreremo. Per la maggior parte, il nome della direttiva e la sua funzione sono le stesse in diversi editor. Ad esempio, se confronti l'editor IDE MPLAB per i microcontrollori PIC, praticamente non c'è differenza!
Ma le squadre sono diverse. L'elenco delle squadre è formato dal produttore e in una certa misura dipende dalla tecnologia di produzione. Anche lo stesso produttore in famiglie diverse può avere un elenco di comandi diverso quando la loro struttura cambia.
ComandoÈ un'unica funzione con la quale possiamo controllare il microcontrollore.
Programmaè una sequenza di comandi corrispondente a un determinato algoritmo (compilato da noi).
Ogni programma inizia con un "header", dove vengono scritte le funzioni principali del programma, il suo autore, il nome del controller che verrà utilizzato, la frequenza di clock e altri dati. Un "limite" è una regola di "buona forma" nella programmazione.
Di solito, il file di inizializzazione.includeххххdef.inc è scritto nell'intestazione. direttive .device, .list, .nolist e altri.
NEL AVR Studio 5 queste direttive vengono scritte per impostazione predefinita. Nella versione precedente AVR Studio 4 queste direttive dovevano essere scritte, quindi le ho lasciate come commenti.
I commenti sono scritti arbitrariamente, come preferisci e l'importante è che rimangano comprensibili per te. Spesso, a causa di commenti incompleti, dopo un certo periodo di tempo l'autore stesso non riesce a capire il proprio programma. I commenti sono preceduti da un segno (;).
Ho introdotto il "tappo" suggerito da John Morton ...

Editor di AVR Studio 5 - comprende scritte, direttive e comandi evidenziandole in blu, i dati numerici rimangono neri, le espressioni incomprensibili in rosso, i commenti in verde.

Prima di iniziare, diamo un'occhiata alle direttive assembler del microcontrollore AVR.
Ogni direttiva è preceduta da un punto:
Direttiva Descrizione BYTE Riserva byte in RAM CSEG Segmento di programma DB Definisce un byte - costante nella memoria Flash o EEPROM .DEF Assegna un nome simbolico al registro DEVICE Definisce il dispositivo per il quale viene compilato il programma DSEG Segmento dati.DW Definisce una parola in Flash memoria o EEPROM .ENDM Fine macro.ENDMACRO Fine macro.EQU Imposta espressione costante.ESEG Segmento EEPROM .EXIT Esci da file.INCLUDE Allega un altro file.LIST Attiva generazione elenco. LISTMAC Attiva espansione macro in elenco.MACRO Avvia macro.NOLIST Disattiva generazione Elenco ORG Imposta la posizione nel segmento SET Imposta la variabile su un'espressione equivalente

Descrizione completa dei comandi e delle direttive assembler nella traduzione russa Ruslan Shimkevich può essere visualizzato qui:
🕗 24/09/11 ⚖️ 397,28 Kb ⇣ 244 Ciao lettore! Mi chiamo Igor, ho 45 anni, sono siberiano e un appassionato ingegnere elettronico dilettante. Ho inventato, creato e gestito questo meraviglioso sito dal 2006.
Per più di 10 anni la nostra rivista è esistita esclusivamente con i miei fondi.

Buona! L'omaggio è finito. Se vuoi file e articoli utili, aiutami!

--
Grazie per l'attenzione!

Torneremo più di una volta alle direttive dell'assembler, e ora proveremo a scrivere un piccolo codice di programma in cui accenderemo i LED.
Per comodità, sceglieremo un microcontrollore ATtiny2313A... Se qualcuno va oltre e sperimenterà in hardware, questo controller è uno dei più convenienti, molto spesso utilizzato in vari progetti che si possono trovare nelle vaste distese della rete.

--
Grazie per l'attenzione!
Igor Kotov, redattore capo della rivista "Datagor"


Devi solo decomprimerlo e avviarlo (a condizione che Proteusgià installato).
Dovrebbe apparire la seguente immagine:

Corriamo AVR Studio 5e nell'editor scriveremo un programmino con commenti dettagliati:
.def temp \u003d r16; la direttiva .def assegna al registro r16 il nome temp; \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d; Inizio di program.cseg; la direttiva .cseg definisce l'inizio del segmento in cui verrà posizionato; codice programma principale. In AVR Studio 5, questa direttiva non lo è; required.org 0; l'inizio della prima riga del programma rjmp Start; salto relativo all'etichetta Start (in PIC corrisponde al comando; goto); \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d \u003d\u003d Inizio: ser temp; imposta tutti i bit del registro temporaneo su 1 out DDRB, temp; traduce tutti i bit in DDRD, temp; porte B e D per clr temp pin; cancella il registro temporaneo (imposta tutti i bit del registro temporaneo a 0) out PortB, temp; disabilita le resistenze pull-up in uscita PortD, temp; porte B e D Cicle: ldi temp, 0b11001100; accende i LED fuori PortB, temp; porta B rjmp Cicle; Torna all'etichetta Cicle, loop

Compiliamolo cliccando su F7
Nella finestra Output appariranno le informazioni sulla compilazione, alla fine dovrebbe esserci una scritta Build riuscita, che conferma l'avvenuto assemblaggio del file .hex.


Questo file si trova per impostazione predefinita in My Documents, nel progetto AVR Studio 5.

Vai a Proteus, fare clic sul disegno del controller e immettere il percorso in cui si trova il file .hex:




Iniziamo l'emulazione del programma.
Dopo aver premuto il pulsante Start, vediamo il risultato!



Per interrompere l'emulazione, fare clic su Stop.
Se lampeggi il microcontrollore con un programmatore e monti il \u200b\u200bcircuito, il risultato sarà lo stesso.

Proviamo a capirlo con il programma:

Linea:
.def temp \u003d r16; la direttiva .def assegna al registro r16 il nome temp
Per comodità, abbiamo assegnato al registro r16 il nome temp, il che significa che ovunque nel programma, quando si scrive la parola temp, il programma farà riferimento al registro r16.
Cos'è questo registro - r16?
Si riferisce a registri di uso generale, designati come r0… .r31, ovvero ci sono solo 32 bit su 8 ciascuno. La seconda metà dei registri di uso generale r16 ... r31 svolge la funzione di memorizzazione temporanea delle informazioni (come batterie, possono ricevere e possono inviare informazioni, per confronto - i controller PIC hanno solo una batteria W). Gli ultimi 6 registri per uso generale sono convenzionalmente combinati in tre registri a 16 bit:

Notare che il byte più significativo viene scritto prima, il meno significativo dopo.

r27: r26 è chiamato registro X,
r29: r28 è chiamato registro Y,
r31: r30 è chiamato registro Z.
Il programma funzionerà anche se la parola temp è assegnata a qualsiasi altro registro generale da r16 a r31 es. Def temp \u003d r20. Dopo la compilazione (tasto F7 in AVR Studio 5), non c'è differenza nel funzionamento del programma.
(Puoi provare, ora sai come farlo!)

Linea:
.cseg; La direttiva cseg definisce l'inizio del segmento in cui verrà posizionato il codice del programma principale
In AVR Studio 5 questa direttiva è scritta per impostazione predefinita.
Nei microcontrollori AVR, sono allocate diverse aree di memoria per memorizzare il codice del programma, i dati nella memoria permanente o EEPROM, ci sono directory per designare quest'area:
.cseg - Segmento di programma
.dseg: segmento di dati
.eseg - Segmento EEPROM

Linea:
.org 0; inizio della prima riga del programma
Il programma parte dalla riga specificata dalla direttiva.org e vi ritornerà al termine.

Linea:
rjmp Start; salto relativo all'etichetta Start (in PIC corrisponde al comando goto)
Questo è un comando di salto relativo all'etichetta Start.
Il programma viene eseguito in sequenza dallo scarico superiore a quello inferiore. Se è necessario andare in un'altra area del programma, utilizzare il comando rjmp

Le linee:
ser temp; imposta tutti i bit del registro temp a 1 clr temp; cancella il registro temporaneo (imposta tutti i bit del registro temporaneo a 0)
Il comando ser viene eseguito con i registri r16… r31 e il comando clr può essere eseguito su tutti i registri, inclusi i registri I / O (registri per scopi speciali). Vedremo in seguito lo scopo di questi registri.

Linea:
ldi temp, 0b11001100
Il comando ldi scrive il numero binario 11001100 nel registro temporaneo (non sarà un errore se invece di 0b11001100 scrivi 204 o CCh, in un caso in forma decimale nell'altro in esadecimale)

Linea:
uscita DDRB, temp
Il comando out scrive il valore del registro temporaneo nel registro della porta DDRB.

Cos'è un port e come funziona?

Se semplificata al minimo, la porta può essere rappresentata come pin-out di un microcontrollore, a cui in modalità di uscita è possibile applicare arbitrariamente tensione o disconnessione, e in modalità di ingresso, determinare se c'è una tensione fornita dall'esterno o meno.
Esistono tre modalità di funzionamento della porta: questi sono output, input e stato disconnesso.
Le porte sono controllate dai registri PinX, PortX, DDRX.
X - indica la porta controllata da questi registri.
Il registro DDRX controlla le modalità I / O, come un relè - acceso (scritto 1) - collegato alla linea di uscita, scollegato (scritto 0) - commutato sulla linea di ingresso (per impostazione predefinita).

Per inviare i dati alla porta X, è necessario commutare il registro DDRX in modalità di output (scrittura 1) e inviare i dati al registro PortX.
È possibile leggere il valore della porta X se il registro DDRX è impostato sulla modalità di ingresso (scrittura 0) dal registro PinX. Per collegare resistenze pull-up in modalità input, è necessario inviare i dati a PortX.
Le resistenze pull-up ci salvano dalla necessità di collegare resistenze esterne al filo positivo e, con l'aiuto di un comando, forniscono esse stesse una logica all'ingresso.

Voto del lettore

L'articolo è stato approvato da 23 lettori.

Per partecipare alla votazione, registrati ed entra nel sito con username e password.

L'articolo prenderà in considerazione il collegamento di LED a un microcontrollore, lavorando con le porte e scrivendo un programma in SI. L'articolo è destinato principalmente ai principianti che hanno appena iniziato a lavorare sui microcontrollori AVR.

Per prima cosa devi scegliere un microcontrollore. Nel mio caso, questo è ATmega8535. In questo caso, puoi prendere qualsiasi microcontrollore, poiché questa attività è facilmente implementabile per qualsiasi MC. Puoi scrivere un programma per un microcontrollore in Assembler, SI, Pascal e Bascom. Ho usato il linguaggio C, tutti questi linguaggi sono diversi.
La differenza specifica tra C e Pascal può essere vista di seguito.

// LED lampeggiante void main () (ddrB \u003d 0b11111111; // imposta le porte B sulla porta di uscitaB \u003d 0b11111111; // per impostazione predefinita tutto è spento mentre (1) (portB \u003d ˜portB; // cambia lo stato del LED al contrario delay_ms (100 ); // effettua un ritardo di 100 millisecondi))

Primo programma; inizio ddrB: \u003d $ FF; // imposta la porta B sulla porta di uscitaB: \u003d $ FF; // per impostazione predefinita non è attivo nulla mentre (1) inizia portB: \u003d not (portB); // cambia lo stato del LED in delay_ms (100) opposto; // termina un po 'di ritardo; fine.

Elenco dei radioelementi

Designazione Un tipo Denominazione quantità NotaPuntoIl mio blocco note
U1 MK AVR 8 bit

ATmega8535

1 Nel blocco note
R1-R8 Resistore

220 Ohm - 1 kOhm

8 Nel blocco note
R9-R11 Resistore

10 kΩ

3 Nel blocco note
V1-V8 Diodo ad emissione luminosa 8 Nel blocco note
Pulsante di tatto 3

Quando si scrive un programma, è spesso necessario formare un certo intervallo di tempo tra i singoli comandi. Un buon esempio di ciò è una ghirlanda in cui le luci si accendono in una certa sequenza a intervalli. Nel nostro caso, per indicare il ritardo, utilizzeremo un led lampeggiante, o preferibilmente due e di diverso colore. Controlleremo la durata della loro accensione e spegnimento, ovvero, cambieremo la frequenza di lampeggiamento.

La maggior parte dei comandi nei microcontrollori AVR vengono eseguiti in un ciclo di clock del master clock. Nella capacità di cui il circuito RC integrato nell'MK è ampiamente utilizzato o un risonatore al quarzo è collegato ai pin XTAL1 e XTAL2.

Ad esempio, se MK funziona a una frequenza di 1 Hz, verrà eseguito un comando in un secondo.

Per impostazione predefinita, l'ATmega8 ha un proprio generatore di frequenza interno, o meglio un circuito RC, che funziona a una frequenza di 1000.000 Hz \u003d 1 MHz. Pertanto, il tempo di esecuzione di un comando è:

Ne consegue che se annotiamo due comandi di seguito, ciascuno dei quali accenderà un LED separato, vedremo visivamente che si accendono entrambi contemporaneamente.

#includere

int main (void)

DDRD \u003d 0b000000011;

mentre (1)

PORTD \u003d 0b000000001; // Accende il primo LED

PORTD \u003d 0b000000010; // Accende il 2 ° LED

Ma in effetti, il secondo LED si accenderà con una differenza di tempo di 0,000001 secondi dal primo. I nostri occhi non possono vedere una così piccola differenza di fuso orario. Già a una frequenza di immagine superiore a 24 Hz (t \u003d 1/24 ≈ 0,042 s), la nostra visione forma una pellicola continua dalle singole immagini. Pertanto, nella maggior parte dei casi, non distinguiamo il 25 ° fotogramma.

Affinché entrambi i LED si accendano con una differenza di tempo di 0,5 secondi, è necessario tra i due comandi corrispondenti (PORTD \u003d 0b000000001; e PORTD \u003d 0b000000010;) inserire altri 500.000 comandi vuoti a ciclo singolo, ovvero fare in modo che il MK non esegua alcun comando utile per mezzo secondo azione. Oppure, come si suol dire, devi "uccidere" 500.000 tick. Se il codice è scritto in Assembler, i programmatori utilizzano loop diversi che "consumano" un certo numero di cicli di clock e quindi ottengono intervalli di tempo diversi.

#includere

int main (void)

DDRD \u003d 0b000000011;

mentre (1)

PORTD \u003d 0b000000001; // Accende il primo LED

Per ottenere un ritardo di 0,5 secondi, è necessario inserire qui

500.000 comandi di un ciclo

PORTD \u003d 0b000000010; // Accendi il 2 °

Funzione _delay_ms () e LED lampeggiante

Quando si scrive codice C in Atmel Studio, c'è una funzione molto comoda _delay_ms(). Perché questa funzione funzioni, deve prima essere collegata alla direttiva del preprocessore .

Tra parentesi di questa funzione, puoi impostare il tempo in millisecondi, quindi devi scrivere ms prima delle parentesi, o noi in microsecondi:

Quando si utilizza questa funzione, in modo che Atmel Studio non generi alcun avviso durante la compilazione, è necessario dichiarare la frequenza utilizzando l'istruzione #define. Poiché il valore predefinito per ATmega8 è 1.000.000 Hz, dichiareremo questo valore. Questo viene fatto con la seguente riga:

#definire F_CPU 1000000UL

In futuro, quando collegheremo un risonatore al quarzo all'MK, questa linea non potrà essere eliminata. La sua struttura rimarrà la stessa, solo che invece di 1.000.000 sarà necessario registrare la frequenza del risonatore al quarzo.

Miglioriamo il nostro programma in modo che il primo LED si accenda, poi dopo mezzo secondo si spenga e dopo un altro mezzo secondo si accenda il secondo e si spenga nuovamente dopo 0,5 secondi.

# definire

Diamo nuovamente un'occhiata al codice sopra. Se è necessario modificare il valore del ritardo nella funzione _ ritardo da 500, ad esempio, a 300, quindi dobbiamo trovare tutte le righe con il suo nome ed eseguire la sostituzione appropriata. Ora immaginiamo che ci siano cento o anche mille di queste righe. È estremamente scomodo e dispendioso in termini di tempo modificare il valore di ciascun numero separatamente. Puoi anche saltare accidentalmente una riga. Pertanto, è necessario adottare un approccio diverso, più conveniente e pratico.

Esistono diversi approcci di questo tipo. Il più semplice è dichiarare una variabile e assegnarle il valore desiderato. Inoltre, questa variabile viene sostituita nelle funzioni corrispondenti. Questo è un buon modo. Lo considereremo più in dettaglio in seguito. Ora ne vedremo uno ancora migliore!

Usiamo l'operatore #define per assegnare un nome al valore numerico. Questo nome è chiamato costante... A differenza di una variabile, una costante non può essere modificata in un programma. Assomiglia a questo:

#define MIG 300

_ ritardo_ sM(MIG);

Il nome della costante può essere impostato su quasi tutto, utilizzando caratteri latini e numeri. In questo caso, il nome MIG indica a cui stiamo applicando un ritardo momentocon LED.

Non c'è punto e virgola dopo la riga con la direttiva del preprocessore #define. Viene inserito uno spazio tra il nome della costante e il valore numerico.

Questa linea funziona come segue. Prima dell'inizio della compilazione, tutte le costanti denominate MIG vengono sostituite con 300.

#definire e si registra

Inoltre, l'operatore #define è buono in quanto puoi usarlo per impostare i nomi dei registri. Ad esempio, se colleghiamo i LED alla porta D, al posto di PORTD possiamo scrivere, ad esempio VD:

#define VD PORTD

VD \u003d 0b00000001;

Riscriviamo il programma usando la direttiva #define:

#definire F_CPU 1000000UL

#includere

#includere

Aggiunto: 28/06/2017 alle 13:00

In questo esempio, scriveremo il nostro primo programma C per il microcontrollore ATtiny13. Si presume che abbiamo già preparato per lavorare tutto ciò di cui hai bisogno: ambiente di sviluppo, compilatore, ecc. Come sperimentale, avrò rispettivamente una scheda di debug fatta in casa, citerò tutto il codice in relazione ad essa.
Come programma di test, scriveremo un esempio classico e più semplice di "lampeggio", che farà lampeggiare un LED a una certa frequenza.

Quindi, creiamo un nuovo progetto e iniziamo. Darò immediatamente il codice completo del programma, quindi spiegherò in modo più dettagliato:

/ * * tiny13_board_blink * Demo-firmware della scheda di debug su ATtiny13 * per verificare la funzionalità del MK. * Facciamo lampeggiare il LED. * / #define F_CPU 1200000UL // Specifica la frequenza di clock del MK #define LED PB2 // Usa il LED collegato a PB2 (7 pin) #include // Include le definizioni di I / O #include // Collega la libreria delle funzioni di ritardo int main (void) (// DDRB LED | \u003d (1<

All'inizio, impostiamo i valori delle costanti e includiamo i file di intestazione e le librerie.
File avr / io.h collega le definizioni di I / O per un tipo di microcontrollore specifico (il tipo MK è specificato come opzione per il compilatore).
La Biblioteca util / delay.h ci colleghiamo per utilizzare le funzioni di ritardo, nel nostro caso: _delay_ms ()... Affinché le funzioni di latenza funzionino, dobbiamo specificare la velocità di clock del processore. perciò PRIMA collegamenti util / delay.h definire una costante F_CPU (in questo caso - 1.2MHz).

Quindi abbiamo la funzione principale principale - questo è, infatti, il corpo del nostro programma. Qui dobbiamo prima descrivere tutte le azioni che avverranno all'avvio del microcontrollore e poi, in un ciclo infinito, avviare l'esecuzione del programma principale:

mentre (1) (...)

Innanzitutto, dobbiamo configurare la porta I / O. In MK AVR, possono esserci diverse porte I / O (A, B, C, D). È possibile collegare fino a otto pin a ciascuna porta. Ciascuna delle gambe può essere configurata sia per l'ingresso che per l'uscita. ATtiny13 ha solo una porta (B) con sei pin (PB0-PB5, vedere la scheda tecnica). Per impostazione predefinita, tutte le gambe sono impostate su input e per pilotare il LED, dobbiamo utilizzare la gamba corrispondente come uscita. Nei microcontrollori AVR, tutto l'hardware è configurato utilizzando registri a otto bit. La direzione (input-output) è impostata dai bit dei registri DDRx (dove x è la lettera della porta, nel nostro caso B). Il valore del bit "0" - corrisponde all'ingresso, "1" - all'uscita. Quindi, per utilizzare la gamba PB2 come uscita, dobbiamo impostare il secondo bit del registro DDRB per unità:

DDRB | \u003d (1<

I registri PORTx vengono utilizzati per controllare lo stato dell'uscita. Ad esempio, per spegnere il LED collegato alla gamba PB2 (inviare un livello di segnale basso), dobbiamo scrivere zero sul secondo bit del registro PORTB:

PORTB & \u003d ~ (1<

Per accendere (dare un livello di segnale alto) - di conseguenza, ne scriviamo uno:

PORTB | \u003d (1<

Ora che la porta I / O è configurata, eseguiamo il loop principale in cui invertiremo lo stato dell'uscita PB2 (alternato alto e basso) con un ritardo di 500 ms. Pertanto, il nostro LED lampeggerà a una velocità di 1 volta al secondo.

LA CAMPANA

C'è chi ha letto questa notizia prima di te.
Iscriviti per ricevere gli ultimi articoli.
E-mail
Nome
Cognome
Come vuoi leggere The Bell
Niente spam