Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

[PIC18] Led e PWM: facile, veloce e senza timers.

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

3
voti

[1] [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTardoFreak » 23 lug 2010, 16:14

Un saluto a tutti gli utenti.
Mio figlio frequenta l' universita' e studia progetto grafico e virtuale (traditore :x ) e mi ha chiesto di realizzargli un circuito per pilotare tre gruppi di LED (rosso, verde e blu) per creare un effetto luminoso di colore. In pratica deve poter scorrere i colori dello spettro. Ho dunque realizzato il nocciolo del programma implementandolo su un PIC18F14K22. Perche' questa MPU? beh, per nessun motivo in particolare. Ne ho preso uno dai cassettini e mi sono detto "vabbe', usiamo questo". :mrgreen:
Ho cercato quindi di realizzare un programma piu' semplice possibile per gestire un certo numero di LEDs (io ne ho usati 3 ma potrebbero essere molti di piu'). La semplicita' e' un requisito necessario poiche dovra' poi spiegare il programma all' esame. Non e' digiuno di programmazione ne di elettronica perche' e' un perito elettronico che poi (traditore :x ) ha scelto una strada diversa.
Quindi non ho usato timers ed ho realizzato il classico loop infinito sperando che il micro fosse abbastanza veloce. E devo dire che lo e' alla grande! E' andato oltre le mie aspettative. Il programma e' questo:
Codice: Seleziona tutto
// Definizione dei bit di configurazione della MPU
#pragma config FOSC     = IRC     // Internal RC oscillator
#pragma config PLLEN    = ON      // 4 X PLL Enable bit
#pragma config PCLKEN   = OFF     // Primary Clock Enable Bit
#pragma config FCMEN    = OFF     // Fail-Safe Clock Monitor Enable bit   
#pragma config IESO     = OFF     // Internal/External Oscillator Switchover bit
#pragma config PWRTEN   = ON      // Power-up Timer Enable bit
#pragma config BOREN    = ON      // Brown-out Reset Enable bits
#pragma config BORV     = 19      // Brown-out Voltage (1,9V)
#pragma config WDTEN    = OFF     // Watchdog Timer Enable bit
#pragma config WDTPS    = 32768   // Watchdog Timer Postscale Select bits
#pragma config MCLRE    = ON      // MCLR Pin Enable bit
#pragma config HFOFST   = OFF     // HFINTOSC Fast Start-up bit (The system clock is held off until the HFINTOSC is stable)
#pragma config STVREN   = ON      // Stack Full/Underflow Reset Enable bit
#pragma config LVP      = OFF     // Single-Supply ICSP Enable bit
#pragma config XINST    = OFF     // Extended Instruction Set Enable bit 
#pragma config CP0      = OFF     // Code Protection bit
#pragma config CP1      = OFF     // Code Protection bit
#pragma config CPB      = OFF     // Boot Block Code Protection bit
#pragma config WRT0     = OFF     // Write Protection bit
#pragma config WRT1     = OFF     // Write Protection bit
#pragma config WRTB     = OFF     // Boot Block Write Protection bit
#pragma config WRTC     = OFF     // Configuration Register Write Protection bit
#pragma config EBTR0    = OFF     // Table Read Protection bit
#pragma config EBTR1    = OFF     // Table Read Protection bit
#pragma config EBTRB    = OFF     // Boot Block Table Read Protection bit

// file di definizioni della MPU
#include <p18f14k22.h>

// Defines porte di uscita per i LEDs
// LED rosso
#define LED_R LATCbits.LATC0
#define LED_R_DIR TRISCbits.TRISC0
// LED verde
#define LED_G LATCbits.LATC1
#define LED_G_DIR TRISCbits.TRISC1
// LED blu
#define LED_B LATCbits.LATC2
#define LED_B_DIR TRISCbits.TRISC2

unsigned char pos_pwm;
unsigned char liv_R,liv_G,liv_B;  // livelli da 0 a 255 dei tre colori
unsigned short pos_spettro;       // posizione da 0 a 767 nello spettro
char base_tempi;                  // bit attivato al completamento di un' onda


/******************************************************************************/
/*  set_spettro                                                               */
/*      calcola la configurazione dei tre colori in base alla posizione nello */
/*      spettro                                                               */
/******************************************************************************/
void set_spettro(void)
{
  short p;
 
  p = pos_spettro;
  if (p<256)
  {
    liv_R = 255 - p;
    liv_G = p;
    liv_B = 0;
  }
  else if (p<512)
  {
    p &= 0xff;
    liv_R = 0;
    liv_G = 255 - p;
    liv_B = p;
  }
  else
  {
    p &= 0xff;
    liv_R = p;
    liv_G = 0;
    liv_B = 255 - p;
  }
}

/******************************************************************************/
/*  inc_spettro                                                               */
/*      incrementa la posizione dello spettro in modo circolare               */
/******************************************************************************/
void inc_spettro(void)
{
  if (pos_spettro != 767) pos_spettro++; else pos_spettro = 0;
}

/******************************************************************************/
/*  inc_spettro                                                               */
/*      decrementa la posizione dello spettro in modo circolare               */
/******************************************************************************/
void dec_spettro(void)
{
  if (pos_spettro) pos_spettro--; else pos_spettro = 767;
}

/******************************************************************************/
/*  main function                                                             */
/*                                                                            */
/******************************************************************************/
void main (void)
{
 
  // inizializza le uscite dei LEDS
  LED_R = 0;
  LED_R_DIR = 0;
  LED_G = 0;
  LED_G_DIR = 0;
  LED_B = 0;
  LED_B_DIR = 0;
  OSCCON |= 0x70; // seleziona clock a 16 MHz
 
  // prova
  liv_R = 255;
  liv_G = 255;
  liv_B = 255;
 
  base_tempi = 0; 
  pos_spettro = 0;
 
  while(1)
  {
   
    // gestione forme d' onda PWM
    if (pos_pwm < liv_R) LED_R = 1; else LED_R = 0;
    if (pos_pwm < liv_G) LED_G = 1; else LED_G = 0;
    if (pos_pwm < liv_B) LED_B = 1; else LED_B = 0;
    pos_pwm++;
    if (!pos_pwm)
    {
      // accensione impulso di base tempi al completamento dell' onda
      base_tempi = 1;;
    }
   
   
    // programma di dissolvenza incrociata
    if (base_tempi)
    {
      base_tempi = 0;
      inc_spettro();
      set_spettro();
    }
  }
 
}


La regolazione PWM si ottiene tramite la variabile pos_pwm che va da 0 a 255. Il suo valore viene confrontato con i livelli di luminosita' dei 3 canali per avere la parte ON ed OFF del segnale di pilotaggio. Se il valore di pos_pwm e' piu' basso di quello del canale l' uscita e' ad 1 logico, se e' piu' altro l' uscita e' a 0. Semplicissimo direi. :wink:
Eventuali altre elaborazioni che dovro' fare (come quella di far scorrere lo spettro dei colori, per prova) va inserita dopo le linee di codice del PWM ricordandosi che e' un loop infinito e che deve funzionare veloce. Sono quindi da evitare chiamate a routines di ritardo. La cosa interessante e' che la frequenza dell cilco PWM e' piu' di 2500 Hz :shock:
Questo vuol dire che di canali ce ne possono stare un' infinita'. Basta infatti che la frequenza non scenda al di sotto dei 60 Hz e tutto va bene. Non e' stato necessario usare un timer perche' non interessa avere una frequenza sempre uguale sui LEDs. Basta che sia veloce.
E' chiaro che questo programma puo' anche essere implementato su altri micro, l' importante e' che siano abbastanza veloci. Ho notato che, con clock ad 1 MHz (il programma predispone un clock a 16 MHz) il risultato e' ancora abbastanza accettabile. Quindi potrebbe funzionare su un micro molto piu' lento, piccolo ed economico.

Buon proseguimento e buona programmazione.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
Rispondere è cortesia, ma lasciare l'ultima parola ai cretini è arte.
Avatar utente
Foto UtenteTardoFreak
73,7k 8 12 13
-EY Legend-
-EY Legend-
 
Messaggi: 15763
Iscritto il: 16 dic 2009, 11:10
Località: Torino - 3° pianeta del Sistema Solare

1
voti

[2] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTardoFreak » 23 lug 2010, 22:18

Piccola aggiunta.
Il programma del listato spazzola tutto lo spettro di colori. Se la scansione e' troppo veloce per un' eventuale applicazione, e' sufficiente modificare la linea
Codice: Seleziona tutto
base_tempi = 1;

in
Codice: Seleziona tutto
base_tempi++;

Con questa modifica il programma resta invariato perche' il risultato e' lo stesso: se base_tempi valeva 0 dopo vale 1. Ma se modifichiamo la linea
Codice: Seleziona tutto
if (base_tempi == 10)

in
Codice: Seleziona tutto
if (base_tempi == 10 )   // esempio di velocita' ridotta

Otterremo una scansione piu' lenta che dipendera' dalla costante (in questo caso 10).
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
Rispondere è cortesia, ma lasciare l'ultima parola ai cretini è arte.
Avatar utente
Foto UtenteTardoFreak
73,7k 8 12 13
-EY Legend-
-EY Legend-
 
Messaggi: 15763
Iscritto il: 16 dic 2009, 11:10
Località: Torino - 3° pianeta del Sistema Solare

0
voti

[3] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTardoFreak » 24 lug 2010, 19:53

Se a qualcuno interessa ho implementato il programma su un PIC16F628 a 4MHz con oscillatore interno. La frequenza del PWM e' di 100Hz circa.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
Rispondere è cortesia, ma lasciare l'ultima parola ai cretini è arte.
Avatar utente
Foto UtenteTardoFreak
73,7k 8 12 13
-EY Legend-
-EY Legend-
 
Messaggi: 15763
Iscritto il: 16 dic 2009, 11:10
Località: Torino - 3° pianeta del Sistema Solare

0
voti

[4] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTheMrLucas » 29 set 2010, 11:16

Salve, io sarei interessato :D
Era da un po' che provavo a creare un PWM via software per la gestione di un led RGB come ha fatto lei, ma per le mie poche conoscenze non ho mai ottenuto risultati accettabili...
Fin ora ho sempre programamto in assembler, quindi mi è difficile capire ciò che ha realizzato, se può spiegarmelo le sarei grato :)
Intanto vedo di cercarmi una guida sul C per vedere di capire, anche a livello base, quello che fa fare al PIC...
Un ultima cosa, io ho qua solo PIC 16f690 e 12f615, quindi poi vedrò di addattarlo ai PIC a disposizione :)
Avatar utente
Foto UtenteTheMrLucas
0 1
 
Messaggi: 4
Iscritto il: 29 set 2010, 10:53

0
voti

[5] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtentePaolino » 29 set 2010, 13:57

Hai provato a dare un'occhiata a questo articolo?

Ciao.

Paolo.
"Houston, Tranquillity Base here. The Eagle has landed." - Neil A.Armstrong

-------------------------------------------------------------

PIC Experience - http://www.picexperience.it
Avatar utente
Foto UtentePaolino
32,4k 8 12 13
G.Master EY
G.Master EY
 
Messaggi: 4213
Iscritto il: 20 gen 2006, 11:42
Località: Vigevano (PV)

0
voti

[6] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTheMrLucas » 29 set 2010, 16:09

Sisi, gestire un PWM con ciò che è già implementato nel PIC mi riesce, ma per controllare un led RGB servono 3 pin con 3 segnali PWM che variano in modo diverso...
Avatar utente
Foto UtenteTheMrLucas
0 1
 
Messaggi: 4
Iscritto il: 29 set 2010, 10:53

0
voti

[7] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTardoFreak » 29 set 2010, 16:33

E' il modo piu' stupido per fare PWM pero' c'e' l' inghippo: deve fare questo e solo questo, non puoi pensare di metterci atra roba dentro se non sotto interrupt.
Il programma e' un ciclo infinito che gira alla sua naturale velocita', quindi la massima che gli e' possibile. Un po' come fare un loop infinito dove attivi e disattivi un' uscita. Otterrai un segnale rettangolare limitato solo dalla velocita' del micro, ma se ci metti dentro altro il tempo di esecuzione aumenta, quindi ti varia il tempo della tua onda rettangolare.
In questo programma c'e' la variabile pos_pwm che va da 0 a 255 e si incrementa ogni ciclo. Ci sono poi tre variabili (una per ogni LED) che contengono il valore del tempo Ton (quindi la luminosita). Ad ogni ciclo viene fatta una comparazione fra la pos_pwm e il livello di ogni LED. Se pos_pwm e' piu' piccola del livello l' uscita corrispondente viene messa a 1, se e' piu' grande viene messa a 0.


Questo e' quello che succede con la variabile liv_R (livello del rosso).
Tutto qui. :)
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
Rispondere è cortesia, ma lasciare l'ultima parola ai cretini è arte.
Avatar utente
Foto UtenteTardoFreak
73,7k 8 12 13
-EY Legend-
-EY Legend-
 
Messaggi: 15763
Iscritto il: 16 dic 2009, 11:10
Località: Torino - 3° pianeta del Sistema Solare

0
voti

[8] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteIsidoroKZ » 29 set 2010, 17:57

Visto che di potenza di calcolo ce n'e` da vendere, interrupt ciclico (ad esempio a 100Hz) e nella routine di interrupt le tre comparazioni per fare i colori?

Saltando di palo in frasca, se il loop cosi' come lo hai fatto fosse scritto in assembler per bene, a che velocita` viaggerebbe?
Per usare proficuamente un simulatore, bisogna sapere molta più elettronica di lui
Plug it in - it works better!
Il 555 sta all'elettronica come Arduino all'informatica! (entrambi loro malgrado)
Se volete risposte rispondete a tutte le mie domande
Avatar utente
Foto UtenteIsidoroKZ
109,5k 1 3 8
G.Master EY
G.Master EY
 
Messaggi: 19286
Iscritto il: 17 ott 2009, 0:00

0
voti

[9] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtentePaolino » 29 set 2010, 18:06

Questo articolo usa timer ma fa PWM software. Prova a dare un'occhiata.
Ciao.

Paolo.
"Houston, Tranquillity Base here. The Eagle has landed." - Neil A.Armstrong

-------------------------------------------------------------

PIC Experience - http://www.picexperience.it
Avatar utente
Foto UtentePaolino
32,4k 8 12 13
G.Master EY
G.Master EY
 
Messaggi: 4213
Iscritto il: 20 gen 2006, 11:42
Località: Vigevano (PV)

0
voti

[10] Re: [PIC18] Led e PWM: facile, veloce e senza timers.

Messaggioda Foto UtenteTardoFreak » 29 set 2010, 18:10

L' avevo fatto inizialmente con l' interrupt ciclico ma visto che doveva fare solo quello ho pensato bene di fare "come si faceva una volta". :mrgreen:
Sicuramente con l' interrupt ciclico e' piu' elegante e corretto. Basta comunque creare un' interrupt a f*256, nel caso di 100 Hz di uscita l' interrupt dovrebbe avvenire ogni 39uS. Inoltre si potrebbero controllare piu' uscite.
Scritto in assembly non saprei dirti quanto piu' veloce puo' essere, non ho provato.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
Rispondere è cortesia, ma lasciare l'ultima parola ai cretini è arte.
Avatar utente
Foto UtenteTardoFreak
73,7k 8 12 13
-EY Legend-
-EY Legend-
 
Messaggi: 15763
Iscritto il: 16 dic 2009, 11:10
Località: Torino - 3° pianeta del Sistema Solare

Prossimo

Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 3 ospiti