akira.keiのアイコン画像
akira.kei 2026年11月06日作成 (2026年11月08日更新) © MIT
製作品 製作品 閲覧数 55
akira.kei 2026年11月06日作成 (2026年11月08日更新) © MIT 製作品 製作品 閲覧数 55

大型7セグメントLEDをI2C接続(その1)

<前の記事 : 次の記事>


大型7セグメントLED

ここに動画が表示されます

秋月で買って死蔵していた大型の7セグメントLEDをなんとなく使う気になったので、頑張ってみた。死蔵していたのは12V駆動であることを把握してなかったためだ。また当然ながら遠くからでも見えるような明るさにするには多くの電流を流す必要があり、マイコンの端子だけでは太刀打ちできないからだ。

複数桁表示のために

昔はもうちょっと安かったのかセールだったのか覚えていないが、4桁表示ができるように4つ買ってある。ダイナミック点灯させようと思うと10本の配線を互いに接続しあうことになってちょっと面倒臭いので、スタティック点灯させることにした。1桁分で1つのマイコンを割り当て、4つのマイコンをI2C接続でバス接続することにした。つまり、1つの7セグメントLEDの裏にPICマイコンを接続し、上位のArduinoやRaspberry Pi Pico WなどからGND /VCC/SDA/SCLと12V電源を接続するだけにするわけだ。これなら1桁あたり5〜6本だけ繋げば良いのでだいぶ楽になる。
HWはこんな感じで写真の右がPIC16F1823、右がTBD62084APGだ。最大定格が20mAなので、10mA程度を流すよう電流制限抵抗を470Ωくらいにしてある。
駆動基板

PIC側の処理

PIC 16F1823側の処理は、

  1. I2Cで1バイトを受け取って保管し、フラグを立てる
  2. メインループでフラグが立ってるか確認したら、保管したバイトを表示ルーチンに
  3. 表示ルーチンでは各ビットに対応してON/OFFを出力
  4. もし回答要求が来るなら保管している値を返す

というこれだけだ。
例によってMCC Classicで各部設定を行ったが、また地雷が埋まっていた。MCCでスレーブアドレスを設定してもちゃんとソースに反映されない、というバグ?があった。結局はi2c_slave.cの中身を以下のように指定の値を直接編集した。

#define I2C_SLAVE_ADDRESS 21

1桁目は21として2桁から4桁目を22から24として、アドレス以外は全く同じファームウェアを書き込む。main関数は以下の様になる。

void main(void) { SYSTEM_Initialize(); I2C_Open(); I2C_SlaveSetReadIntHandler(My_I2C_Receive_Callback); I2C_SlaveSetWriteIntHandler(My_I2C_Transmit_Callback); INTERRUPT_GlobalInterruptEnable(); INTERRUPT_PeripheralInterruptEnable(); while (1) { if(flag) { flag=0; display(segments); } } }

表示関数dispは脳筋だ。ビット位置に対応してGPIOを上げたり下げたりする。MSBはセグメントPで順にAからGまで合計8ビットのGPIO制御を行う。7セグメントLEDはアノードコモンであり、アノードは常に12V電源に接続し、各ビットをHighにすればシンクドライバーの出力がGNDに落ちて対応するセグメントが点灯する。
シンクドライバを使わないでマイコン端子をそのまま使う(非推奨)ならSetHigh()とSetLow()を入れ替える必要があるが、この場合は電流値を1mA程度にする必要がある。

void display(uint8_t seg) { if(seg&0b01000000) A1_SetHigh(); else A1_SetLow(); if(seg&0b00100000) B2_SetHigh(); else B2_SetLow(); if(seg&0b00010000) C3_SetHigh(); else C3_SetLow(); if(seg&0b00001000) D4_SetHigh(); else D4_SetLow(); if(seg&0b00000100) E5_SetHigh(); else E5_SetLow(); if(seg&0b00000010) F6_SetHigh(); else F6_SetLow(); if(seg&0b00000001) G7_SetHigh(); else G7_SetLow(); if(seg&0b10000000) P8_SetHigh(); else P8_SetLow(); }

また、I2C通信の割り込みルーチンは以下の様に非常にシンプルになっている。

volatile uint8_t segments = 0; volatile uint8_t flag=0; void My_I2C_Receive_Callback(void) { segments = I2C_Read(); LED_Toggle(); flag=1; } void My_I2C_Transmit_Callback(void) { I2C_Write(segments); }

上位側の表示制御

Arduinoを使った場合のスケッチは、例えば以下の様になる。ループ内ではエラー処理は省略してある。

#include <Wire.h> const int SLAVE_ADDRESS = 21; byte cnt=0; byte segments[]={ 0b1111110, 0b0110000, 0b1101101, 0b1111001, 0b0110011, 0b1011011, 0b1011111, 0b1110010, 0b1111111, 0b1111011, }; void setup() { Wire.begin(); Serial.begin(115200); while (!Serial); Serial.println("I2C Direct Master Started"); } void loop() { Wire.beginTransmission(SLAVE_ADDRESS); Wire.write(segments[cnt]); byte error = Wire.endTransmission(); Serial.print("Write Success: sent "); Serial.println(segments[cnt]); delay(100); byte bytesReceived = Wire.requestFrom(SLAVE_ADDRESS, 1); byte val = Wire.read(); Serial.print("Read Success, received: "); Serial.println(val); cnt++; if(cnt>9) cnt=0; Serial.println(); delay(1000); }

<前の記事 : 次の記事>

akira.keiのアイコン画像
機械系エンジニアだが電子工作を趣味としている。週末はひとりバーベキュー。
ログインしてコメントを投稿する