← Volver al inicio

Laboratorio 2: Display de 7 Segmentos

Control de perifericos mediante una comunicacion serie síncrona

1. ¿Qué es un Display de 7 Segmentos?

Es un componente optoelectrónico compuesto por 7 LEDs (segmentos) dispuestos en forma de "8", más un octavo LED para el punto decimal (DP). Permite representar números y algunos caracteres alfanuméricos.

Tipos de Configuración:

  • Cátodo Común: Todos los cátodos de los LEDs están unidos a masa (GND). Se iluminan con un '1' lógico (HIGH).
  • Ánodo Común: Todos los ánodos están unidos a VCC. Se iluminan con un '0' lógico (LOW).
Segmentos a-g

2. Registro de Desplazamiento 74HC595

Para ahorrar pines en el microcontrolador (solo usamos 3), empleamos este chip que convierte datos serie en paralelo (SISO/SIPO).

DS (Serial Data)

Pin por donde entra el bit de datos actual.

SHCP (Shift Clock)

Desplaza el dato de DS al interior del registro en cada flanco de subida.

STCP (Latch Clock)

Actualiza las salidas físicas (QA-QH) con el contenido del registro.

3. Funcionamiento Dinámico (Multiplexado)

En sistemas con varios dígitos, se utiliza el multiplexado para ahorrar componentes. Se activan los dígitos uno a uno de forma secuencial.

Esquema de conexión
  1. Primer 595 (U3): Controla qué segmentos (a-g, dp) se encienden. Sus salidas están conectadas a todos los dígitos en paralelo.
  2. Segundo 595 (cascada - U2): Controla los "comunes" (dígitos). Activa uno a uno cada dígito a gran velocidad.
Persistencia de la visión: Al conmutar entre dígitos tan rápido (frecuencia > 50Hz), el ojo humano percibe que todos los dígitos están encendidos simultáneamente aunque solo haya uno activo en cada instante de tiempo.

4. Ejemplo de Implementación: Contador 0-9

A continuación se muestra un ejemplo completo para implementar un contador de 0 a 9 en un display de 7 segmentos conectado a un 74HC595. Se presentan dos implementaciones: Bare-Metal (manipulando registros directamente) y CMSIS (usando la biblioteca de periféricos).

Esquema de Conexión

STM32F103RB
Microcontrolador
PB0 → DS (Datos)
PB1 → SHCP (Reloj)
PB2 → STCP (Cerrojo)
74HC595
Registro de Desplazamiento
QA-QH → Segmentos a-g, dp
Display 7 segmentos (cátodo común)
Nota sobre conexiones: Las salidas QA-QH del 74HC595 se conectan directamente a los pines del display de 7 segmentos. El orden típico es: QA=A, QB=B, QC=C, QD=D, QE=E, QF=F, QG=G, QH=DP.

Tabla de Códigos para Display (Cátodo Común)

Código hexadecimal a enviar al 74HC595 para mostrar cada dígito (formato: 0bHGFEDCBA):

Dígito Segmentos Encendidos Binario Hexadecimal
0a,b,c,d,e,f0b001111110x3F
1b,c0b000001100x06
2a,b,d,e,g0b010110110x5B
3a,b,c,d,g0b010011110x4F
4b,c,f,g0b011001100x66
5a,c,d,f,g0b011011010x6D
6a,c,d,e,f,g0b011111010x7D
7a,b,c0b000001110x07
8a,b,c,d,e,f,g0b011111110x7F
9a,b,c,d,f,g0b011011110x6F

Implementación del Programa

#include "stm32f10x.h"

// Pines conectados al 74HC595
#define HC595_DS_PORT  GPIOB
#define HC595_DS_PIN   GPIO_ODR_ODR0

#define HC595_SHCP_PORT GPIOB
#define HC595_SHCP_PIN  GPIO_ODR_ODR1

#define HC595_STCP_PORT GPIOB
#define HC595_STCP_PIN  GPIO_ODR_ODR2

// Tabla de códigos para display 7 segmentos (cátodo común)
const uint8_t seg_codes[10] = {
    0x3F, // 0: a,b,c,d,e,f
    0x06, // 1: b,c
    0x5B, // 2: a,b,d,e,g
    0x4F, // 3: a,b,c,d,g
    0x66, // 4: b,c,f,g
    0x6D, // 5: a,c,d,f,g
    0x7D, // 6: a,c,d,e,f,g
    0x07, // 7: a,b,c
    0x7F, // 8: a,b,c,d,e,f,g
    0x6F  // 9: a,b,c,d,f,g
};

void delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 1000; i++) {
        __NOP();
    }
}

void hc595_send_byte(uint8_t data) {
    //-enviamos los 8 bits (MSB primero)
    for (int8_t i = 7; i >= 0; i--) {
        //-establecer el bit de datos
        if (data & (1 << i)) {
            HC595_DS_PORT->BSRR = HC595_DS_PIN;  // DS = 1
        } else {
            HC595_DS_PORT->BRR = HC595_DS_PIN;   // DS = 0
        }

        //-pulso de reloj (SHCP)
        HC595_SHCP_PORT->BSRR = HC595_SHCP_PIN;  // SHCP = 1
        delay_ms(1);
        HC595_SHCP_PORT->BRR = HC595_SHCP_PIN;   // SHCP = 0
        delay_ms(1);
    }

    //-pulso de cerrojo (STCP) para actualizar salidas
    HC595_STCP_PORT->BSRR = HC595_STCP_PIN;  // STCP = 1
    delay_ms(1);
    HC595_STCP_PORT->BRR = HC595_STCP_PIN;   // STCP = 0
}

int main(void) {
    //-habilitar reloj para GPIOB
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

    //-configurar PB0, PB1, PB2 como salida push-pull a 2MHz
    GPIOB->CRL &= ~(0xFFF << 0);  // Limpiar configuración de PB0-PB2
    GPIOB->CRL |= (0x222 << 0);   // Mode=2MHz Output, CNF=0 (Push-Pull)

    while (1) {
        //-contador de 0 a 9
        for (uint8_t i = 0; i < 10; i++) {
            hc595_send_byte(seg_codes[i]);
            delay_ms(500);
        }
    }
}
#include "stm32f10x.h"

// Definiciones de pines usando macros CMSIS
#define HC595_DS_PIN   GPIO_ODR_ODR0
#define HC595_SHCP_PIN GPIO_ODR_ODR1
#define HC595_STCP_PIN GPIO_ODR_ODR2

// Tabla de códigos para display 7 segmentos (cátodo común)
const uint8_t seg_codes[10] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

void delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 8000; i++) {
        __NOP();
    }
}

void hc595_send_byte(uint8_t data) {
    //-enviamos los 8 bits (MSB primero)
    for (int8_t i = 7; i >= 0; i--) {
        //-establecer el bit de datos (DS)
        if (data & (1 << i)) {
            GPIOB->BSRR = HC595_DS_PIN;
        } else {
            GPIOB->BRR = HC595_DS_PIN;
        }

        //-pulso de reloj (SHCP)
        GPIOB->BSRR = HC595_SHCP_PIN;
        delay_ms(1);
        GPIOB->BRR = HC595_SHCP_PIN;
        delay_ms(1);
    }

    //-pulso de cerrojo (STCP) para actualizar salidas
    GPIOB->BSRR = HC595_STCP_PIN;
    delay_ms(1);
    GPIOB->BRR = HC595_STCP_PIN;
}

int main(void) {
    //-habilitar reloj para GPIOB usando RCC_APB2ENR
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

    //-configurar pines como salida a 2MHz push-pull
    //-usar máscaras CMSIS para limpiar y configurar
    GPIOB->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_MODE1 | GPIO_CRL_MODE2 |
                    GPIO_CRL_CNF0  | GPIO_CRL_CNF1  | GPIO_CRL_CNF2);

    //-configurar como salida velocidad 2MHz (MODE = 10)
    GPIOB->CRL |= (GPIO_CRL_MODE0_1 | GPIO_CRL_MODE1_1 | GPIO_CRL_MODE2_1);

    //-CNF = 00 (Push-Pull) ya es el valor por defecto

    while (1) {
        for (uint8_t i = 0; i < 10; i++) {
            hc595_send_byte(seg_codes[i]);
            delay_ms(500);
        }
    }
}
Diferencias clave:
  • Bare-Metal: Manipulación directa de registros con operaciones de bits simples. Acceso directo a BSRR/BRR para set/reset de pines.
  • CMSIS: Uso de macros predefinidas (GPIO_ODR_ODR0, RCC_APB2ENR_IOPBEN) que mejoran la legibilidad y portabilidad del código.

4. Laboratorio: Decodificador Manual

Introduce un valor hexadecimal (0x00 a 0xFF) para ver cómo se comportarían los segmentos si enviaras ese dato al registro de desplazamiento.

Orden de los bits (MSB a LSB): DP, G, F, E, D, C, B, A

00000000