pic12f675 potenziometro

PIC12F675 LED PWM POTENZIOMETRO

Le potenzialità software del PIC12F675 ci permettono di sopperire anche alla mancanza del modulo CCP per la generazione del PWM. Non avendo a disposizione quindi un generatore di modulazione di larghezza di impulsi vedremo come generarli tramite il software e applicare questo tipo di modulazione digitale per variare la luminosità di due led, definita da un potenziometro.
Non entro nei dettagli di come funziona il PWM, quali sono i vantaggi, i svantaggi. Potete trovare tutti i dettagli in rete, anche nel link sopra da me inserito. Il mio scopo in questo tutorial è vedere come generare il PWM con il PIC12F675 e regolarlo in base al potenziometro.
In pratica rispetto all’articolo precedente, PIC12F675 INPUT CON POTENZIOMETRO LED LAMPEGGIANTI, dove introducevo l‘input del potenziometro, affronteremo in più la generazione del PWM e sfrutteremo per questo anche l’Interrupt, che servirà per regolare correttamente la temporizzazione dell’impulso.

Circ PIC12F675 potenziometro 2Led

In questo tutorial in particolare non mi sono soffermato sulla frequenza del PWM, non ho quindi calcolato delle frequenze ben stabilite, in quanto quello che mi occorreva in particolare era regolare il Duty Cicle del PWM, per variare la luminosità dei led.

PIC12f675 LED PWM Potenziometro

Il potenziometro collegato alla porta GP0 del PIC12F675 fornisce l’input che regola la luminosità dei Led. Andremo quindi a leggere la porta GP0 e con il supporto del convertitore A/D e otterremo un valore ADC compreso tra 0 e 1024. Dovremo a questo punto adeguare questo valore al dato che ci serve per la generazione del PWM e dato che questo valore deve essere compreso tra 0 e 255, valore che può assumere il duty cicle, saremo costretti a dividere il valore ADC per 4. A questo punto il valore che io ho definito nel codice nella variabile PWMDuty, interagirà con l’Interrupt assegnando il valore della TMR0 attraverso delle istruzioni di controllo if(), creeremo il PWM, mandando in HIGH (1) la porta GP2 e la porta GP4 e inversamente in LOW (0). Ecco ad esempio come risulta l’onda quadra del PWM del PIC12F675 ne l simulatore del programma MPLAB X IDE mentre lo testavo, con Duty di circa il 50%.

ONDA quadra del PWM generato con il pic 12f675

Vediamo quindi il codice in XC8 che ho scritto per questo tutorial.

//*****************************************************************************/
//2 LED con regolazione luminosità in PWM con potenziometro
// www.mdn75.it
//
// modulo: main.c
// autore: MDN75
// data: 25/07/2014 Update: 04/03/2017
// descrizione: 2 led con input
// picmicro: PIC12F675
// clock: interno a 4 MHz
//
//*****************************************************************************/

/******************************************************************************/
/* Files to Include */
/******************************************************************************/


#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */



/******************************************************************************/
/* Configurazione del PIC12F675 per il nostro programma! */
/******************************************************************************/
#pragma config MCLRE = OFF, CP = OFF, CPD = ON, BOREN = ON, WDTE = OFF
#pragma config PWRTE = ON, FOSC = INTRCIO
#define _XTAL_FREQ 4000000

void init_ports(void) /* Funzione di iniziazione delle porte */
{
 TRISIO = 0; /* Imposto tutte le porte in uscita */
 ANSEL = 0; /* Imposto tutte le porte come digitali */
 CMCON = 0x07; //Disable analog comparator
 TRISIO0 = 1; /* Imposto GP0 in input */
 ADCON0 = 0x81; // Abilito A/D Converter
 VRCON = 0x00; /* Imposto voltaggio di riferimento */
 ADCON0 |= 0x00; /* Imposto A/D sulla porta GP0/AN0 */
 OPTION_REG = 1; /* Inizializzo Timer0 */
 T0IE = 1; /* Abilito Timer0 Interrupt */
 GIE = 1 ; /* Abilito Interrupt Globale */
}

/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/
int PWMDuty = 0;
int ADC_value = 0; /* Risultato che ottengo dall'input */
/* i.e. uint8_t <variable_name>; */

/******************************************************************************/
/* Main Program */
/******************************************************************************/

void PWMfunc(void)
{
 /* Verifico che il PMWDuty sia maggiore di 0 e minore o uguale 255*/
 /* Se il valore è zero mando in High i Led*/
 /* Queste verifiche si sono rese necessarie perchè a 0 e a 255 il PWM
 * deve essere costante in LOW o HIGH, ma dalle simulazioni non risultava*/
 if(PWMDuty > 0 && PWMDuty <= 255)
 {
 /* Verifico che il PWM sia in LOW e che il PWMDuty sia minore di 255*/
 /* A 255 il PWM deve essere costantemente in LOW*/
 if(GPIO2 == 0 && PWMDuty < 255)
 {
 GPIO2 = 1; //LED1 HIGH
 GPIO4 = 1; //LED2 HIGH
 TMR0 = PWMDuty; //Setto il timer dell'Interrupt
 
 }
 else /* Quindi se non risponde all' if() mando in LOW */
 {
 GPIO2 = 0; //LED1 LOW
 GPIO4 = 0; //LED2 LOW
 TMR0 = 255 - PWMDuty; //Setto il timer dell'Interrupt

 }
 }
 else /* Quindi se non risponde all' if() mando in HIGH */
 {
 GPIO2 = 1; //LED1 HIGH
 GPIO4 = 1; //LED2 HIGH
 TMR0 = PWMDuty; //Setto il timer dell'Interrupt
 }
}

void interrupt isr(void)
{
 /* Verifico se il timer ha il flag e se l'Interrupt è abilitato */
 /* ogni 255 viene messo il flag al timer */
 if(INTCONbits.T0IF && INTCONbits.T0IE)
 { 
 INTCONbits.T0IF = 0; // elimino il flag del timer
 PWMfunc(); // Richiamo la funzione che genera il PWM
 // Il timer viene settato nella funzione PWMfunc()
 }
}

void main(void)
{
 ADC_value = 0; // inizializzo la variabile ADC_value a 0
 /* Istruzioni che deve eseguire il PIC */
 init_ports(); // Richiamo la funzione per inizializzare le porte

 while(1) // ciclo infinito
 {
 //__delay_us(5); /* Tempo necessario per ottenere un valore corretto della conversione ADC */
 GO_nDONE = 1; // Abilito Go/Done
 while(GO_nDONE); //Aspettiamo finchè la conversione ADC sia finita
 ADC_value = ((ADRESH<<8)+ADRESL); // otteniamo 10 bit ADC value
 if(ADC_value >= 0) // Verifico che ADC_Value non sia 0
 {
 PWMDuty = (ADC_value/4); // Converto il valore ADC per il PWM
 if(PWMDuty > 255) // PWMDuty potrebbe valere 256! valore da non considerare
 {
 PWMDuty = 255; // Se è maggiore lo blocco a 255
 }
 }
 else
 {
 PWMDuty = 0; // Setto il PWM duty a 0
 }
 }
}

Il test di questo codice è stato per me un pochino lungo, in quanto volevo presentare un codice funzionante a pieno e quando mi sono trovato a gestire la funzione della creazione del PWM, no notato che c’erano dei problemi quando il valore del duty era a 0 o a 255: in questa condizione non si ha un onda quadra, ma una linea costante HIGH o LOW.  Qui probabilmente come ho gestito la verifica delle condizioni può risultare un po’ macchinosa, ma il risultato che ottengo è quello voluto e corretto.

Se questo articolo vi è sembrato interessante e vi è stato d’aiuto, condividetelo.
Aiutami a mantenere online il sito con un piccolo aiuto:  paypal.