ハードウェアの準備が整ったら、次はRP2040からMAX7219へ「点灯の指示」を送るプログラムを作成します。
MAX7219を使いこなす鍵は、3本の信号線(DIN, CLK, LOAD/CS)を使って送る16ビットのデータパケットの理解にあります。
前回 配線と回路設計 MAX7219でLチカするまで
ラズパイとMAX7219でスマートにLチカ!3本の信号線で8個のLEDを自在に操る
マイコンのピン不足を解消するLEDドライバ「MAX7219」を徹底解説!MAX7221との違いやラズパイ(RP2040)での回路設計、ノイズ対策のコツまで紹介します。あえてデコード機能を使わず、アドレス指定でLEDを1つずつ制御する「流れるLチカ」の実践ガイド。マトリクス表示への第一歩に最適です。
1. MAX7219の「共通言語」:16ビットパケットの構造
MAX7219への命令は、常に16ビット(2バイト)を1つの単位として送信します 。この16個のビットには、それぞれ役割が決まっています 22。
- D15~D12:使用しないビット(任意の値でOK) 。
- D11~D8:レジスタアドレス(命令を届ける「住所」) 。
- D7~D0:データ(光らせるパターンなどの「内容」) 。
データは最上位ビット(MSB)であるD15から順番に送るのがルールです 。
2. 制御を始める前の「4つの初期化命令」
MAX7219は、電源を入れた直後は全ての表示が消えた「シャットダウンモード」になっています 。LEDを光らせる前に、まず以下の4つのレジスタに設定値を送る「儀式」が必要です。
| 設定項目 | アドレス(HEX) | 設定値(HEX) | 理由・効果 |
| シャットダウン解除 | 0x0C | 0x01 | デバイスを通常動作モードに移行させます 。 |
| デコードモード | 0x09 | 0x00 | 今回は7セグ数字ではなく、LEDを個別に制御するため「デコードなし」に設定します 。 |
| 輝度(明るさ) | 0x0A | 0x03 | 16段階で明るさを調整できます。今回はテスト用に低めに設定します 。 |
| スキャン制限 | 0x0B | 0x00 | 表示する桁数を指定します。今回は「Digit 0」の1桁分(LED8個)だけを使用します 。 |
3. アドレス直接指定でLEDを操作する
「デコードなしモード」に設定した場合、各桁のレジスタに書き込むデータの各ビットが、接続された8個のLEDと1対1で対応します 。
今回は「Digit 0(アドレス 0x01)」を使用しているため、このレジスタに送るデータの各ビットとLED(セグメントピン)の対応は以下の通りです 。
- 対応関係(D7〜D0):
- D7: DP(ドット)
- D6: SEG A
- D5: SEG B
- D4: SEG C
- D3: SEG D
- D2: SEG E
- D1: SEG F
- D0: SEG G
例えば、Digit 0に接続したLEDのうち「SEG A」と「SEG B」だけを光らせたい場合は、D6とD5を 1 にしたバイナリデータ 0b01100000 をアドレス 0x01 へ送信します。
4. RP2040での実装ロジック
RP2040でプログラムを書く際のポイントは、SPI通信のタイミングとデータの合成です。
データの合成
アドレス(8ビット)とデータ(8ビット)を合体させて、16ビットの数値を作ります。
# 例:アドレス0x01(Digit0)に、データ0xFF(全点灯)を送る場合
spi.write(bytes([0x01, 0xFF]))LOAD(CS)ピンの制御
MAX7219は、LOAD(またはCS)ピンが立ち上がった瞬間にデータを内部レジスタにラッチ(保持)します 。
- 通信開始前に LOADピンをLow にする 。
- SPIで 16ビット分 のデータを送り出す。
- 送信完了後、 LOADピンをHigh に戻す 。
この手順を守ることで、狙った通りのタイミングでLEDが点灯します。
ウェーブ発光のプログラムサンプル
circuitpytyhon で書き込んだ、spi通信でウェーブ発行させるプログラムの例です。
import board
import busio
import digitalio
import analogio
import time
# --- 1. SPI/CSの初期化 ---
spi = busio.SPI(board.GP2, MOSI=board.GP3)
while not spi.try_lock():
pass
spi.configure(baudrate=1000000, polarity=0, phase=0)
spi.unlock()
cs = digitalio.DigitalInOut(board.GP4)
cs.direction = digitalio.Direction.OUTPUT
cs.value = True
def write_reg(reg, data):
while not spi.try_lock():
pass
try:
cs.value = False
time.sleep(0.001)
spi.write(bytes([reg, data]))
time.sleep(0.001)
cs.value = True
time.sleep(0.001)
finally:
spi.unlock()
# --- 2. MAX7219 初期化シーケンス ---
print("Initializing MAX7219...")
write_reg(0x0F, 0x00) # ディスプレイテストOFF
write_reg(0x0C, 0x01) # 通常動作モード
write_reg(0x09, 0x00) # デコードモード: 無効
write_reg(0x0B, 0x00) # スキャンリミット: Digit 0 のみ
write_reg(0x0A, 0x03) # 輝度設定 (0x00 - 0x0F)
# 一旦すべて消灯 (Digit 0)
write_reg(0x01, 0x00)
print("Starting Sequential Lighting (A to G)...")
# 点灯させたいセグメントのリスト (A, B, C, D, E, F, G)
segments = [
0x01, # A
0x02, # B
0x04, # C
0x08, # D
0x10, # E
0x20, # F
0x40, # G
0x80 # DP
]
# --- 3. メインループ ---
try:
while True:
for seg_data in segments:
# 指定したセグメントのみを点灯
write_reg(0x01, seg_data)
time.sleep(0.3) # 0.3秒間隔で切り替え
except KeyboardInterrupt:
# 終了時に消灯
write_reg(0x01, 0x00)
write_reg(0x0C, 0x00)
print("Program stopped.")
まとめ:これで自由自在!
一度初期設定を済ませてしまえば、あとはループ処理の中で「Digit 0」レジスタに送るビットをずらしていくだけで、小気味よく流れるLチカが実現できます。
2列以上の操作をしたいときは、spi.write(bytes([0x01, 0xFF]))のアドレス を変更すればよく、2列めは0x02、3列目は0X03、8列目は0x08とすることで列を指定できます。
# 2行3列目(7SEGなら2桁目の3つ目のセグメント)を光らせたいとき
write_reg(0x02, 0x04)
# 5行8列目の場合
write_reg(0x05, 0x80)
# 5行目の3から8番目全部点灯させたいとき
# data 0b11111100 -> 0xfc
write_reg(0x05, 0xfc)アドレス直接指定の仕組みを理解すると、マトリクスLEDを使った複雑なアニメーションや、独自のアイコン表示など、活用の幅がぐっと広がります。ぜひ、色々な点灯パターンを試してみてください!
2 記事
ラズパイでLED制御(max7219)
マトリクスLEDや複数行の7セグのLED制御が出来るチップMAX7219をラズパイを用いたSPI通信で制御します。
ここまで読んでいただきありがとうございます。
では、次の記事で。 lumenHero