部品屋根性(9) 7セグLED、割り込みでダイナミック駆動

Joseph Halfmoon

毎度毎度、馬鹿なバグがお約束になっておりますが、へい、今回もやってしまいました。もうデバイスを疑ったりしませんよ、みんな自分が悪いのです。自分で作ってしまうのだけれど、自分では予想していないもの、バグです。さて前回は一桁の7セグLEDでしたが、今回は四桁の7セグLEDです。タイマ割り込みでダイナミック駆動するという趣向。

※「部品屋根性」投稿順Indexはこちら

今回使用の4桁7セグLEDは、例の中華部品キットの中にあったアイキャッチ画像のものです。例によって付属CDの中の4桁7セグLEDのデータシートには会社名なく、あまつさえ、16ピンの結線図の横に12ピンの外形図があったりと、ツッコミどころはあるものの、その辺はもう慣れました。スルー。意外と使えるのが、若干残念な日本語の説明書であります。必要なのは、アノードコモンなのか、カソードコモンなのかの種別と、端子配置です。書いてありました。アノードコモンのタイプのようです。一応、Vf測って現物で確認、OKであります。

前回の1桁の7セグLEDはカソードコモンだったので、方向逆です。プラス、マイナス反転させる感じでブレッドボード上に回路を作ります。このタイプの4桁の7セグLEDの場合、

  • 各桁毎、全セグメントのアノードが共通
  • 4桁のaからdpまでの同一セグメントのカソードも共通

であります。というわけでスタティックに駆動したのでは4桁に異なる表示はできませぬ。各桁毎にまず表示すべきデータをカソード側に印加し、印加したタイミングでその桁のアノードだけを駆動する、と。すると1桁だけ所望の表示が光ります。素早く次の桁で同じことをやり、という塩梅で「素早く」各桁を駆動しつづければ、人の目にはちゃんと4桁表示されているように見える、という方式であります。

全てのセグメントに1対1で端子を割り振るのに比べたら遥かに結線数は少なくて済みます。信号数たかだか12本。しかし、ブレッドボード上、ジャンパ線はこんな感じになりました。

4桁7セグLED ブレッドボード上テスト回路配線汚い。後で何とか綺麗にまとめたいところです。駆動するのは、例によってRISC-V搭載32ビットマイコンGD32VF103、seeed社製のボードです。GD32-SDK利用。カソード側は、74HC595を使いマイコンからはシリアルでセグメント毎の点灯データを送り、595でシリパラ変換して表示という「定番」な感じです。

既にGD32VF103のTIMER5を使って、1000分の1秒毎にタイマ割り込みがかかるようになっています。呼ばれる度に1桁ずつ表示することにしました。すると250分の1秒毎に全四桁表示されることになります。まあ、人の目には「とまらない」筈の速さ。

割り込みハンドラの中で呼んでいる表示ルーチンは以下のとおり。既にスタティック駆動の回で「実績」のある7セグの表示パタン点灯ルーチンを呼び出しております(実はそれがトラブルの元だった。。。)

void dynamicDisplay7Seg() {
    gpio_bit_reset(GPIOC, GPIO_PIN_0);
    gpio_bit_reset(GPIOC, GPIO_PIN_1);
    gpio_bit_reset(GPIOC, GPIO_PIN_2);
    gpio_bit_reset(GPIOC, GPIO_PIN_7);
    enableOE(LED7_OD); //DISABLE OUTPUT
    sendShiftRegister( displayData[ displayIndex++ ]);
    enableOE(LED7_OE); //ENABLE OUTPUT
    switch (displayIndex) {
        case 1:
            gpio_bit_set(GPIOC, GPIO_PIN_0);
            break;
        case 2:
            gpio_bit_set(GPIOC, GPIO_PIN_1);
            break;
        case 3:
            gpio_bit_set(GPIOC, GPIO_PIN_2);
            break;
        default:
            gpio_bit_set(GPIOC, GPIO_PIN_7);
            break;
    }
    displayIndex = (displayIndex > 3) ? 0 : displayIndex;
}

割り込みハンドラ自体は、非常に簡単であります。以下のとおり。

void TIMER5_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP)){
        timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
        dynamicDisplay7Seg();
    }
}

こんな簡単なものなら、

一発で動く筈

と思ったら、お約束どおり駄目でした。何かね、変なパターンが表示されるのです。だから回路的には動いていそう。もうデバイスを疑ったりしませんよ。まずは「汚い」配線のチェックです。

でもね、大丈夫なんだこれが。よくこんな配線間違えないな、と悪態をついてもやったのは自分。はてさて。

結局のところ、またまた、お約束どおりでソフトでした。2つのバグが重なって、妙なパターンを表示していました。

スタティック駆動で「実績」のある筈の下位関数、カソードコモンのつもりで書いていました。用は点灯のとき1(ハイ)を出力するようにしていました。ところが、今回のデバイスはアノードコモンです。74HC595の側は0(ロー)を出力しないと点灯しません。まずこれでパターン反転。

さらに、自分で作った下位関数の仕様を忘れていました。4桁点灯のため、4桁分の数字を記録する配列を用意し、そこに表示する数値を格納しました。そして各桁を順番に読み出し、前回すでに準備済のLEDパターン用の配列に通してパターンに変換して下位関数に渡してました。ところが、自分で作った下位関数の中でもパターン変換していました。つまりパターン変換など不要。表示したい数値そのものを与えればよかったのです。2回パターン変換して反転、簡単ですが暗号化と言えなくもない。結果、不思議な表示が現れ、途方に暮れたと。

分かってしまえば何のことはない、上のコードは直した後のものです。

ようやく、所望のとおり点灯するようになりました。ちょっとピンボケですが、明るく写せた一枚。(見た目は明るいのだけれど、ダイナミック駆動のせいか、カメラの目だとなかなか明るく写せなかったです。カメラもしょぼい。)

7セグLED 4桁ダイナミック駆動それにしても配線汚い。

部品屋根性(8) 困ったときのAnalog Discovery2 へ戻る

部品屋根性(10) PMOS、BSS84でアノードドライバ へ進む