Generazione dei segnali PWM

Questo articolo mostra come realizzare un PWM software sfruttando alcune tecniche di programmazione C e le risorse dei microcontrollori PIC mid-range.

La maggior parte dei microcontrollori di fascia media dispone di canali PWM di tipo hardware. Va, però, detto che non tutti i micro sono dotati di PWM hardware e, se presenti, si limita a uno o due canali. Nei casi in cui il PWM non sia disponibile oppure si vogliano generare segnali PWM su diversi pin, è necessario ricorrere ad un PWM software. Questo articolo mostra, quindi, come realizzare un PWM software sfruttando alcune tecniche di programmazione e le risorse del microcontrollore. Gli esempi sono riferiti a microcontrollori PIC e scritti in C. In Figura 1 è mostrato lo schema con cui è possibile realizzare il PWM software. Alla porta PORTB del PIC16F819 è connesso un LED, con interposta la resistenza limitatrice di corrente. La scelta del PIC non è vincolante, ma il PIC16F819 offre spunti interessanti; innanzitutto è dotato di oscillatore interno, per cui non è necessario il quarzo esterno; inoltre, è un microcontrollore FLASH programmabile in-circuit con ICD2. Per la realizzazione del PWM software sono necessari i componenti indicati in Tabella 1.

Tabella 1: i componenti necessari per la realizzazione del PWM software.

Tabella 1: I componenti necessari per la realizzazione del PWM software

Il progetto è realizzabile anche con altri PIC (si veda il paragrafo più avanti) come il glorioso (ma obsoleto) PIC16F84A o il più recente PIC16F628A ma anche il PIC16F876A. La criticità del circuito è tale per cui il montaggio può avvenire senza problemi anche su breadboard oppure su una basetta mille fori. Trattandosi di un esperimento, non si è riportato lo stadio di alimentazione: va da sé che il PIC va alimentato con tensione 5 V stabilizzata che può essere fornita da un alimentatore da laboratorio oppure, in alternativa, si può optare per uno stadio di alimentazione classico con LM7805.

Figura 1: schema elettrico per la realizzazione del PWM software.

Figura 1: Schema elettrico per la realizzazione del PWM software

IL FIRMWARE DEL PWM

Per chi non sapesse cos’è un segnale modulato in larghezza di impulso, rimando all’approfondimento presente in queste pagine. Il primo codice da analizzare, denominato PWM_UN_PIN, è quello che genera il PWM su un solo pin del PIC; è stato preso in considerazione il pin RB0 ma è facile sceglierne un altro al suo posto. La tecnica adottata per la generazione del PWM si affida al TIMER0 del PIC ed al suo overflow che va a scatenare l’interrupt. La funzione ConfiguraPIC() si preoccupa quindi di abilitare l’oscillatore interno e di configurare il TIMER0 a 8 bit e con prescaler 1:2. Questo significa che, sfruttando l’oscillatore interno a 8 MHz, si ha un overflow del timer ogni 256 μs. Una volta scatenato l’interrupt, la routine che lo gestisce si preoccupa di riattivare il TIMER0 precaricandolo con un valore compreso tra 0 e 255; la scelta del numero è stabilita dal valore che la variabile chPwmOn aveva assunto al ciclo precedente, 1 o 0, indicando cioè che il PWM era a livello logico alto oppure basso.

Ecco di seguito un esempio: si immagini che uchDuty valga 100 e che il PWM sia a livello alto, (ossia chPwmOn vale 1). Giunto l’interrupt, chPwmOn viene posta a 0 e il registro del timer viene caricato con un valore in funzione della variabile uchDuty che, in questo esempio, vale 100. Il timer, quindi, comincia a contare non da 0 ma da 100 e quindi giunge ad overflow in un tempo inferiore rispetto a quando lo si carichi con 0. All’overflow si scatena un altro interrupt e questa volta la routine verifica che chPwmOn vale 0 (è stato posto a 0 nell’interrupt precedente), pertanto pone chPwmOn a 1 e precarica il registro del timer con un valore pari a 155, ottenuto dalla differenza 255-100. A questo punto è sufficiente andare a testare il valore di chPwmOn per stabilire se un pin va posto a 1 o a 0; nel main() si richiama la funzione PWM() che non fa altro che porre il pin RB0 ad assumere lo stesso valore di chPwmOn. Il Listato 1 mostra il cuore del codice scritto per la realizzazione del PWM software.

void interrupt (void)
{
 if (intcon.TMR0IF) // Interrupt su overflow TIMER 0
 {
                             intcon.TMR0IF=0;
                             if (chPwmOn)
                             {
                               chPwmOn=0;
                               tmr0=uchDuty;
                               } else {
                               chPwmOn=1;
                               tmr0=255-uchDuty;
                              }
 }
}
void main()
{
 ConfiguraPic();
// Abilitazione interrupt
 intcon=0xA0;
// Ciclo continuo
 while(1)
 {
                                 PWM();
 }
}
void PWM (void)
{
 if (chPwmOn)
 {
                                 set_bit(portb,0);
 } else {
                                 clear_bit(portb,0);
 }
}
Listato 1

VARIAZIONE DEL DUTY-CYCLE

Così come è stato proposto, il codice PWM_UN_PIN genera un PWM a frequenza fissa e con duty-cycle fisso. Come fare quindi per la variazione del duty-cycle? Proprio per il ruolo che riveste, il duty-cycle è la vera e propria variabile di comando del PWM, quello che determina l’effetto finale del PWM sui circuiti hardware. La variazione del PWM è quindi generalmente demandata ad algoritmi che, in base a considerazioni proprie, determinano il valore che il duty-cycle deve assumere. Per il progetto didattico che si propone in queste pagine, invece, può essere interessante variare manualmente il duty-cycle, senza dover necessariamente sottostare a qualche algoritmo.

Si osservi che il PIC che è stato scelto per l’esempio dispone di ingressi analogici; configurando la porta RA0 come ingresso AN0, si può pensare di collegare a questo pin un potenziometro, la cui variazione sarà nient’altro che il valore di duty-cycle. In Figura 2 è illustrato lo schema elettrico con l’aggiunta di un potenziometro (o trimmer) da 10 k, connesso al pin AN0. Il codice che gestisce l’ingresso analogico è PWM_UN_PIN_POTI; la funzione ConfiguraPIC() si preoccupa quindi di configurare anche il modulo di conversione analogico/digitale mentre la gestione del convertitore avviene invece in interrupt. Il modulo ADC converte la tensione letta su AN0 in un valore a 10 bit che viene poi ridotto a 8 bit per agevolare l’associazione tra il valore convertito e il duty-cycle.

Figura 2: aggiunta del potenziometro per la variazione del duty-cycle.

Figura 2: Aggiunta del potenziometro per la variazione del duty-cycle

LE MACRO

Il codice C utilizza due macro: set_bit() e clear_bit(). Queste macro, già disponibili per BoostC ma non per MikroC, permettono l’accesso ad un bit di un byte portandolo rispettivamente al valore logico 1 e 0. Tali macro sono state definite nel file di include di entrambi i progetti.

COME FARE CON ALTRI PIC?

L’adattamento del progetto ad altri PIC, come il PIC16F84A, il PIC16F876A o il PIC16F628A, non è cosa impossibile ma è necessario prestare attenzione ad alcuni punti chiave da non sottovalutare, pena il malfunzionamento del circuito.

ADATTAMENTO DELLO SCHEMA ELETTRICO

Alcuni PIC, come il PIC16F84A o il PIC16F876A necessitano di un oscillatore esterno; il quarzo va connesso come da datasheet, ai pin OSC1 e OSC2 (un esempio è mostrato in Figura 3). Va altresì sottolineato come alcuni PIC non dispongano di ingresso analogico; per questi tutti gli aspetti legati alla conversione A/D vanno esclusi, a partire dal potenziometro connesso ad AN0. In mancanza del convertitore A/D può essere utile installare un paio di pulsanti deputati all’incremento e al decremento della variabile duty-cycle.

Figura 3: esempio di collegamente dell’escillatore esterno.

Figura 3: Esempio di collegamenti dell’oscillatore esterno

ADATTAMENTO DEL FIRMWARE

Ogni PIC dispone di un set di configuration bit; questi permettono di fornire una configurazione hardware per diversi aspetti: dal tipo di oscillatore, se è interno oppure esterno, se si vuole utilizzare il Watch Dog Timer, eccetera. Benché esista una certa familiarità tra PIC, in funzione del dispositivo scelto è necessario stabilire il corretto set di configuration bit. Anche in questo caso torna utile sfogliare il datasheet. Nel progetto originale per PIC16F819 si è utilizzato l’oscillatore interno a 8 MHz; dovendo adattare il progetto ad altri PIC, oltre all’apposizione di un (eventuale) quarzo esterno, se si opta per un oscillatore a frequenza diversa, questo va indicato sia in MikroC sia in BoostC. Si tenga conto del fatto che la frequenza Fosc è tale da determinare la frequenza dell’interrupt di TIMER0. Così, se per esempio si adottasse un quarzo esterno da 4 MHz, la risposta all’interrupt avverrebbe ogni 512 μs e non ogni 256 μs. Avendo optato per la scrittura del firmware in linguaggio C si ha la quasi totale portabilità su tutti i PIC della famiglia mid-range; è, infatti, il compilatore ad occuparsi di molte delle attività che invece andrebbero dettagliate, se si scrivesse in assembly.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend