.. note::

    こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ！Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。

    **参加する理由は？**

    - **エキスパートサポート**：コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
    - **学び＆共有**：ヒントやチュートリアルを交換してスキルを向上させましょう。
    - **独占的なプレビュー**：新製品の発表や先行プレビューに早期アクセスしましょう。
    - **特別割引**：最新製品の独占割引をお楽しみください。
    - **祭りのプロモーションとギフト**：ギフトや祝日のプロモーションに参加しましょう。

    👉 私たちと一緒に探索し、創造する準備はできていますか？[|link_sf_facebook|]をクリックして今すぐ参加しましょう！

.. _py_4-dig:

1.1.5 4桁7セグメントディスプレイ
====================================

前書き
-----------------

次に、4桁7セグメントディスプレイを制御してみてください。

部品
---------------

.. image:: media/list_4_digit.png


原理
--------------

**4桁7セグメントディスプレイ**

4桁の7セグメントディスプレイは、連携して動作する4つの7セグメントディスプレイで構成されている。

.. image:: media/4-digit-sche.png

4デジタル7セグメントディスプレイは独立して動作する。人間の視覚的持続性の原理を使用して、ループ内の各7セグメントの文字をすばやく表示し、連続した文字列を形成する。

つまり、ディスプレイに「1234」が表示されている場合、最初の7セグメントに「1」が表示され、「234」は表示されないということである。しばらくすると、2番目の7セグメントに「2」が表示され、7セグメントの1番目、3番目、4番目に表示されなくなり、4つのデジタルディスプレイショーが順番に表示される。このプロセスは非常に短く（通常5ms）、光学的残光効果と視覚的残留の原理により、同時に4つの文字を見ることができる。

.. image:: media/image78.png


**表示コード**

7セグメントディスプレイ（アノードコモン）がどのように番号を表示するかを知るために、次の表をご参照ください。数字は7セグメントディスプレイに表示される0〜Fの数字である。（DP）GFEDCBAは、0または1に設定された対応のLEDを指す。たとえば、11000000はDPおよびGが1に設定され、他のLEDが0に設定されることを意味する。
したがって、7セグメントディスプレイには0が表示され、HEXコードは16進数に対応する。

.. image:: media/common_anode.png


回路図
--------------------------

============ ======== ======== ===
T-Board Name 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
============ ======== ======== ===

.. image:: media/schmatic_4_digit.png


実験手順
-----------------------------------

ステップ1: 回路を作る。

.. image:: media/image80.png
    :width: 800

C言語ユーザー向け
^^^^^^^^^^^^^^^^^^^^^^^^

ステップ2：コードのフォルダーに入る。

.. raw:: html

   <run></run>

.. code-block::

    cd ~/davinci-kit-for-raspberry-pi/c/1.1.5/

ステップ3：コードをコンパイルする。

.. raw:: html

   <run></run>

.. code-block::

    gcc 1.1.5_4-Digit.c -lwiringPi

ステップ4：EXEファイルを実行する。

.. raw:: html

   <run></run>

.. code-block::

    sudo ./a.out

コードの実行後、プログラムは1秒間に1つずつ増やすカウントを行い、4桁の7セグメントディスプレイにそのカウントが表示される。


**コード**

.. 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 placePin[] = {12, 3, 2, 0};
    unsigned char number[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

    int counter = 0;

    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 loop()
    {
        while(1){
        clearDisplay();
        pickDigit(0);
        hc595_shift(number[counter % 10]);

        clearDisplay();
        pickDigit(1);
        hc595_shift(number[counter % 100 / 10]);

        clearDisplay();
        pickDigit(2);
        hc595_shift(number[counter % 1000 / 100]);
    
        clearDisplay();
        pickDigit(3);
        hc595_shift(number[counter % 10000 / 1000]);
        }
    }

    void timer(int timer1)
    { 
        if (timer1 == SIGALRM)
        { 
            counter++;
            alarm(1); 
            printf("%d\n", counter);
        }
    }

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



**コードの説明**

.. code-block:: c

    const int placePin[] = {12, 3, 2, 0};

これらの4つのピンは、4桁の7セグメントディスプレイのアノードコモンピンを制御する。

.. code-block:: c

    unsigned char number[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

16進数（アノードコモン）の0〜9のセグメントコード配列。

.. code-block:: c

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

値の場所を選択する。毎回有効な場所は1つだけである。有効な場所はhighに書き込まれる。

.. code-block:: c

    void loop()
    {
        while(1){
        clearDisplay();
        pickDigit(0);
        hc595_shift(number[counter % 10]);

        clearDisplay();
        pickDigit(1);
        hc595_shift(number[counter % 100 / 10]);

        clearDisplay();
        pickDigit(2);
        hc595_shift(number[counter % 1000 / 100]);
    
        clearDisplay();
        pickDigit(3);
        hc595_shift(number[counter % 10000 / 1000]);
        }
    }

この機能を使用して、4桁の7セグメントディスプレイに表示される番号を設定する。

* ``clearDisplay()`` ：11111111に書き込み、7セグメントディスプレイ上のこれら8つのLEDをオフにして、表示されたコンテンツを消去する。
* ``pickDigit(0)`` ：4番目の7セグメントディスプレイを選択する。
* ``hc595_shift(number[counter%10])`` ：カウンターの1桁の数字が4番目のセグメントに表示される。

.. code-block:: c

    signal(SIGALRM, timer); 

これはシステム組み込みの関数であり、コードのプロトタイプは次のとおりである：

.. code-block:: c

    sig_t signal(int signum,sig_t handler);

``signal()`` を実行した後、プロセスは対応する signum（ここでSIGALRM）を受信すると、すぐに既存のタスクを一時停止し、設定関数(ここでtimer(sig))を処理する。

.. code-block:: c

    alarm(1);

これもシステム組み込み関数である。コードのプロトタイプは：

.. code-block:: c

    unsigned int alarm (unsigned int seconds);

指定した秒数後にSIGALRMシグナルを生成する。

.. code-block:: c

    void timer(int timer1)
    { 
        if (timer1 == SIGALRM)
        { 
            counter++;
            alarm(1); 
            printf("%d\n", counter);
        }
    }

上記の関数を使用して、タイマー関数を実装する。 ``alarm()`` がSIGALRMシグナルを生成した後、タイマー関数が呼び出される。カウンターに1を追加すると、1秒後に関数 ``alarm(1)`` が繰り返し呼び出される。

Python言語ユーザー向け
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ステップ2：コードのフォルダーに入る。

.. raw:: html

   <run></run>

.. code-block::

    cd ~/davinci-kit-for-raspberry-pi/python/

ステップ3：EXEファイルを実行する。

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 1.1.5_4-Digit.py

コードの実行後、プログラムは1秒ずつ増加するカウントをして、4桁のディスプレイにカウントが表示される。

**コード**

.. note::

    以下のコードを **変更/リセット/コピー/実行/停止** できます。 ただし、その前に、 ``davinci-kit-for-raspberry-pi/python`` のようなソースコードパスに移動する必要があります。
     
.. raw:: html

    <run></run>

.. code-block:: python

    import RPi.GPIO as GPIO
    import time
    import threading

    SDI = 24
    RCLK = 23
    SRCLK = 18

    placePin = (10, 22, 27, 17)
    number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)

    counter = 0
    timer1 = 0

    def clearDisplay():
        for i in range(8):
            GPIO.output(SDI, 1)
            GPIO.output(SRCLK, GPIO.HIGH)
            GPIO.output(SRCLK, GPIO.LOW)
        GPIO.output(RCLK, GPIO.HIGH)
        GPIO.output(RCLK, GPIO.LOW)    

    def hc595_shift(data): 
        for i in range(8):
            GPIO.output(SDI, 0x80 & (data << i))
            GPIO.output(SRCLK, GPIO.HIGH)
            GPIO.output(SRCLK, GPIO.LOW)
        GPIO.output(RCLK, GPIO.HIGH)
        GPIO.output(RCLK, GPIO.LOW)

    def pickDigit(digit):
        for i in placePin:
            GPIO.output(i,GPIO.LOW)
        GPIO.output(placePin[digit], GPIO.HIGH)


    def timer():  
        global counter
        global timer1
        timer1 = threading.Timer(1.0, timer) 
        timer1.start()  
        counter += 1
        print("%d" % counter)


    def loop():
        global counter                    
        while True:
            clearDisplay() 
            pickDigit(0)  
            hc595_shift(number[counter % 10])
            
            clearDisplay()
            pickDigit(1)
            hc595_shift(number[counter % 100//10])

            clearDisplay()
            pickDigit(2)
            hc595_shift(number[counter % 1000//100])

            clearDisplay()
            pickDigit(3)
            hc595_shift(number[counter % 10000//1000])


    def setup():
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(SDI, GPIO.OUT)
        GPIO.setup(RCLK, GPIO.OUT)
        GPIO.setup(SRCLK, GPIO.OUT)
        for i in placePin:
            GPIO.setup(i, GPIO.OUT)
        global timer1
        timer1 = threading.Timer(1.0, timer)  
        timer1.start()       

    def destroy():   # When "Ctrl+C" is pressed, the function is executed.
        global timer1
        GPIO.cleanup()
        timer1.cancel()  # cancel the timer

    if __name__ == '__main__':  # Program starting from here
        setup()
        try:
            loop()
        except KeyboardInterrupt:
            destroy()

**コードの説明**

.. code-block:: python

    placePin = (10, 22, 27, 17)

これらの4つのピンは、4桁の7セグメントディスプレイのアノードコモンピンを制御する。

.. code-block:: python

    number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)

16進数の0〜9のセグメントコード配列（アノードコモン）。

.. code-block:: python

    def clearDisplay():
        for i in range(8):
            GPIO.output(SDI, 1)
            GPIO.output(SRCLK, GPIO.HIGH)
            GPIO.output(SRCLK, GPIO.LOW)
    GPIO.output(RCLK, GPIO.HIGH)
    GPIO.output(RCLK, GPIO.LOW) 

SDIに「1」を8回書き込むと、7セグメントディスプレイの8つのLEDが消灯し、表示されたコンテンツが消去される。

.. code-block:: python

    def pickDigit(digit):
        for i in placePin:
            GPIO.output(i,GPIO.LOW)
        GPIO.output(placePin[digit], GPIO.HIGH)

値の場所を選択する。毎回有効な場所は1つだけである。有効な場所はhighに書き込まれる。

.. code-block:: python

    def loop():
        global counter                    
        while True:
            clearDisplay() 
            pickDigit(0)  
            hc595_shift(number[counter % 10])

            clearDisplay()
            pickDigit(1)
            hc595_shift(number[counter % 100//10])

            clearDisplay()
            pickDigit(2)
            hc595_shift(number[counter % 1000//100])

            clearDisplay()
            pickDigit(3)
            hc595_shift(number[counter % 10000//1000])

この機能は、4桁の7セグメントディスプレイに表示される番号を設定するために使用される。

まず、4番目のセグメントディスプレイを開始し、1桁の数字を書き込む。次に、3番目のセグメントディスプレイを開始し、10桁の数字を入力する。その後、2番目と1番目のセグメントディスプレイをそれぞれ開始し、それぞれ数百桁と数千桁を書き込む。リフレッシュ速度が非常に速いため、完全な4桁のディスプレイが表示される。

.. code-block:: python

    timer1 = threading.Timer(1.0, timer)  
    timer1.start()  

モジュール、スレッドはPythonの一般的なスレッドモジュールであり、タイマーはそのサブクラスである。コードのプロトタイプは次のとおりです：

.. code-block:: python

    class threading.Timer(interval, function, args=[], kwargs={})

間隔の後、関数が実行される。ここでは、間隔は1.0、関数は ``timer()`` である。 ``start()`` は、タイマーがこの時点で開始することを意味する。

.. code-block:: python

    def timer():  
        global counter
        global timer1
        timer1 = threading.Timer(1.0, timer) 
        timer1.start()  
        counter += 1
        print("%d" % counter)

Timerが1.0秒に達すると、Timer関数が呼び出される。カウンターに1を追加すると、タイマーが再び使用されて、1秒ごとに繰り返し実行される。

現象画像
-----------------------

.. image:: media/image81.jpeg