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

専用のコントローラをつなぐ方法があり、4桁などにはHT16K33があります。ここでは、シフトレジスタ74HC595と緑色LEDを組み合わせた秋月電子通商の製品を利用します。
緑色7セグメントLEDシリアルドライバモジュール 完成品
6個つなげて6桁の7セグメントLEDを作りました。6桁は市販品にありません。

接続
74HC595への書き込みは、SPIのタイミングが利用できます。LATCHはCE(CS)と同じタイミングです。SCK(GP6)はクロックで、データを送るSDIはMOSI(GP7)につなぎます。
こちらの資料が詳しいです。
PicoのMOSIから最初のLEDのSDIにデータを入れ、SDOからそのままデータを次のLEDのSDIへ送ります。これを6個分繰り返します。
LATCH、SCK、GND、3.3Vはそれぞれ全部共通につなぎます。
プログラム
前回のblinkと同様に、worksフォルダにプログラムを作ります。LED7seg_74HC595フォルダを作ります。worksフォルダにあるCMakeLists.txtを次のように変更します。変更点は、最後の行にフォルダを追加しました。
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のライブラリを追加したところです。
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に表示の記事を参照してプログラムを作ります。
SPIバスのチップ・セレクト信号CSは、プログラムで制御します。デフォルトはHighで、転送開始前にLowに落とし、転送が終わるとHighに戻します。
LED7seg_74HC595.cのソースです。
spi_write_blocking(SPI_PORT, XXdataXX, 1);
で転送すると一番左のLEDにデータXXdataXXが書き込まれます。同じく2回目のデータを転送すると、最初のデータは左に押し出されて、2桁のLEDが表示されます。6回転送すると、全桁の表示が終わります。
/**
* 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に移動します。
cmake ..
/home/pi/pico/works/build/LED7seg_74HC595に移動します。
make -j4
ラズパイのデスクトップにPico(PRI-RP2)をマウントするために、BOOTSELボタンを押したままUSBケーブルをつなげました(抜き差し)。
できたLED7seg_74HC585.uf2をPRI-RP2ドライブへドロップします。
(※)LEDの合計の消費電流がいくらかは不明です。輝度は十分とれています。Picoの3.3V端子からどのくらいの電流が流せるかは不明(300mA?)です。LEDを全部点灯させたときに一番電流が流れます。Pico以外から3.3Vの電源を取るのが望ましいです。