Sommario:

Microcontrollore AVR. LED lampeggiatore utilizzando il timer. Interruzioni timer. Modalità CTC timer: 6 passaggi
Microcontrollore AVR. LED lampeggiatore utilizzando il timer. Interruzioni timer. Modalità CTC timer: 6 passaggi

Video: Microcontrollore AVR. LED lampeggiatore utilizzando il timer. Interruzioni timer. Modalità CTC timer: 6 passaggi

Video: Microcontrollore AVR. LED lampeggiatore utilizzando il timer. Interruzioni timer. Modalità CTC timer: 6 passaggi
Video: Микроконтроллер AVR. Светодиодная мигалка с использованием таймеров. Таймеры прерывают. Режим таймера CTC. 2024, Novembre
Anonim
Image
Image

Ciao a tutti!

I timer sono un concetto importante nel campo dell'elettronica. Ogni componente elettronico funziona in base ai tempi. Questa base dei tempi aiuta a mantenere tutto il lavoro sincronizzato. Tutti i microcontrollori funzionano a una frequenza di clock predefinita, tutti hanno una disposizione per impostare i timer. AVR si vanta di avere un timer che è molto accurato, preciso e affidabile. Offre un sacco di funzionalità al suo interno, rendendolo così un argomento vasto. La parte migliore è che il timer è totalmente indipendente dalla CPU. Pertanto, funziona parallelamente alla CPU e non vi è alcun intervento della CPU, il che rende il timer abbastanza preciso. In questa sezione spiego i concetti di base dei timer AVR. Sto scrivendo un semplice programma in codice C per controllare il lampeggiatore a LED, utilizzando i timer.

Passaggio 1: descrizione

Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms
Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms

In ATMega328 ci sono tre tipi di timer:

Timer/Counter0 (TC0) - è un modulo timer/contatore a 8 bit per uso generico, con due unità OutputCompare indipendenti e supporto PWM;

Timer/Counter1 (TC1) - L'unità Timer/Counter a 16 bit consente un'accurata temporizzazione dell'esecuzione del programma (gestione degli eventi), generazione di onde e misurazione della temporizzazione del segnale;

Timer/Counter2 (TC2) -è un modulo timer/counter a 8 bit per uso generale, canale, con PWM e funzionamento asincrono;

Fase 2: Problema Dichiarazione 1: Accendiamo il primo LED (verde) ogni 50 Ms

Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms
Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms
Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms
Dichiarazione del problema 1: facciamo lampeggiare il primo LED (verde) ogni 50 Ms

Metodologia:

- utilizzare un prescaler Timer0 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzare un interrupt ogni volta che il Timer0 va in overflow;

Timer0 (8 bit) conta da 0 a 255 dopo di che, vanno in overflow, questo valore cambia ad ogni impulso di clock.

F_CPU=16MHz: Periodo di clock = 1000ms / 16000000Hz = 0.0000625ms

Conteggio timer = (Ritardo richiesto / Periodo di tempo dell'orologio) -1 = (50 ms / 0.0000625 ms) = 799999

L'orologio ha già ticchettato 799999 volte per fornire un ritardo di soli 50 ms!

Possiamo usare la tecnica della divisione di frequenza chiamata prescaling per diminuire il conteggio del timer. L'AVR ci offre i seguenti valori di prescaler tra cui scegliere: 8, 64, 256 e 1024. Vedere la tabella che riassume i risultati dell'utilizzo di diversi prescaler.

Il valore del contatore deve essere sempre un numero intero. Scegliamo un prescaler 256!

Nella maggior parte dei microcontrollori, c'è qualcosa chiamato Interrupt. Questo interrupt può essere attivato ogni volta che vengono soddisfatte determinate condizioni. Ora ogni volta che viene lanciato un interrupt, l'AVR si ferma e salva la sua esecuzione della routine principale, si occupa della chiamata di interrupt (eseguendo una routine speciale, chiamata Interrupt Service Routine, ISR) e una volta terminata, torna al routine principale e continua a eseguirla.

Poiché il ritardo richiesto (50 ms) è maggiore del ritardo massimo possibile: 4, 096 ms = 1000 ms / 62500 Hz * 256, ovviamente il timer andrà in overflow. E ogni volta che il timer va in overflow, viene attivato un interrupt.

Quante volte deve essere attivato l'interrupt?

50ms / 4.096ms = 3125 / 256 = 12.207 Se il timer ha superato 12 volte, sarebbero passati 12 * 4.096ms = 49.152ms. Nella tredicesima iterazione, abbiamo bisogno di un ritardo di 50 ms – 49,152 ms = 0,848 ms.

Ad una frequenza di 62500Hz (prescaler = 256), ogni tick impiega 0,016 ms. Pertanto, per ottenere un ritardo di 0,848 ms, sarebbero necessari 0,848 ms / 0,016 ms = 53 tick. Pertanto, nella tredicesima iterazione, consentiamo al timer di contare solo fino a 53, quindi reimpostarlo.

Inizializza Timer0/Contatore (vedi foto):

TCCR0B |= (1 << CS02) // imposta timer con prescaler = 256 TCNT0 = 0 // inizializza contatore TIMSK0 |= (1 << TOIE0) // abilita l'interrupt di overflow sei() // abilita gli interrupt globali tot_overflow = 0 // inizializza la variabile del contatore di overflow

Fase 3: Problema Dichiarazione 2: Accendiamo il secondo LED (blu) ogni 1s

Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s
Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s
Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s
Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s
Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s
Dichiarazione del problema 2: facciamo lampeggiare il secondo LED (blu) ogni 1s

Metodologia:

- utilizzando un prescaler Timer1 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzando la modalità Clear Timer on Compare (CTC);

- utilizzo di interrupt con modalità CTC;

Timer1 (16 bit) conta da 0 a 65534 dopodiché traboccano. Questo valore cambia ad ogni impulso di clock.

F_CPU=16MHz: Periodo di clock = 1000ms / 16000000Hz = 0.0000625ms Conteggio timer = (Ritardo richiesto / Periodo di clock)-1 = (1000ms / 0.0000625ms) = 15999999

L'orologio ha già ticchettato 15999999 volte per dare un ritardo di 1s!

Possiamo usare la tecnica della divisione di frequenza chiamata prescaling per diminuire il conteggio del timer. L'AVR ci offre i seguenti valori di prescaler tra cui scegliere: 8, 64, 256 e 1024. Vedere la tabella che riassume i risultati dell'utilizzo di diversi prescaler. Il valore del contatore deve essere sempre un numero intero. Scegliamo un prescaler 256!

In modalità Clear timer on Compare(CTC), i registri OCR1A o ICR1 vengono utilizzati per manipolare la risoluzione del contatore. In modalità CTC il contatore viene azzerato quando il valore del contatore (TCNT1) corrisponde a OCR1A o ICR1. L'OCR1A o ICR1 definiscono il valore massimo del contatore, quindi anche la sua risoluzione. Questa modalità permette un maggiore controllo della frequenza di uscita del confronto match. Inoltre semplifica l'operazione di conteggio degli eventi esterni. Dobbiamo dire all'AVR di resettare il Timer1/Contatore non appena il suo valore raggiunge il valore 62500, così da ottenere un ritardo di 1s.

Inizializza Timer1/Contatore (vedi foto):

TCCR1B |= (1 << WGM12)|(1 << CS12) // imposta timer con prescaler = 256 e modalità CTC TCNT1 = 0 // inizializza contatore TIMSK1 |= (1 << OCIE1A) // abilita l'interrupt di confronto OCR1A = 62500 // inizializza il valore di confronto

Passaggio 4: Dichiarazione del problema 3: Accendiamo il terzo LED (rosso) ogni 16 ms

Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms
Dichiarazione del problema 3: facciamo lampeggiare il terzo LED (rosso) ogni 16 ms

Metodologia:

- utilizzando un prescaler Timer2 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzando la modalità Clear Timer on Compare (CTC);

- utilizzando la modalità CTC hardware senza interruzioni;

Timer2 (8 bit) conta da 0 a 255 dopodiché traboccano. Questo valore cambia ad ogni impulso di clock.

F_CPU=16MHz: Periodo di clock = 1000ms / 16000000Hz = 0.0000625ms

Conteggio timer = (Ritardo richiesto / Periodo di tempo dell'orologio) -1 = (16 ms / 0.0000625 ms) = 255999

L'orologio ha già ticchettato 255999 volte per fornire un ritardo di 16 ms!

Vedere la tabella che riassume i risultati dell'utilizzo di diversi prescaler. Il valore del contatore deve essere sempre un numero intero. Scegliamo un prescaler 1024!

In modalità CTC il contatore viene azzerato quando il valore del contatore (TCNT2) corrisponde a OCR2A o ICR2. Il pin PB3 è anche il pin Output Compare di TIMER2 - OC2A (vedi diagramma).

Registro di controllo timer/contatore2 A – TCCR2A Bit 7:6 – COM2A1:0 – Modalità di uscita di confronto per l'unità di confronto A. Poiché è necessario attivare il LED, scegliamo l'opzione: Attiva/disattiva OC2A su confronto di confronto Ogni volta che si verifica una corrispondenza di confronto, il Il pin OC2A viene commutato automaticamente. Non è necessario controllare alcun bit di flag, non è necessario occuparsi di eventuali interruzioni.

Inizializza Timer2/Contatore

TCCR2A |= (1 << COM2A0)|(1 << WGM21) // imposta il pin del timer OC2A in modalità toggle e modalità CTC TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20) // imposta timer con prescaler = 1024 TCNT2 = 0 // inizializza contatore OCR2A = 250 // inizializza confronta valore

Passaggio 5: scrittura del codice per un programma in C. Caricamento del file HEX nella memoria flash del microcontrollore

Scrittura di codice per un programma in C. Caricamento di file HEX nella memoria flash del microcontrollore
Scrittura di codice per un programma in C. Caricamento di file HEX nella memoria flash del microcontrollore
Scrittura di codice per un programma in C. Caricamento di file HEX nella memoria flash del microcontrollore
Scrittura di codice per un programma in C. Caricamento di file HEX nella memoria flash del microcontrollore

Scrivere e costruire l'applicazione del microcontrollore AVR in codice C utilizzando la piattaforma di sviluppo integrata - Atmel Studio.

F_CPU definisce la frequenza di clock in Hertz ed è comune nei programmi che utilizzano la libreria avr-libc. In questo caso viene utilizzato dalle routine di ritardo per determinare come calcolare i ritardi.

#ifndef F_CPU

#define F_CPU 16000000UL // indica la frequenza del cristallo del controller (16 MHz AVR ATMega328P) #endif

#include // header per abilitare il controllo del flusso di dati sui pin. Definisce pin, porte, ecc.

Il primo file di inclusione fa parte di avr-libc e verrà utilizzato praticamente in qualsiasi progetto AVR su cui lavori. io.h determinerà la CPU che stai utilizzando (motivo per cui specifichi la parte durante la compilazione) e a sua volta includerà l'intestazione di definizione IO appropriata per il chip che stiamo utilizzando. Definisce semplicemente le costanti per tutti i tuoi pin, porte, registri speciali, ecc.

#include // header per abilitare l'interrupt

volatile uint8_t tot_overflow; // variabile globale per contare il numero di overflow

Metodologia della dichiarazione del problema: il LED lampeggia prima (verde) ogni 50 ms

- utilizzare un prescaler Timer0 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzare un interrupt ogni volta che il Timer0 va in overflow;

void timer0_init() // inizializza timer0, interrupt e variabile

{TCCR0B |= (1 << CS02); // imposta il timer con prescaler = 256 TCNT0 = 0; // inizializza il contatore TIMSK0 |= (1 << TOIE0); // abilita l'overflow interrompe sei(); // abilita gli interrupt globali tot_overflow = 0; // inizializza la variabile del contatore di overflow }

Metodologia della dichiarazione del problema: lampeggia il secondo LED (blu) ogni 1s

- utilizzando un prescaler Timer1 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzando la modalità Clear Timer on Compare (CTC);

- utilizzo di interrupt con modalità CTC;

void timer1_init() // inizializza timer1, interrupt e variabile{ TCCR1B |= (1 << WGM12)|(1 << CS12); // imposta timer con prescaler = 256 e modalità CTC TCNT1 = 0; // inizializza il contatore OCR1A = 62500; // inizializza il valore di confronto TIMSK1 |= (1 << OCIE1A); // abilita l'interruzione di confronto}

Metodologia della dichiarazione del problema: lampeggia il terzo LED (rosso) ogni 16 ms

- utilizzando un prescaler Timer2 per ridurre un segnale elettrico ad alta frequenza ad una frequenza inferiore per divisione intera;

- utilizzando la modalità Clear Timer on Compare (CTC);

- utilizzando la modalità CTC hardware senza interruzioni;

void timer2_init() // inizializza timer2{ TCCR2A |= (1 << COM2A0)|(1 << WGM21); // imposta il pin del timer OC2A in modalità toggle e modalità CTC TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20); // imposta timer con prescaler = 1024 TCNT2 = 0; // inizializza il contatore OCR2A = 250; // inizializza il valore di confronto }

Routine di servizio di interruzione dell'overflow di TIMER0 chiamata ogni volta che TCNT0 va in overflow:

ISR(TIMER0_OVF_vect)

{ tot_overflow++; // tiene traccia del numero di overflow }

Questo ISR viene attivato ogni volta che si verifica una corrispondenza, quindi, attiva/disattiva il led qui stesso:

ISR (TIMER1_COMPA_vect){ PORTC ^= (1 << 1); // attiva/disattiva il led qui}

int main (vuoto)

{ DDRB |= (1 << 0); // collega 1 led (verde) al pin PB0 DDRC |= (1 << 1); // collega 2 led (blu) al pin PC1 DDRB |= (1 << 3); // collega 3 led (rosso) al pin PB3 (OC2A) timer0_init(); // inizializza timer0 timer1_init(); // inizializza timer1 timer2_init(); // inizializza timer2 while(1) // loop per sempre {

Se il Timer0 ha superato 12 volte, sarebbero passati 12 * 4.096 ms = 49.152 ms. Nella tredicesima iterazione, abbiamo bisogno di un ritardo di 50 ms – 49,152 ms = 0,848 ms. Pertanto, nella tredicesima iterazione, consentiamo al timer di contare solo fino a 53, quindi reimpostarlo.

if (tot_overflow >= 12) // controlla se no. di overflow = 12 NOTA: viene utilizzato '>='

{ if (TCNT0 >= 53) // controlla se il conteggio del timer raggiunge 53 { PORTB ^= (1 << 0); // commuta il led TCNT0 = 0; // resetta il contatore tot_overflow = 0; // resetta il contatore di overflow } } } }

Caricamento del file HEX nella memoria flash del microcontrollore:

digitare nella finestra del prompt di DOS il comando:

avrdude –c [nome del programmatore] –p m328p –u –U flash:w:[nome del tuo file esadecimale]Nel mio caso è: avrdude –c ISPProgv1 –p m328p –u –U flash:w:Timers.hex

Questo comando scrive il file esadecimale nella memoria del microcontrollore. Guarda il video con una descrizione dettagliata della masterizzazione della memoria flash del microcontrollore:

Masterizzazione della memoria flash del microcontrollore…

Ok! Ora, il microcontrollore funziona secondo le istruzioni del nostro programma. Controlliamolo!

Passaggio 6: creazione del circuito elettrico

Realizzazione del circuito elettrico
Realizzazione del circuito elettrico
Realizzazione del circuito elettrico
Realizzazione del circuito elettrico
Realizzazione del circuito elettrico
Realizzazione del circuito elettrico

Collegare i componenti secondo il diagramma schematico.

Consigliato: