.. note::

    ¡Hola! Bienvenidos a la Comunidad de Entusiastas de SunFounder Raspberry Pi, Arduino y ESP32 en Facebook. Sumérgete en el mundo de Raspberry Pi, Arduino y ESP32 con otros entusiastas.

    **¿Por qué unirse?**

    - **Soporte de Expertos**: Resuelve problemas post-venta y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y Comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances Exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y adelantos exclusivos.
    - **Descuentos Especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones y Sorteos Festivos**: Participa en sorteos y promociones especiales.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo!

.. _3.1.6_c:

3.1.6 Semáforo
==============================

Introducción
-----------------

En este proyecto, usaremos luces LED de tres colores para simular el cambio de los 
semáforos y una pantalla de 7 segmentos de cuatro dígitos para mostrar la temporización 
de cada estado del tráfico.

Componentes Necesarios
--------------------------------

En este proyecto, necesitamos los siguientes componentes.

.. image:: ../img/list_Traffic_Light.png
    :align: center

Es muy conveniente comprar un kit completo, aquí tienes el enlace:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Nombre
        - ÍTEMS EN ESTE KIT
        - ENLACE
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

También puedes comprarlos por separado en los enlaces a continuación.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - INTRODUCCIÓN DEL COMPONENTE
        - ENLACE DE COMPRA

    *   - :ref:`cpn_gpio_extension_board`
        - |link_gpio_board_buy|
    *   - :ref:`cpn_breadboard`
        - |link_breadboard_buy|
    *   - :ref:`cpn_wires`
        - |link_wires_buy|
    *   - :ref:`cpn_resistor`
        - |link_resistor_buy|
    *   - :ref:`cpn_led`
        - |link_led_buy|
    *   - :ref:`cpn_4_digit`
        - \-
    *   - :ref:`cpn_74hc595`
        - |link_74hc595_buy|

Diagrama Esquemático
-----------------------

============ ======== ======== ===
Nombre T-Board physical wiringPi BCM
GPIO17       Pin 11   0        17
GPIO27       Pin 13   2        27
GPIO22       Pin 15   3        22
SPIMOSI      Pin 19   12       10
GPIO18       Pin 12   1        18
GPIO23       Pin 16   4        23
GPIO24       Pin 18   5        24
GPIO25       Pin 22   6        25
SPICE0       Pin 24   10       8
SPICE1       Pin 26   11       7
============ ======== ======== ===

.. image:: ../img/Schematic_three_one7.png
   :align: center

Procedimientos Experimentales
----------------------------------

**Paso 1:** Construir el circuito.

.. image:: ../img/image254.png

**Paso 2:** Cambiar de directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/c/3.1.6/

**Paso 3:** Compilar.

.. raw:: html

   <run></run>

.. code-block:: 

    gcc 3.1.6_TrafficLight.c -lwiringPi

**Paso 4:** Ejecutar.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo ./a.out

Al ejecutar el código, los LEDs simularán el cambio de colores de los semáforos. 
Primero, el LED rojo se enciende durante 60 segundos, luego el LED verde se enciende 
durante 30 segundos; a continuación, el LED amarillo se enciende durante 5 segundos. 
Después de eso, el LED rojo se enciende nuevamente durante 60 segundos. De esta manera, 
esta serie de acciones se ejecutará repetidamente.

.. note::

    Si no funciona después de ejecutarlo, o aparece un mensaje de error: \"wiringPi.h: No such file or directory\", consulta :ref:`install_wiringpi`.

Código
---------

.. code-block:: c

    #include <wiringPi.h>
    #include <stdio.h>
    #include <wiringShift.h>
    #include <signal.h>
    #include <unistd.h>
    #define     SDI     5 
    #define     RCLK    4  
    #define     SRCLK    1   

    const int ledPin[]={6,10,11};  
    const int placePin[] = {12, 3, 2, 0};
    unsigned char number[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

    int greenLight = 30;
    int yellowLight = 5;
    int redLight = 60;
    int colorState = 0;
    char *lightColor[]={"Red","Green","Yellow"};
    int counter = 60;

    void lightup()
    {
        for(int i=0;i<3;i++){
            digitalWrite(ledPin[i],HIGH);
        }
        digitalWrite(ledPin[colorState],LOW);    
    }

    void pickDigit(int digit)
    {
        for (int i = 0; i < 4; i++)
        {
            digitalWrite(placePin[i], 0);
        }
        digitalWrite(placePin[digit], 1);
    }

    void hc595_shift(int8_t data)
    {
        int i;
        for (i = 0; i < 8; i++)
        {
            digitalWrite(SDI, 0x80 & (data << i));
            digitalWrite(SRCLK, 1);
            delayMicroseconds(1);
            digitalWrite(SRCLK, 0);
        }
        digitalWrite(RCLK, 1);
        delayMicroseconds(1);
        digitalWrite(RCLK, 0);
    }

    void clearDisplay()
    {
        int i;
        for (i = 0; i < 8; i++)
        {
            digitalWrite(SDI, 1);
            digitalWrite(SRCLK, 1);
            delayMicroseconds(1);
            digitalWrite(SRCLK, 0);
        }
        digitalWrite(RCLK, 1);
        delayMicroseconds(1);
        digitalWrite(RCLK, 0);
    }

    void display()
    {
        int a,b,c;
        
        a = counter % 10000 / 1000 + counter % 1000 / 100;
        b = counter % 10000 / 1000 + counter % 1000 / 100 + counter % 100 / 10;
        c = counter % 10000 / 1000 + counter % 1000 / 100 + counter % 100 / 10 + counter % 10;

        if (counter % 10000 / 1000 == 0){
            clearDisplay();
        }
        else{
            clearDisplay();
            pickDigit(3);
            hc595_shift(number[counter % 10000 / 1000]);
        }
        if (a == 0){
            clearDisplay();
        }
        else{
            clearDisplay();
            pickDigit(2);
            hc595_shift(number[counter % 1000 / 100]);
        }
        if (b == 0){
            clearDisplay();
        }
        else{
            clearDisplay();
            pickDigit(1);
            hc595_shift(number[counter % 100 / 10]);
        }
        if(c == 0){
            clearDisplay();
        }

        else{
            clearDisplay();
            pickDigit(0);
            hc595_shift(number[counter % 10]);
        }
    }

    void loop()
    {
        while(1){
        display();
        lightup(); 
        }
    }


    void timer(int  timer1){       //Timer function
        if(timer1 == SIGALRM){   
            counter --;         
            alarm(1); 
            if(counter == 0){
                if(colorState == 0) counter = greenLight;
                if(colorState == 1) counter = yellowLight;
                if(colorState == 2) counter = redLight;
                colorState = (colorState+1)%3; 
            }
            printf("counter : %d \t light color: %s \n",counter,lightColor[colorState]);
        }
    }

    int main(void)
    {
        int i;
        if(wiringPiSetup() == -1){ 
            printf("setup wiringPi failed !");
            return 1; 
        }
        pinMode(SDI,OUTPUT);        
        pinMode(RCLK,OUTPUT);
        pinMode(SRCLK,OUTPUT);
        for(i=0;i<4;i++){       
            pinMode(placePin[i],OUTPUT);
            digitalWrite(placePin[i],HIGH);
        }
        for(i=0;i<3;i++){       
            pinMode(ledPin[i],OUTPUT);
            digitalWrite(ledPin[i],HIGH);
        }
        signal(SIGALRM,timer);  
        alarm(1); 
        loop();
        return 0;
    }


Explicación del Código
-----------------------------

.. code-block:: c

    #define     SDI     5 
    #define     RCLK    4  
    #define     SRCLK    1   

    const int placePin[] = {12, 3, 2, 0};
    unsigned char number[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

    void pickDigit(int digit);
    void hc595_shift(int8_t data);
    void clearDisplay();
    void display();

Estos códigos se utilizan para realizar la función de visualización 
de números en una pantalla de 7 segmentos de 4 dígitos. Consulte el 
capítulo 1.1.5 del documento para obtener más detalles. Aquí, usamos 
los códigos para mostrar la cuenta regresiva del tiempo del semáforo.

.. code-block:: c

    const int ledPin[]={6,10,11};  

    int colorState = 0;

    void lightup()
    {
        for(int i=0;i<3;i++){
            digitalWrite(ledPin[i],HIGH);
        }
        digitalWrite(ledPin[colorState],LOW);    
    }

Los códigos se utilizan para encender y apagar el LED.

.. code-block:: c

    int greenLight = 30;
    int yellowLight = 5;
    int redLight = 60;
    int colorState = 0;
    char *lightColor[]={"Red","Green","Yellow"};
    int counter = 60;

    void timer(int  timer1){       //Timer function
        if(timer1 == SIGALRM){   
            counter --;         
            alarm(1); 
            if(counter == 0){
                if(colorState == 0) counter = greenLight;
                if(colorState == 1) counter = yellowLight;
                if(colorState == 2) counter = redLight;
                colorState = (colorState+1)%3; 
            }
            printf("counter : %d \t light color: %s \n",counter,lightColor[colorState]);
        }
    }

Los códigos se utilizan para activar y desactivar el temporizador. Consulte el 
capítulo 1.1.5 para obtener más detalles. Aquí, cuando el temporizador vuelve a cero, 
se cambiará colorState para cambiar el LED, y se asignará un nuevo valor al temporizador.

.. code-block:: c

    void loop()
    {
        while(1){
        display();
        lightup(); 
        }
    }

    int main(void)
    {
        //…
        signal(SIGALRM,timer);  
        alarm(1); 
        loop();
        return 0;
    }

El temporizador se inicia en la función main(). En la función loop(), 
se utiliza un bucle **while(1)** y se llaman las funciones de la pantalla 
de 7 segmentos de 4 dígitos y del LED.

Imagen del Fenómeno
-----------------------

.. image:: ../img/IMG_8319.jpg
   :align: center