初めてのRaspberry Pi Pico ⑨ C言語で7セグメントLEDを点灯 その1

　7セグメントLEDは八つのLEDを数字の形になるように点灯させます。桁数が増えると配線の量が加速度的に増えます。

<img width="450" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/685f6880-932f-e70d-a40a-96c1d0db4d08.png">




　専用のコントローラをつなぐ方法があり、4桁などにはHT16K33があります。ここでは、シフトレジスタ74HC595と緑色LEDを組み合わせた秋月電子通商の製品を利用します。
　　[緑色７セグメントＬＥＤシリアルドライバモジュール　完成品](https://akizukidenshi.com/catalog/g/gM-12570/)

　6個つなげて6桁の7セグメントLEDを作りました。6桁は市販品にありません。

<img width="80" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/3d15a042-9a45-8c46-a16b-fec9ce9869fb.png">



###接続

　74HC595への書き込みは、SPIのタイミングが利用できます。LATCHはCE（CS）と同じタイミングです。SCK（GP6）はクロックで、データを送るSDIはMOSI（GP7）につなぎます。
　[こちらの資料](http://akizukidenshi.com/download/ds/akizuki/AE-7SEG-BOARD_a2.pdf)が詳しいです。

　PicoのMOSIから最初のLEDのSDIにデータを入れ、SDOからそのままデータを次のLEDのSDIへ送ります。これを6個分繰り返します。
　LATCH、SCK、GND、3.3Vはそれぞれ全部共通につなぎます。
![7seg-6d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/32898dfe-675d-770e-7940-5fccea3ff4e9.png)



###プログラム
　前回のblinkと同様に、worksフォルダにプログラムを作ります。LED7seg_74HC595フォルダを作ります。worksフォルダにあるCMakeLists.txtを次のように変更します。変更点は、最後の行にフォルダを追加しました。

```shell
cmake_minimum_required(VERSION 3.12)

# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)

project(pico_examples C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})

# Initialize the SDK
pico_sdk_init()

include(example_auto_set_url.cmake)
# Add blink example
add_subdirectory(blink)
add_subdirectory(cmake)
add_subdirectory(LED7seg_74HC595)
```
　LED7seg_74HC595フォルダの中にはLED7seg_74HC595.cとCMakeLists.txtの二つのファイルを作ります。CMakeLists.txtの内容です。blinkのときと異なるのは、hardware_spiのライブラリを追加したところです。

```shell
add_executable(LED7seg_74HC595
        LED7seg_74HC595.c
        )

# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(LED7seg_74HC595 pico_stdlib  hardware_spi)

# create map/bin/hex file etc.
pico_add_extra_outputs(LED7seg_74HC595)

# add url via pico_set_program_url
example_auto_set_url(LED7seg_74HC595)
```



　　[超精密温度計の製作⑤7セグLEDに表示](https://www.denshi.club/cookbook/arduino/esp32/57led.html)の記事を参照してプログラムを作ります。
　SPIバスのチップ・セレクト信号CSは、プログラムで制御します。デフォルトはHighで、転送開始前にLowに落とし、転送が終わるとHighに戻します。

　LED7seg_74HC595.cのソースです。

```cpp
　spi_write_blocking(SPI_PORT, XXdataXX, 1);
```

で転送すると一番左のLEDにデータXXdataXXが書き込まれます。同じく2回目のデータを転送すると、最初のデータは左に押し出されて、2桁のLEDが表示されます。6回転送すると、全桁の表示が終わります。

```cpp
/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/spi.h"

#define PIN_CS   5
#define PIN_SCK  6
#define PIN_MOSI 7

#define SPI_PORT spi0
#define READ_BIT 0x80

const uint8_t digits[] = {
  0b00111111, // 0
  0b00000110, // 1
  0b01011011, // 2
  0b01001111, // 3
  0b01100110, // 4
  0b01101101, // 5
  0b01111101, // 6
  0b00000111, // 7
  0b01111111, // 8
  0b01101111, // 9
};
const uint8_t  dot   = 0b10000000;
const uint8_t  blank = 0b00000000;
const uint8_t  minus = 0b01000000;  // -

static inline void cs_select() {
    asm volatile("nop \n nop \n nop");
    gpio_put(PIN_CS, 0);  // Active low
    asm volatile("nop \n nop \n nop");
}

static inline void cs_deselect() {
    asm volatile("nop \n nop \n nop");
    gpio_put(PIN_CS, 1);
    asm volatile("nop \n nop \n nop");
}

static void write_register(uint8_t reg, uint8_t data) {
    uint8_t buf[2];
    buf[0] = reg & 0x7f;  // remove read bit as this is a write
    buf[1] = data;
    cs_select();
    spi_write_blocking(SPI_PORT, buf, 2);
    cs_deselect();
    sleep_ms(10);
}

void clearLED(){
    // clear all segments
    cs_select();
    spi_write_blocking(SPI_PORT, &blank, 1);
    spi_write_blocking(SPI_PORT, &blank, 1);
    spi_write_blocking(SPI_PORT, &blank, 1);
    spi_write_blocking(SPI_PORT, &blank, 1);
    spi_write_blocking(SPI_PORT, &blank, 1);
    spi_write_blocking(SPI_PORT, &blank, 1);
    cs_deselect();
}
void setup_SPI(){
    // This example will use SPI0 at 0.5MHz.
    spi_init(SPI_PORT, 500 * 1000);
    gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
    gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);

    // Chip select is active-low, so we'll initialise it to a driven-high state
    gpio_init(PIN_CS);
    gpio_set_dir(PIN_CS, GPIO_OUT);
    gpio_put(PIN_CS, 1);
}

int main() {
    stdio_init_all();

    printf("\nHello, 7SegmentLED via SPI...\n");
    setup_SPI();
    clearLED();

  float Temp=-1.4567;
  // Serial.println(Temp,4);
  char sTemp[8];
  snprintf(sTemp, 8, "%f", Temp);
  puts(sTemp);
  int seisuu;
  for (int i=0; i<8; i=i+1){
      //printf("moji %d ",sTemp[i]);
      if (sTemp[i] == 46){        // 46=.
          //printf("seisuu %d\n",i);
          seisuu = i;
          break;
      }
  }
 
  cs_select();
  if (Temp > 0.0) {
    if (seisuu == 2) {  // 23.4567
      spi_write_blocking(SPI_PORT, &digits[sTemp[0]-48], 1);
      uint8_t pp = digits[sTemp[1]-48] ^ dot;
      spi_write_blocking(SPI_PORT, &pp, 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[3]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[4]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[5]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[6]-48], 1);
    }
    if (seisuu == 1) {     // 1.2345
      spi_write_blocking(SPI_PORT, &blank, 1); // blank
      uint8_t pp = digits[sTemp[0]-48] ^ dot;
      spi_write_blocking(SPI_PORT, &pp, 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[2]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[3]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[4]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[5]-48], 1);
    }
  }else{  // minus
    if (seisuu == 3) {     // -12.3456
      spi_write_blocking(SPI_PORT, &minus, 1); // -
      uint8_t pp = digits[sTemp[2] - 48] ^ dot;
      spi_write_blocking(SPI_PORT, &digits[sTemp[1]-48], 1);
      spi_write_blocking(SPI_PORT, &pp, 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[4]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[5]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[6]-48], 1);
    }
    if (seisuu == 2) {     // -1.2222
      spi_write_blocking(SPI_PORT, &blank, 1); // blank
      spi_write_blocking(SPI_PORT, &minus, 1); // -
      uint8_t pp = digits[sTemp[1]-48] ^ dot;
      spi_write_blocking(SPI_PORT, &pp, 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[3]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[4]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[5]-48], 1);
      spi_write_blocking(SPI_PORT, &digits[sTemp[6]-48], 1);   
    }
  }
  cs_deselect();
  sleep_ms(2000);;

    return 0;
}
```
　/home/pi/pico/works/buildに移動します。

```shell
cmake ..
```
　/home/pi/pico/works/build/LED7seg_74HC595に移動します。

```shell
make -j4
```

　ラズパイのデスクトップにPico（PRI-RP2）をマウントするために、BOOTSELボタンを押したままUSBケーブルをつなげました（抜き差し）。
　できたLED7seg_74HC585.uf2をPRI-RP2ドライブへドロップします。

　Temp=-1.4567がテスト・データです。
![IMGP0182.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/864900b0-d739-36e3-b797-83830e1d6f39.png)

（※）LEDの合計の消費電流がいくらかは不明です。輝度は十分とれています。Picoの3.3V端子からどのくらいの電流が流せるかは不明（300mA？）です。LEDを全部点灯させたときに一番電流が流れます。Pico以外から3.3Vの電源を取るのが望ましいです。