Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

6
voti

Accendiamole con un PIC

Premessa

Il forum di Electroportal ospita da qualche tempo uno spazio dedicato ai microcontrollori PIC prodotti da Microchip Technology. In questo ambito, è aperta una sezione specifica sul software per PIC che pian piano prende forma con esempi di codice. Con alcuni appuntamenti di questa rubrica, porto all'attenzione degli utenti cosa si può fare con i microcontrollori ed in particolare con i PIC che, per costo e diffusione, hanno una popolarità molto elevata.

Le luci di cortesia e il PWM software

Credo che dire che cosa sia la modulazione a larghezza d'impulso (PWM, Pulse Width Modulation) sia superfluo, in questa sede. Vorrei invece mostrare un'applicazione che sfrutta il PWM: le luci di cortesia per auto.

Benché la maggior parte delle autovetture di oggi dispongano già di luci di cortesia, ritengo questo un buon esercizio per partire. Innanzitutto, cosa sono le luci di cortesia? Non sono altro che un modo gentile per accogliere il conducente ed i passeggeri a bordo. Ecco come funzionano: all'apertura delle portiere, le luci interne si accendono e restano accese fintanto che le portiere restano aperte. Non appena l'ultima portiera si chiude, le luci restano accese per un certo tempo, per permettere al conducente di sistemarsi sul sedile e di poter individuare facilmente il punto di innesto della chiave di avviamento. Intanto il timer che mantiene accesa la luce interna va ad esaurirsi; quando scade,  l'intensità luminosa della luce si abbassa gradualmente, sino a spegnersi.

A livello concettuale, propongo lo schema di figura 1 che rappresenta il cuore del progetto;

Casella di testo:  
fig. 1: Schema

un microcontrollore PIC12F508, alimentato a 5V,  viene collegato ad un interruttore di una portiera (S1) ed alla lampadina (PWM_OUT). Ovviamente, non è possibile eseguire un collegamento diretto né dell'interruttore sulla portiera né alla lampadina! Come detto lo schema è concettuale. Per provare il concetto, è però possibile collegare un semplice interruttore al PIC ed un LED con una resistenza di limitazione della corrente. In figura 2 è mostrata la fotografia del prototipo impiegato per le prove e le misure illustrate nel seguito.

Casella di testo:  
fig. 2: prototipo

La macchina a stati

Il problema proposto si presta bene ad essere analizzato come una macchina a stati. Lo stato da tenere sotto controllo è quello della portiera:

  1. portiera chiusa;
  2. portiera aperta;
  3. portiera appena richiusa;
  4. portiera chiusa con luce in evanescenza.

In figura 3 sono riportati gli stati e le condizioni di commutazione tra stato e stato e le condizioni di stazionamento in ciascuno stato.

Casella di testo:  
fig. 3: diagrammi di stato

Gli stati sono rappresentati dai cerchi, le condizioni di commutazione tra uno stato e l'altro sono rappresentate dalle frecce nere, mentre le frecce rosse indicano le condizioni di permanenza in uno stato. Per poter analizzare in modo semplice il problema, consiglio di partire dalla condizione di portiera chiusa.

Il codice del firmware

Recentemente, Microchip ha messo a disposizione nel suo ambiente MPLAB un compilatore C gratuito e senza limitazioni sviluppato da una società terza: CCS C Compiler. Questo compilatore C è sì gratuito e senza limitazioni in termini di ampiezza di codice, ma è limitato ad un certo numero di microcontrollori ed in particolar modo a quelli definiti a core 12-bit, come appunto il PIC12F508. Ecco quindi che propongo nel seguito i due file scritti in C che vanno compilati con CCS; questi vanno inseriti in un progetto di MPLAB come illustrato in figura 4.

 

Consiglio di impiegare lo strumento PROJECT WIZARD che aiuta a preparare l'albero di progetto ed a scegliere il compilatore C di CCS.

#include "C:\Progetti\Cortesia508\Cortesia508.h"
/*
CORTESIA508.C
Macchina a quattro stati:
STATO 0: portiera CHIUSA
STATO 1: portiera APERTA
STATO 2: portiera APPENA CHIUSA
STATO 3: portiera con LUCE EVANESCENTE
Per queste condizioni sul micro della portiera, la luce è:
portiera CHIUSA: luce OFF
portiera APERTA: luce ON
portiera APPENA CHIUSA: luce ON per 5s
portiera con LUCE EVANESCENTE: PWM luce verso OFF
*/
#define PORTA_CHIUSA 0
#define PORTA_APERTA 1
#define PORTA_RICHIUSA 2
#define LUCE_EVANESCENTE 3
#define OFF 0
#define ON 1
// Variabili globali
unsigned char duty,k;
char M_STATUS; // Indica lo stato della macchina
int16 delay_counter;
struct t_GPIO {
            int GP0:1;                    // I
            int GP1:1;                    // I
            int PORTIERA:1; // I
            int GP3:1;                    // I
            int GP4:1;                    // I
            int LUCE:1;     // O
} GPIO;
#byte GPIO = 6
// Dichiarazione delle funzioni
BOOLEAN PortieraAperta (void);
BOOLEAN PortieraChiusa (void);
void PWM (void);
void main (void)
{
            set_tris_b(0x1F);
// Impostazioni del TIMER 0:
// Va in overflow dopo 0.016384 secondi (16.384 ms)
// T_ovf= 1/(1000000/256/64)
            setup_timer_0(RTCC_DIV_64);
            M_STATUS=0;
            while(1)
            {
                        switch (M_STATUS)
                        {
                                   case PORTA_CHIUSA:
                                               GPIO.LUCE=OFF;
                                               if (PortieraAperta())
                                               {
                                                           M_STATUS=PORTA_APERTA;
                                               }
                                   break;
                                   case PORTA_APERTA:
                                               GPIO.LUCE=ON;
                                               if (PortieraChiusa())
                                               {
                                                           M_STATUS=PORTA_RICHIUSA;
                                                           delay_counter=0;
                                                           k=0;
                                               }
                                   break;
                                   case PORTA_RICHIUSA:
                                               if (delay_counter<3000) {
                                                           if (PortieraAperta())
                                                           {
                                                                       delay_counter=0;
                                                                       M_STATUS=PORTA_APERTA;
                                                                       break;
                                                           }
                                                           if (get_timer0()>=250) {
                                                                       delay_counter++;
                                                           }
                                               } else {
                                                           duty=0xFF;
                                                           M_STATUS=LUCE_EVANESCENTE;
                                               }
                                   break;
                                   case LUCE_EVANESCENTE:
                                               if (get_timer0()>=250)
                                               {
                                                           set_timer0(0);
                                                           duty--;
                                               }
                                               if (duty==0)
                                               {
                                                           M_STATUS=PORTA_CHIUSA;
                                                           break;
                                               }
                                               if (PortieraAperta())
                                               {
// Se viene riaperta la porta, lo stato torna a PORTA_APERTA
                                                           delay_counter=0;
                                                           M_STATUS=PORTA_APERTA;
                                                           break;
                                               }
                                               PWM();
                                   break;
                        }
            }
}
BOOLEAN PortieraAperta (void)
{
            if (GPIO.PORTIERA==1)
            {
                        delay_ms(5);
                        if (GPIO.PORTIERA==1)
                        {
                                   return TRUE;
                        }
            } else {
                        return FALSE;
            }
}
BOOLEAN PortieraChiusa (void)
{
            if (GPIO.PORTIERA==0)
            {
                        delay_ms(5);
                        if (GPIO.PORTIERA==0)
                        {
                                   return TRUE;
                        }
            } else {
                        return FALSE;
            }
}
void PWM (void)
{
            if (k<=duty)
            {
                        GPIO.LUCE = ON;
            } else {
                        GPIO.LUCE = OFF;
            }

            k++;

}


// CORTESIA508.H
#include "C:\PROGRAMMI\MICROCHIP\THIRD PARTY\PICC\devices\12f508.h"

#FUSES NOWDT,INTRC,MCLR,NOPROTECT

#use delay(clock=4000000) // Oscillatore interno a 4MHz

La routine più interessante di questo piccolo progetto è quella del PWM software, in quanto non è disponibile il modulo PWM hardware (come per altri PIC); il PIC12F508 dispone di un timer (TMR0) ma non di interrupt sull'overflow di quel timer, quindi la sfida è ardua, ma interessante. Come fare, allora, per generare il PWM? Fissata la frequenza del PWM, si considera un periodo; questo periodo lo si spezzetta in una serie di sottointervalli (per questo esempio ho scelto 255). Quando il timer si esaurisce,  si confronta il valore di un contatore (che va da 0 a 255, il numero dei sottointervalli) con il duty-cycle previsto. Se k (contatore dei sottointervalli) è minore o uguale del duty-cycle, la luce viene accesa; viceversa, la si spegne. Il timer viene riavviato, e si decrementa il valore del duty-cycle.

Le misure

Nelle figure che seguono, riporto le misure eseguite con l'oscilloscopio: stato di porta richiusa e avvio del PWM,


la durata del PWM con le sue "sfumature"


ed infine la frequenza del PWM.

Per concludere

Questo esercizio di elettronica facilmente si risolveva con un la carica di un condensatore la cui scarica sarebbe servita a pilotare la base di un transistor deputato a pilotare la lampada... Non era questo lo scopo della lezione.

Nei prossimi appuntamenti mostrerò come si possa realizzare il medesimo esercizio con un PIC dotato di interrupt sul timer.

Riferimenti

Tutto ciò che riguarda i PIC va ricercato presso la Casa costruttrice: http://www.microchip.com

Per maggiori informazioni sul compilatore C di CCS: http://www.ccsinfo.com

1

Commenti e note

Inserisci un commento

di vsc,

Ottimo esempio di programmazione pratica!!

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.