- Cos'è un segnale PWM?
- Programmazione PIC per generare PWM su GPIO Pin
- Schema elettrico
- Simulazione
- Configurazione hardware per il controllo del servomotore utilizzando il microcontrollore PIC
La generazione del segnale PWM è uno strumento vitale in ogni arsenale di ingegneri incorporati, sono molto utili per molte applicazioni come il controllo della posizione del servomotore, la commutazione di pochi circuiti integrati elettronici di potenza in convertitori / invertitori e anche per un semplice controllo della luminosità dei LED. Nei microcontrollori PIC i segnali PWM possono essere generati utilizzando i moduli Compare, Capture e PWM (CCP) impostando i registri richiesti, abbiamo già imparato come farlo nel tutorial PIC PWM. Ma c'è un considerevole inconveniente con questo metodo.
Il PIC16F877A può generare segnali PWM solo sui pin RC1 e RC2, se utilizziamo i moduli CCP. Ma potremmo incontrare situazioni in cui abbiamo bisogno di più pin per avere la funzionalità PWM. Ad esempio, nel mio caso, voglio controllare 6 servomotori RC per il mio progetto di braccio robotico per il quale il modulo CCP è senza speranza. In questi scenari possiamo programmare i pin GPIO per produrre segnali PWM utilizzando moduli timer. In questo modo possiamo generare tanti segnali PWM con qualsiasi pin richiesto. Ci sono anche altri hack hardware come l'utilizzo di un IC multiplexer, ma perché investire sull'hardware quando lo stesso può essere ottenuto tramite la programmazione. Quindi in questo tutorial impareremo come convertire un pin GPIO PIC in un pin PWM e per testarlo lo simuleremo su proteus con oscilloscopio digitale e anchecontrollare la posizione del servomotore utilizzando il segnale PWM e variare il suo ciclo di lavoro variando un potenziometro.
Cos'è un segnale PWM?
Prima di entrare nei dettagli, ripassiamo un po 'cosa sono i segnali PWM. Pulse Width Modulation (PWM) è un segnale digitale più comunemente utilizzato nei circuiti di controllo. Questo segnale è impostato alto (5v) e basso (0v) in un tempo e una velocità predefiniti. Il tempo durante il quale il segnale rimane alto è chiamato "tempo di accensione " e il tempo durante il quale il segnale rimane basso è chiamato "tempo di spegnimento". Esistono due parametri importanti per un PWM come discusso di seguito:
Ciclo di lavoro del PWM
La percentuale di tempo in cui il segnale PWM rimane ALTO (tempo di attivazione) viene chiamata duty cycle. Se il segnale è sempre ON è nel duty cycle del 100% e se è sempre spento è nel duty cycle dello 0%.
Ciclo di lavoro = Tempo di accensione / (Tempo di accensione + Tempo di spegnimento)
Nome variabile |
Si riferisce a |
PWM_Frequency |
Frequenza del segnale PWM |
T_TOTAL |
Tempo totale impiegato per un ciclo completo di PWM |
TONNELLATA |
In tempo del segnale PWM |
T_OFF |
Tempo di spegnimento del segnale PWM |
Ciclo di lavoro |
Ciclo di lavoro del segnale PWM |
Quindi ora, facciamo i conti.
Queste sono le formule standard in cui la frequenza è semplicemente il reciproco del tempo. Il valore della frequenza deve essere deciso e impostato dall'utente in base alle proprie esigenze applicative.
T_TOTAL = (1 / PWM_Frequency)
Quando l'utente modifica il valore del Duty cycle, il nostro programma dovrebbe regolare automaticamente il tempo T_ON e il tempo T_OFF in base a quello. Quindi le formule sopra possono essere utilizzate per calcolare T_ON in base al valore di Duty_Cycle e T_TOTAL.
T_ON = (Duty_Cycle * T_TOTAL) / 100
Poiché il tempo totale del segnale PWM per un ciclo completo sarà la somma del tempo di accensione e del tempo di spegnimento. Possiamo calcolare il tempo di spegnimento T_OFF come mostrato sopra.
T_OFF = T_TOTAL - T_ON
Con queste formule in mente possiamo iniziare a programmare il microcontrollore PIC. Il programma coinvolge il modulo timer PIC e il modulo ADC PIC per creare un segnale PWM basato con un ciclo di lavoro variabile in base al valore ADC dal POT. Se sei nuovo nell'uso di questi moduli, ti consigliamo vivamente di leggere il tutorial appropriato facendo clic sui collegamenti ipertestuali.
Programmazione PIC per generare PWM su GPIO Pin
Il programma completo di questo tutorial si trova in fondo al sito come sempre. In questa sezione capiamo come viene effettivamente scritto il programma. Come tutti i programmi, iniziamo impostando i bit di configurazione. Ho usato l'opzione di visualizzazione della memoria per impostarlo per me.
// CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabilitato) #pragma config BOREN = ON // Bit di abilitazione ripristino brown-out (BOR abilitato) #pragma config LVP = OFF // Bit di abilitazione programmazione seriale in-circuit a bassa tensione (alimentazione singola) (RB3 è I / O digitale, HV su MCLR deve essere utilizzato per la programmazione) #pragma config CPD = OFF // Bit di protezione del codice di memoria EEPROM dati (protezione del codice EEPROM dati disattivata) #pragma config WRT = OFF // Bit di abilitazione scrittura memoria programma flash (protezione da scrittura disattivata; tutta la memoria del programma può essere scritta dal controllo EECON) #pragma config CP = OFF // Bit di protezione del codice della memoria del programma Flash (protezione del codice disattivata) // Le istruzioni di configurazione #pragma devono precedere gli include file di progetto. // Usa le enumerazioni del progetto invece di #define per ON e OFF. #includere
Quindi citiamo la frequenza di clock utilizzata nell'hardware, qui il mio hardware utilizza il cristallo da 20 MHz, puoi inserire il valore in base al tuo hardware. Seguito da quello è il valore di frequenza del segnale PWM. Dal momento che il mio scopo qui è controllare un servomotore RC hobby che richiede una frequenza PWM di 50Hz, ho impostato 0,05 KHz come valore di frequenza, puoi anche modificarlo in base ai requisiti dell'applicazione.
#define _XTAL_FREQ 20000000 #define PWM_Frequency 0,05 // in KHz (50Hz)
Ora che abbiamo il valore di Frequenza possiamo calcolare T_TOTALE usando le formule sopra discusse. Il risultato viene diviso per 10 per ottenere il valore del tempo in milli secondi. Nel mio caso il valore di T_TOTAL sarà di 2 milli secondi.
int T_TOTAL = (1 / PWM_Frequency) / 10; // calcola il tempo totale dalla frequenza (in milli sec)) // 2msec
Successivamente, inizializziamo i moduli ADC per leggere la posizione del potenziometro come discusso nel nostro tutorial ADC PIC. Successivamente abbiamo la routine del servizio Interrupt che verrà chiamata ogni volta, il timer va in overflow torneremo su questo più tardi, per ora controlliamo la funzione principale.
All'interno della funzione principale configuriamo il modulo timer. Qui ho configurato il modulo Timer per overflow per ogni 0.1ms. Il valore del tempo può essere calcolato utilizzando le formule seguenti
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) ritardo in sec e Fosc in hz
Nel mio caso per un ritardo di 0.0001 secondi (0.1ms) con prescalar di 64 e Fosc di 20MHz il valore del mio registro (TMR0) dovrebbe essere 248. Quindi la configurazione appare così
/ ***** Configurazione porta per timer ****** / OPTION_REG = 0b00000101; // Timer0 con freq esterna e 64 come prescalar // Abilita anche PULL UP TMR0 = 248; // Carica il valore temporale per 0.0001s; delayValue può essere compreso tra 0 e 256 solo TMR0IE = 1; // Abilita il bit di interrupt del timer nel registro PIE1 GIE = 1; // Abilita interrupt globale PEIE = 1; // Abilita l'interruzione periferica / *********** ______ *********** /
Quindi dobbiamo impostare la configurazione degli ingressi e delle uscite. Qui stiamo usando il pin AN0 per leggere il valore ADC e i pin PORTD per emettere i segnali PWM. Quindi inizializzali come pin di output e rendili bassi usando le seguenti righe di codice.
/ ***** Configurazione porta per I / O ****** / TRISD = 0x00; // Indica all'MCU che tutti i pin sulla PORTA D vengono emessi PORTD = 0x00; // Inizializza tutti i pin su 0 / *********** ______ *********** /
All'interno del ciclo while infinito, dobbiamo calcolare il valore di on time (T_ON) dal duty cycle. Il tempo di accensione e il ciclo di lavoro variano in base alla posizione del POT, quindi lo facciamo ripetutamente all'interno del ciclo while come mostrato di seguito. 0,0976 è il valore che deve essere moltiplicato per 1024 per ottenere 100 e per calcolare T_ON lo abbiamo moltiplicato per 10 per ottenere il valore in milli secondi.
while (1) { POT_val = (ADC_Read (0)); // Leggi il valore di POT usando ADC Duty_cycle = (POT_val * 0.0976); // Mappa da 0 a 1024 a 0 a 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Calcola il tempo utilizzando le formule unità in milli secondi __delay_ms (100); }
Poiché il timer è impostato su overflow per ogni 0,1 ms, la routine di servizio di interruzione del timer ISR verrà richiamata ogni 0,1 ms. All'interno della routine di servizio utilizziamo una variabile chiamata count e la incrementiamo ogni 0.1ms. In questo modo possiamo tenere traccia del tempo. Per ulteriori informazioni sugli interrupt nel microcontrollore PIC, seguire i collegamenti
if (TMR0IF == 1) // Il flag del timer è stato attivato a causa dell'overflow del timer -> impostato su overflow per ogni 0.1ms { TMR0 = 248; // Carica il timer Value TMR0IF = 0; // Cancella il conteggio dei flag di interruzione del timer ++; // Count increments for every 0.1ms -> count / 10 will give value of count in ms }
Finalmente è il momento di attivare il pin GPIO in base al valore di T_ON e T_OFF. Abbiamo la variabile count che tiene traccia del tempo in milli secondi. Quindi usiamo quella variabile per verificare se il tempo è inferiore all'orario , se sì, teniamo acceso il pin GPIO altrimenti lo spegniamo e lo teniamo spento fino all'inizio del nuovo ciclo. Questo può essere fatto confrontandolo con il tempo totale di un ciclo PWM. Il codice per fare lo stesso è mostrato di seguito
if (count <= (T_ON)) // If time less than on time RD1 = 1; // Attiva GPIO altrimenti RD1 = 0; // Altrimenti disattiva GPIO if (count> = (T_TOTAL * 10)) // Tienilo spento finché non inizia un nuovo ciclo count = 0;
Schema elettrico
Lo schema circuitale per la generazione di PWM con pin GPIO del microcontrollore PIC è davvero semplice, basta alimentare il PIC con l'oscillatore e collegare il potenziometro al pin AN0 e il servomotore al pin RD1, possiamo usare il pin GPIO per ottenere il segnale PWM, ho selezionato RD1 appena fuori casuale. Sia il potenziometro che il servomotore sono alimentati da 5V che è regolato dal 7805 come mostrato di seguito nello schema del circuito.
Simulazione
Per simulare il progetto ho utilizzato il mio software proteus. Costruisci il circuito mostrato di seguito e collega il codice alla simulazione ed eseguilo. Dovresti ottenere un segnale PWM sul pin GPIO RD1 come da nostro programma e il ciclo di lavoro del PWM dovrebbe essere controllato in base alla posizione del potenziometro. La GIF sottostante mostra come rispondono il segnale PWM e il servomotore quando il valore ADC viene modificato tramite il potenziometro.
Configurazione hardware per il controllo del servomotore utilizzando il microcontrollore PIC
La mia configurazione hardware completa è mostrata di seguito, per le persone che stanno seguendo i miei tutorial questa scheda dovrebbe sembrare familiare, è la stessa scheda che ho usato in tutti i miei tutorial finora. Puoi fare riferimento al tutorial LED lampeggiante se sei interessato a sapere come lo costruisco. Altrimenti basta seguire lo schema del circuito sopra e tutto dovrebbe funzionare bene.
Carica il programma e varia il potenziometro e dovresti vedere il servo cambiare la posizione in base alla posizione del potenziometro. Il funzionamento completo del progetto è mostrato nel video riportato alla fine di questa pagina. Spero che tu abbia capito il progetto e ti sia piaciuto realizzarlo, se hai dei quesiti sentiti libero di pubblicarli sul forum e farò del mio meglio per risponderti.
Ho intenzione di portare avanti questo progetto aggiungendo opzioni per controllare più servomotori e quindi costruendone un braccio robotico, simile al braccio robotico Arduino che abbiamo già costruito. Quindi fino ad allora ci vediamo !!