Difference between revisions of "PIC16F1459 SMT µClock"

From FabLabGenovaWiki
Jump to: navigation, search
(Hardware)
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''Soon on-line!'''
+
Si tratta di un progettino estremamente semplice, nato da un display a 7 segmenti a 4 cifre multiplexato e dalla voglia di fare qualcosa di utile e carino in SMT. Il risultato è veramente gradvole e funzionale, unica pecca il consumo un po' altino ( circa 30mA ), ma ho intenzione di migliorare il firmware per abbassarlo un po'.
 +
==Hardware==
 +
[[File:microClock.jpg|thumb|300px|L'µClock v 2 appena finito]]Sull'hardware non c'è molto da dire, è grossomodo identico a centinaia di altri progetti simili che si trovano in rete. Utilizza il comodissimo quarzo da 32,768 kHz ( connesso tra SOSCI e SOSCO ) come clock per un timer a 16bit ( timer 1 ), che tramite precaricamenti e prescaler vari finisce per generare un interrupt ogni secondo. Per regolare le ore e i minuti sono presenti due pulsanti che per semplificare il software hanno un anti-bounce hardware fatto con due resistenze da 33kΩ e 22kΩ e un condensatore da 100nF, questo sistema è una variazione di quanto ho trovato in giro per la rete, i valori dei componenti li ho determinati per aggiustamenti successivi e devo dire che ne sono molto soddisfatto, dato che non capita praticamente mai che faccia salti di due unità anzichè una.
 +
Dato che i GPIO del PIC sono in grado di assorbire/fornire 25mA l'uno gli anodi dei segmenti sono collegati direttamente a PORTC ( così come l'anodo dei due punti al centro ), mentre per l'attivazione di ciascuna cifra è necessario usare un piccolo transistor NPN ( BC817 in SOT23 ) controllato dal microprocessore, dato che deve mandare a massa fino a 8 volte la corrente di un singolo segmento; naturalmente servono delle resistenze da 10kΩ sulle basi dei transistor. Il display utilizzato ha la sigla LTC2727 e qui ([[file:LTC2727.zip]]) trovate il datasheet.
 +
Il curcuito sbrogliato è abbastanza piccolo, circa 41mm x 50mm, a singola faccia, ha dei fori di montaggio da 3mm ai quattro angoli ed è stato realizzato con la tecnica del toner transfert senza alcun problema ( le piste sono quasi tutte da 24mil ). Di seguito trovate i file eagle ([[ file:microclock_eagle.zip]]) per realizzare il circuito.
  
[[File:microClock.jpg]]
+
==Firmware==
 +
Anche sul firmware c'è poco da dire, gira su un PIC16F1459 per questione di simpatia e disponibilità. Usa l'interrupt su timer1 per aggiornare l'orario ogni secondo e gli interrupt-on-change su RA0 e RA1 per la regolazione dell'orario. È molto poco ottimizzato per il consumo, ma ci si può lavorare. Dato che è abbondantemente commentato metto semplicemente il codice scritto e testato con MPLABX e XC8 v 1.3, chiunque abbia un minimo di esperienza coi microprocessori Microchip lo può capire ( e migliorare ) in pochi minuti.
 +
<source lang="c">
 +
#include <xc.h>
 +
 
 +
#pragma config BOREN = OFF, IESO = OFF, FOSC = INTOSC, FCMEN = OFF, MCLRE = OFF
 +
#pragma config WDTE = OFF, CP = OFF, PWRTE = ON, CLKOUTEN = OFF
 +
#pragma config USBLSCLK = 48MHz, LPBOR = OFF, CPUDIV = NOCLKDIV, PLLEN = DISABLED
 +
#pragma config WRT = OFF, STVREN = OFF, PLLMULT = 3x, BORV = HI, LVP = OFF
 +
 
 +
#define _XTAL_FREQ 4000000 //Quarzo esterno da 32.768kHz, oscillatore interno a 4MHz
 +
 
 +
//Numeri in uscita su PORTC con configurazione 16Mar14
 +
int NUMBERS[] = { 0b0111111, 0b0100010, 0b1011011, 0b1101011, 0b1100110, 0b1101101,
 +
                    0b1111101, 0b0100111, 0b1111111, 0b1101111 };
 +
 
 +
//Contatore su timer 0
 +
int sec = 0, min = 0, h = 0;
 +
bit dots = 0;
 +
 
 +
int main( void ){
 +
    OSCCONbits.IRCF = 0b1101; // Internal oscillator @ 4MHz
 +
    TRISA = 0b00001011;
 +
    TRISC = 0b00000000;
 +
    TRISB = 0x00;
 +
 
 +
    //Setting per gli interrupt
 +
    INTCONbits.GIE = 1;//Abilita gli interrupt
 +
    INTCONbits.PEIE = 1;//Abilita gli interrupt sulle periferiche esterne ( TMR1)
 +
    INTCONbits.IOCIE = 1;//Abilita gli interrupt-on-change
 +
    INTCONbits.IOCIF = 0;
 +
 
 +
    TMR1IE = 1;//Abilita gli interrupt su timer1
 +
    TMR1IF = 0;
 +
 
 +
    //Setting di Timer 1
 +
    T1CON = 0b10011101; //Timer 1 attivato, utilizza come source un oscillatore
 +
                        //al quarzo tra T1OSO e T1OSI, prescaler 1:2 e non sincro
 +
    TMR1GE = 0; //Le funzionalità del Gate di Timer 1 sono disattivate
 +
 
 +
    //Setting degli interrupt-on-change
 +
    IOCAP = 0x00;//Spenti sul rising edge di tutte le PORTA
 +
    IOCAN = 0b00000011;//Interrupt sul falling edge di RA1 e RA0
 +
    IOCBP = 0x00;//Spenti sia sul falling che sul rising di PORTB
 +
    IOCBN = 0x00;
 +
    //Ciclo di riscrittura del numero parametri di multiplex funzionanti il
 +
    //17Feb14 5ms x cifra, no resistenze. BC337 a catodo comune 10K sulla base.
 +
    //Vdd = 3.3V
 +
 
 +
    while( 1 ){
 +
        RB4 = 1;
 +
        PORTC = NUMBERS[h/10] + dots * 128;
 +
        __delay_ms(1);
 +
        PORTC = 0x00;
 +
        RB4 = 0;
 +
        RB6 = 1;
 +
        PORTC = NUMBERS[h%10] + dots * 128;
 +
        __delay_ms(1);
 +
        PORTC = 0x00;
 +
        RB6 = 0;
 +
        RB5 = 1;
 +
        PORTC = NUMBERS[min/10] + dots * 128;
 +
        __delay_ms(1);
 +
        PORTC = 0x00;
 +
        RB5 = 0;
 +
        RB7 = 1;
 +
        PORTC = NUMBERS[min%10] + dots * 128;
 +
        __delay_ms(1);
 +
        PORTC = 0x00;
 +
        RB7 = 0;
 +
    }
 +
 
 +
}
 +
 
 +
void interrupt gestione(){
 +
    if( TMR1IF ){
 +
        //Ricarica l'interrupt.
 +
        TMR1H = 0xC0;
 +
        TMR1L = 0x00;
 +
        dots = !dots;
 +
        sec++;
 +
        if( sec == 60){
 +
            min++;
 +
            sec = 0;
 +
        }
 +
        if( min == 60 ){
 +
            min = 0;
 +
            h++;
 +
        }
 +
        if( h == 24 ) h = 0;
 +
        TMR1IF = 0;
 +
    }
 +
    if( IOCAF1 ){
 +
            h++;
 +
            if( h == 24 ) h = 0;
 +
            sec = 0;
 +
            TMR1H = 0xc0;
 +
            TMR1L = 0x00;
 +
            IOCAF1 = 0;
 +
            IOCIF = 0;
 +
    }
 +
    if( IOCAF0 ){
 +
            min++;
 +
            sec = 0;
 +
            if( min==60) min = 0;
 +
            TMR1H = 0xc0;
 +
            TMR1L = 0x00;
 +
            IOCAF0 = 0;
 +
            IOCIF = 0;
 +
    }
 +
}
 +
</source>

Latest revision as of 11:25, 16 March 2014

Si tratta di un progettino estremamente semplice, nato da un display a 7 segmenti a 4 cifre multiplexato e dalla voglia di fare qualcosa di utile e carino in SMT. Il risultato è veramente gradvole e funzionale, unica pecca il consumo un po' altino ( circa 30mA ), ma ho intenzione di migliorare il firmware per abbassarlo un po'.

Hardware

L'µClock v 2 appena finito
Sull'hardware non c'è molto da dire, è grossomodo identico a centinaia di altri progetti simili che si trovano in rete. Utilizza il comodissimo quarzo da 32,768 kHz ( connesso tra SOSCI e SOSCO ) come clock per un timer a 16bit ( timer 1 ), che tramite precaricamenti e prescaler vari finisce per generare un interrupt ogni secondo. Per regolare le ore e i minuti sono presenti due pulsanti che per semplificare il software hanno un anti-bounce hardware fatto con due resistenze da 33kΩ e 22kΩ e un condensatore da 100nF, questo sistema è una variazione di quanto ho trovato in giro per la rete, i valori dei componenti li ho determinati per aggiustamenti successivi e devo dire che ne sono molto soddisfatto, dato che non capita praticamente mai che faccia salti di due unità anzichè una.

Dato che i GPIO del PIC sono in grado di assorbire/fornire 25mA l'uno gli anodi dei segmenti sono collegati direttamente a PORTC ( così come l'anodo dei due punti al centro ), mentre per l'attivazione di ciascuna cifra è necessario usare un piccolo transistor NPN ( BC817 in SOT23 ) controllato dal microprocessore, dato che deve mandare a massa fino a 8 volte la corrente di un singolo segmento; naturalmente servono delle resistenze da 10kΩ sulle basi dei transistor. Il display utilizzato ha la sigla LTC2727 e qui (File:LTC2727.zip) trovate il datasheet. Il curcuito sbrogliato è abbastanza piccolo, circa 41mm x 50mm, a singola faccia, ha dei fori di montaggio da 3mm ai quattro angoli ed è stato realizzato con la tecnica del toner transfert senza alcun problema ( le piste sono quasi tutte da 24mil ). Di seguito trovate i file eagle (File:Microclock eagle.zip) per realizzare il circuito.

Firmware

Anche sul firmware c'è poco da dire, gira su un PIC16F1459 per questione di simpatia e disponibilità. Usa l'interrupt su timer1 per aggiornare l'orario ogni secondo e gli interrupt-on-change su RA0 e RA1 per la regolazione dell'orario. È molto poco ottimizzato per il consumo, ma ci si può lavorare. Dato che è abbondantemente commentato metto semplicemente il codice scritto e testato con MPLABX e XC8 v 1.3, chiunque abbia un minimo di esperienza coi microprocessori Microchip lo può capire ( e migliorare ) in pochi minuti. <source lang="c">

  1. include <xc.h>
  1. pragma config BOREN = OFF, IESO = OFF, FOSC = INTOSC, FCMEN = OFF, MCLRE = OFF
  2. pragma config WDTE = OFF, CP = OFF, PWRTE = ON, CLKOUTEN = OFF
  3. pragma config USBLSCLK = 48MHz, LPBOR = OFF, CPUDIV = NOCLKDIV, PLLEN = DISABLED
  4. pragma config WRT = OFF, STVREN = OFF, PLLMULT = 3x, BORV = HI, LVP = OFF
  1. define _XTAL_FREQ 4000000 //Quarzo esterno da 32.768kHz, oscillatore interno a 4MHz

//Numeri in uscita su PORTC con configurazione 16Mar14 int NUMBERS[] = { 0b0111111, 0b0100010, 0b1011011, 0b1101011, 0b1100110, 0b1101101,

                   0b1111101, 0b0100111, 0b1111111, 0b1101111 };

//Contatore su timer 0 int sec = 0, min = 0, h = 0; bit dots = 0;

int main( void ){

   OSCCONbits.IRCF = 0b1101; // Internal oscillator @ 4MHz
   TRISA = 0b00001011;
   TRISC = 0b00000000;
   TRISB = 0x00;
   //Setting per gli interrupt
   INTCONbits.GIE = 1;//Abilita gli interrupt
   INTCONbits.PEIE = 1;//Abilita gli interrupt sulle periferiche esterne ( TMR1)
   INTCONbits.IOCIE = 1;//Abilita gli interrupt-on-change
   INTCONbits.IOCIF = 0;
   TMR1IE = 1;//Abilita gli interrupt su timer1
   TMR1IF = 0;
   //Setting di Timer 1
   T1CON = 0b10011101; //Timer 1 attivato, utilizza come source un oscillatore
                       //al quarzo tra T1OSO e T1OSI, prescaler 1:2 e non sincro
   TMR1GE = 0; //Le funzionalità del Gate di Timer 1 sono disattivate
   //Setting degli interrupt-on-change
   IOCAP = 0x00;//Spenti sul rising edge di tutte le PORTA
   IOCAN = 0b00000011;//Interrupt sul falling edge di RA1 e RA0
   IOCBP = 0x00;//Spenti sia sul falling che sul rising di PORTB
   IOCBN = 0x00;
   //Ciclo di riscrittura del numero parametri di multiplex funzionanti il
   //17Feb14 5ms x cifra, no resistenze. BC337 a catodo comune 10K sulla base.
   //Vdd = 3.3V
   while( 1 ){
       RB4 = 1;
       PORTC = NUMBERS[h/10] + dots * 128;
       __delay_ms(1);
       PORTC = 0x00;
       RB4 = 0;
       RB6 = 1;
       PORTC = NUMBERS[h%10] + dots * 128;
       __delay_ms(1);
       PORTC = 0x00;
       RB6 = 0;
       RB5 = 1;
       PORTC = NUMBERS[min/10] + dots * 128;
       __delay_ms(1);
       PORTC = 0x00;
       RB5 = 0;
       RB7 = 1;
       PORTC = NUMBERS[min%10] + dots * 128;
       __delay_ms(1);
       PORTC = 0x00;
       RB7 = 0;
   }

}

void interrupt gestione(){

   if( TMR1IF ){
       //Ricarica l'interrupt.
       TMR1H = 0xC0;
       TMR1L = 0x00;
       dots = !dots;
       sec++;
       if( sec == 60){
           min++;
           sec = 0;
       }
       if( min == 60 ){
           min = 0;
           h++;
       }
       if( h == 24 ) h = 0;
       TMR1IF = 0;
   }
   if( IOCAF1 ){
           h++;
           if( h == 24 ) h = 0;
           sec = 0;
           TMR1H = 0xc0;
           TMR1L = 0x00;
           IOCAF1 = 0;
           IOCIF = 0;
   }
   if( IOCAF0 ){
           min++;
           sec = 0;
           if( min==60) min = 0;
           TMR1H = 0xc0;
           TMR1L = 0x00;
           IOCAF0 = 0;
           IOCIF = 0;
   }

} </source>