sábado, 21 de abril de 2012

MSP430: 7Seg + BDC To 7Seg

En esta entrada mostraremos cómo un sistema gobernado por un microcontrolador es capaz de trabajar con displays de 7 segmentos, tal y cómo describimos en el anterior capítulo: MSP430: 7 Segmentos + BCD To 7-Seg.

Vamos a trabajar sobre la placa MSP430 Launchpad y volvemos a emplear el microcontrolador MSP430G245.

El programa en sí es sencillo, cada vez que presionamos el pulsador de la placa MSP430 Launchpad (en el pin P1.3), se incrementará en una unidad la información mostrada por los displays de 7 segmentos.

El material que vamos a necesitar y su función es la que se muestra a continuación:

· MSP430 Launchpad: Evidentemente, nuestra placa de desarrollo con el microcontrolador MSP430G245, dónde aprovecharemos el pulsador en el pin P1.3.
· Display de 7 Segmentos: Para este caso, emplearemos un módulo (de reloj) de 4 displays de 7 segmentos de cátodo común de la empresa Vishay, cuya referencia y hoja de características es: TDCY1060M.
· Decodificador BCD a 7-Seg: Usaremos un decodificador que controle displays de 7 segmentos de cátodo común, en este caso, hemos elegido el siguiente: MC14511B (este tipo de integrados lo podemos encontrar en el catálogo de varios fabricantes: Motorola, ON Semiconductor, etc).
· Transistores y Resistores: Transistores del tipo NPN para elevar la intensidad que circula por el display de 7 Segmentos.

El funcionamiento del programa, como ya hemos comentado anteriormente, es simple, el display de 7 segmentos mostrará el dato: 0000 y cada vez que pulsemos el pulsador se incrementará en una unidad hasta llegar al dato: 9999, en este caso, si volvemos a accionar el pulsador, el dato volverá a: 0000.

Tanto la conexión con el display, del decodificador BCD a 7Seg cómo los transistores, se muestran en la parte de comentarios del programa que veremos más abajo.

La manera de gestionar el tiempo de refresco del display de 7 segmentos se hará mediante el TimerA configurado al reloj ACLK (que se le asociará el VLOCLK y mediante la técnica de polling), el código del programa es el siguiente:

/*----------------------------------------------------------------------
     AqueronteBlog@gmail.com            
                                                      
Este archivo es propiedad intelectual del blog Aqueronte,  
cuya dirección web, es la siguiente:                       
                                                       
     http://unbarquero.blogspot.com/           
                                                       
Se permite cualquier modificación del archivo siempre y cuando
se mantenga la autoría del autor.                          
                                                      
----------------------------------------------------------------------
                                                       
Filename:      main.c                              
Date:          18-April-12                                
File Version:  vs0.0                                     
Compiler:      IAR 5.40.3 [Kickstart]   

Author:        Manuel Caballero                           
Company:       Hades                          
                       
----------------------------------------------------------------------
                                                      
Notes:   En este programa vamos a mostrar como trabajar con displays
         de 7 segmentos mediante un decodificador BCD a 7 segmentos.
         Cada vez que presionemos el pulsador, se incrementará en una 
         unidad el dato mostrado por el módulo de 4 displays de 7 
         segmentos.
  
        · Configuración del Sistema:
           · MCLK: DCLOCK ~8 MHz
           · ACLK: VLOCLK ~12 kHz
           · Timer A: Encargado del refresco del módulo display

        · Conexión al MC14511BCP
           · 1.  B:    P1.1
           · 2.  C:    P1.2
           · 3.  #LT:  +3V
           · 4.  #BI:  +3V
           · 5.  LE:   GND
           · 6.  D:    P1.4
           · 7.  A:    P1.0
           · 8.  Vss:  GND
           · 9.  e:    Ánodo E
           · 10. d:    Ánodo D
           · 11. c:    Ánodo C
           · 12. b:    Ánodo B
           · 13. a:    Ánodo A
           · 14. g:    Ánodo G
           · 15. f:    Ánodo F
           · 16. Vdd:  +3V

        · Otras conexiones:
           · Base Q1:   P2.3
           · Base Q2:   P2.4
           · Base Q3:   P2.5
           · Base Q4:   P1.6
           · Fuente Q1: Cátodo común D1
           · Fuente Q2: Cátodo común D2
           · Fuente Q3: Cátodo común D3
           · Fuente Q4: Cátodo común D4
           · Pulsador:  P1.3
*/

#include "io430.h"

// Prototipos de funciones
void conf_CLK (void);
void conf_TimerA (void);
void conf_IO (void);  
unsigned int INT_To_BCD (unsigned int );

// Variables globales
unsigned int num = 0;
unsigned int cont = 0;

void main( void )
{ 
    conf_CLK ();
    conf_IO (); 
    conf_TimerA ();
  
    P1OUT = ~BIT3;
    P2OUT = 0;
  
    __enable_interrupt();  // Interrupt enable
 
    while (1){   
    // Dígito 1
      while (TA0CTL_bit.TAIFG == 0);
      P1OUT = num + (num & BIT4) + BIT3;
      P2OUT = BIT3;
      P1OUT &= ~BIT6;
      TA0CTL_bit.TAIFG = 0;       // Reset flag TAIFG
    
    // Dígito 2
      while (TA0CTL_bit.TAIFG == 0);
      P1OUT = (num >> 4) + ((num >> 4) & BIT4) + BIT3;
      P2OUT = BIT4;
      P1OUT &= ~BIT6;
      TA0CTL_bit.TAIFG = 0;       // Reset flag TAIFG
    
    // Dígito 3
      while (TA0CTL_bit.TAIFG == 0);
      P1OUT = (num >> 8) + ((num >> 8) & BIT4) + BIT3;
      P1OUT &= ~(BIT6);
      P2OUT = BIT5;
      TA0CTL_bit.TAIFG = 0;      // Reset flag TAIFG
    
    // Dígito 4    
      while (TA0CTL_bit.TAIFG == 0);
      P1OUT = (num >> 12) + ((num >> 12) & BIT4) + BIT3;
      P2OUT &= ~(BIT5+BIT4+BIT3);
      P1OUT |= BIT6;
      TA0CTL_bit.TAIFG = 0;     // Reset flag TAIFG
    }
}

/*
  Function: conf_CLK (void)

  Version:  vs0.0 (6/03/2012)
  Compiler: IAR 5.40.3 [Kickstart] 

  Description: Configura reloj del sistema (~8 MHz) y ACLK (~12 kHz).
  Notes:       
*/
void conf_CLK (void)
{
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
  
    DCOCTL = CALDCO_8MHZ;
    BCSCTL1 = CALBC1_8MHZ;                    
  
   BCSCTL3 = LFXT1S1;          // ACLK = VLOCLK
}
 
void conf_IO (void)
{
    P1DIR |= BIT0+BIT1+BIT2+BIT4+BIT6;
    P1DIR &= ~BIT3;
  
    P2DIR |= BIT3+BIT4+BIT5;
  
    P1REN |= BIT3;           // P1.3 pullup
    P1OUT |= BIT3;
    P1IE |= BIT3;            // P1.3 interrupt enabled
    P1IES |= BIT3;           // P1.3 Hi/lo edge
    P1IFG &= ~BIT3;          // P1.3 IFG cleared
}

void conf_TimerA (void)
{
    TA0CCR0 = 75;                      // TAIFG on around ~6.25ms
    TA0CTL = TASSEL_1 + MC_1 + TACLR;  // ACLK, upmode
    TA0CTL_bit.TAIFG = 0;              // Reset flag TAIFG
}

unsigned int INT_To_BCD (unsigned int comd)
{
    unsigned int retval = 0;
  
    while (comd > 999)
    {
      comd -= 1000;
      retval += 0x1000;
    }
  
    while (comd > 99)
    {
      comd -= 100;
      retval += 0x100;
    }
  
    while (comd > 9)
    {
      comd -= 10;
      retval += 0x10;
    }
  
    while (comd != 0)
    {
      comd -= 1;
      retval += 0x1;
    }
    
    return retval;
}

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void P1_ISR(void)
{
    cont++;
  
    if (cont > 9999)
      cont = 0;
  
    num = INT_To_BCD (cont);
    P1IFG &= ~BIT3;           // P1.3 IFG cleared
}

Un vídeo que demuestra lo explicado anteriormente se presenta a continuación:




Os pongo a vuestra disposición el programa en lenguaje C (IAR y MSPGCC) para que lo podáis descargar y probar:


MSP430: 7 Segmentos + BCD To 7Seg
Compilador IARCompilador MSPGCC
CC
7 Segmentos + BCD To 7Seg
7 Segmentos + BCD To 7Seg
7 Segmentos + BCD To 7Seg
7 Segmentos + BCD To 7Seg
7 Segmentos + BCD To 7Seg
7 Segmentos + BCD To 7Seg


Como se ha podido ver en el transcurso de esta entrada, controlar y representar información a través displays de 7 segmentos es relativamente sencillo mediante un microcontrolador.

6 comentarios:

Anónimo dijo...

Buenas noches estoy comenzando a trabajar con este micro estoy realizando un frecuencímetro.
Estoy utilizando el modo de captura para medir el tiempo que dura el periodo de la señal, ya logre visualizar el valor del periodo en displays de 7 segmentos ahora lo que necesito es convertir este valor para poder obtener la frecuencia.
Agradeceria mucho su asesoria, este es el codigo realizado hasta el momento.

#include
#define d3 0x10
#define d2 0x20
#define d1 0x40
#define d0 0x80

void ss (void);
unsigned int mux,dig3,dig2,dig1,dig0,f,suma,c,prom;
unsigned int measure,measure_1,measure_2;

void main(void){
WDTCTL = WDT_ADLY_1_9; // WDT 1.9 ms, ACLK, interval timer, tiempo para refresco del display
IE1 |= WDTIE; // Enable WDT interrupt


if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){while(1);}
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation

P1DIR |= 0xFD; // P1.0 output
P1OUT &= ~0XFD;
P1SEL = BIT1;
P2DIR |= 0X3F;
P2OUT &= ~0X3F;

mux=dig3=dig2=dig1=dig0=0;

TACCTL0 |= CM_1 + SCS + CCIS_0 + CAP + CCIE;
TACTL |= TASSEL_2 + MC_2 + ID_0;
_BIS_SR(LPM3_bits + GIE);} // Enter LPM3 w/ interrupt

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void){
measure=TACCR0-measure_1;
measure_1=TACCR0;

ss();
}

#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void){
mux++;
if(mux>3)mux=0;

switch (mux){
case 0:
{P2OUT=dig0,P1OUT=d0;}
break;
case 1:
{P2OUT=dig1,P1OUT=d1;}
break;
case 2:
{P2OUT=dig2,P1OUT=d2;}
break;
default:
{P2OUT=dig3,P1OUT=d3;}
}
}


void ss (void){
dig0 = measure%10;
measure /= 10;
dig1 = measure%10;
measure /= 10;
dig2 = measure%10;
measure /= 10;
dig3 = measure%10;
}

Unknown dijo...

Buenas:

La expresión que relaciona el tiempo con el dato del timer/captura es la siguiente:

· X/(f_T) = Tiempo

Donde:

· X: Carga o captura del timer.
· f_T: Frecuencia a la que trabaja dicho timer.
· Tiempo: Tiempo consumido.

Pongamos un ejemplo:

· f_T = 125 kHz.
· X = 62500

Entonces, aplicando la expresión anterior, tenemos que:

· Tiempo = 65200/(125 kHz) = 0.5 segundos.

Y la relación entre la frecuencia y el tiempo es la siguiente:

· f = 1/Tiempo

Por lo tanto, siguiendo con nuestro ejemplo, tenemos lo siguiente:

· f = 1/0.5 = 2 Hz.

Es decir, que si la captura es de 65200, la señal estudiada tendrá una frecuencia de 2 Hz.

Un saludo.

Anónimo dijo...

Que tal
Como ejemplo deseo medir una señal con una frecuencia de 1 k Hz. Configuro el timer para que trabaje a 1 M Hz.

El registro TACCR0 del timer se carga con un valor de 1000.

· f_T = 1 MHz.
· X = 1000
Tiempo =( x / f_T)

·Tiempo = 1000/(1 MHz)=1000 µ segundos.

f = 1/Tiempo

· f = 1/1000x10-6 = 1 K Hz.

La pregunta es como hago la operación

f = (1/1000x10-6)

La operación que entiende el microcontrolador debe realizar es:

operación 1) (1/1000) y no
operación 2) (1/1000x10-6)

Si realizo la operación 1 y despues multiplico por la frecuencia a la que trabaja el timer obtengo el mismo resultado.

El problema ahora seria si el microcontrolador puede trabajar con este tipo de datos








































Unknown dijo...

Buenas:

Vamos a ver, teniendo en cuenta la configuración que has mencionado:

· f_Timer = 1 MHz.

Y a la hora de la captura, obtienes el valor en el registro apropiado:

· TACCR0 = 1000.

Pues significa lo siguiente:

· Tiempo = 1000/(1000000) = 1 ms.

Quiere decir que has capturado un cambio de la señal de 1 ms.

En términos de frecuencia, aplicamos la siguiente expresión:

· f = 1/Tiempo = 1/0.001 = 1000 Hz = 1 kHz.

En otras palabras, la frecuencia, cuando se ha capturado un cambio de estado en la señal, es de 1 kHz.

Un saludo.

Anónimo dijo...

Gracias por la pronta respuesta

continuare haciendo pruebas y comentando los resultados obtenidos

Otra pregunta cual metodo es mas preciso para medición de frecuencia con este micro.

*Medir el periodo de una señal.

*Contar el numero de pulsos en un intervalo de tiempo conocido.



Unknown dijo...

Buenas:

Dependerá de la morfología de la propia señal a medir, es decir, pongamos de ejemplo una señal cuadrada.

Configuramos una de las patitas del microcontrolador que produzca una interrupción a un evento de cambio de flanco (por ejemplo, de subida). Gráficamente:
____
· Flanco de Subida: __|

En este momento se produce una interrupción y obtenemos la captura del timer (lo llamamos dato A).

____
· Flanco de bajado: |_

No sucede nada, esperamos al siguiente flanco.

____
· Flanco de Subida: __|

Se produce una interrupción y volvemos a capturar el dato del timer (lo llamamos dato B).

Pues bien, en estos momentos estamos en condiciones de conocer la frecuencia de esta señal cuadrada:

· Tiempo = (B - A)/f_Timer

Vamos a darle valores de ejemplo:

· B = 2000.
· A = 1000.
· f_Timer = 1 MHz.

Sustituimos valores:

· Tiempo = (2000 - 1000)/1000000 = 1 ms.

La frecuencia será:

· f = 1/Tiempo = 1/0.001 = 1000 Hz = 1 kHz.

Como verás, depende mucho de la señal a medir, tendrás que hacer pruebas y elegir la mejor forma de medir frecuencias.

Un saludo.