FPGA & Verilog入門本『TANG PriMERで始める FPGA & Verilog入門』頒布中!

ニキシー管時計 (with Arduino) 製作記 【Part 7】

スポンサーリンク
Arduino

ニキシー管時計製作記 Part 7です。

今回は、前回までの回路・ダイナミック点灯制御を踏まえて、時計として動かすためのプログラムの方式についてご紹介します。

ニキシー管 IN-12B 6個セット
clockwork
売り上げランキング: 129,658
スポンサーリンク

Arduino UNOを使ったデジタル時計の設計方針

前回までの回路とダイナミック点灯の内容を踏まえまして、あの回路をデジタル時計たらしめるプログラムの方式を考えます。

プログラムを設計するにあたって、今回の製作における設計方針を決めました。

  • Arduinoのデフォルトライブラリのみを使用する
  • オブジェクト指向の勉強としてC++の「クラス」等を積極的に使う

これはデジタル時計製作に必要な設計方針というよりも、自分に課す縛りと言えます。

このため、プログラムの参考にはならないかもしれません

Arduinoのデフォルトライブラリのみを使用する

Arduinoというのはマイコンを簡単に使用できるように色々と丸め込まれています。マイコンとして見ればAtmega328Pであり、8bit CPUと言えどマイコン自体の機能を色々持っています。Arduinoは丸め込まれている故に、Arduinoとしては見えないマイコンの機能があります(実は裏で動いていることもあります)。

Arduinoの開発環境であっても、やろうとしたらレジスタを直接たたいたりアセンブラでプログラムできたりします。しかし、そういったことをやり出すとArduinoを使う意味は無く、AVRマイコンの開発環境で開発したほうが良いのではないかと思えてきます。

よって、Arduinoの標準ライブラリ(標準関数等)のみを使って、Arduinoとして使おうと考えました。

(自分がAVRマイコンとして開発出来ないとは大きな声では言えません。)

また、製作を開始した時点で製作記を書くことを考えていました。使用するハードルが低いArduinoで製作することによって「ニキシー管 × Arduino」としてニキシー管時計の製作に興味をもっている方の参考になる製作記になるのではないかとも考えていました。

標準関数のみでなんとか時計を作ることができるといった意味では、ご参考になれば幸いです。

オブジェクト指向の勉強としてC++の「クラス」等を積極的に使う

Arduino IDEでコードを書く際にはあまり意識しなくても良い様になっていますが、裏は「C++」になっています。CとC++の違いと言えば、ひとつはC++はオブジェクト指向言語だということです。

学生時代からC言語の手続き型のプログラムしか書いたことがなく、オブジェクト指向はなんだかわからないものとして避けがちでした。しかし最近では組み込みにもオブジェクト指向を使う動きを見聞きしまして、オブジェクト指向でマイコンのプログラムを書くことに挑戦しようと思った次第です。その挑戦の機会が今回のニキシー管時計の製作です。

デフォルトライブラリのみを使用する苦しみ(楽しみ)

マイコンでダイナミック点灯制御を用いてデジタル時計を作ろうとした場合、「タイマ割り込み」という機能を使うことが良策と考えられます。タイマ割り込みという機能は、簡単に言うと「決められた時間ごとに定期的に処理を行う」ということを可能にするものです。(説明しておきながら自分が上手く使えるか?というと、そうではありません。)

つまり、ダイナミック点灯として点灯する桁を変更する処理を、前回検討したダイナミック点灯の制御時間に従って定期的に行うことが可能です。この機能を使えば忙しいダイナミック点灯をしながら、デジタル時計としての機能を盛り込むことも簡単そうです。

しかし、このタイマ割り込みの機能はArduinoのデフォルトライブラリとしては提供されていません。

ではどうするかというと、別の方法を考えることになります。これは苦しいけど楽しいみたいな感覚になります。

プログラムは上から下へ、やることがたくさん

さて、プログラムの動きについて考えます。

ニキシー管時計として動かすプログラムはArduinoのコードでは「loop」関数でグルグル回っています。基本的にはプログラムを書いた順番に上から下へ処理が行われます。

このグルグルとループする中でArduinoはやることがたくさんあります。

  • ダイナミック点灯
    • 表示する桁に応じたアノード制御
    • 表示する桁に応じたニキシー管ドライバICの制御
  • スイッチの押下を判断
    • チャタリング対策のポーリング
  • 1秒毎に秒情報を更新
    • RTCから出力される1秒毎の信号をポーリング
    • 信号が入っていたら秒情報を更新

1ループの中でこれらの仕事をします。

ダイナミック点灯

これは前回ご紹介しました。チラついて見えないように、高速でニキシー管を点灯します。

スイッチの押下を判断

これは時間設定をするためのスイッチが押されているかどうかという判断をする処理です。

スイッチの読み取り時に問題となるのが「チャタリング」という現象です。1度スイッチを押したはずが、スイッチの接点がバウンドしてしまって複数回押された様に検出されるものです。これは誤作動につながります。この対策には「ポーリング」という方法を使います。ポーリングは、定期的にポートを確認するといった意味です。

例えばスイッチのポートを2msごとに5回読み取るポーリングをして、5回連続でON状態だったら「1回押された」と確定します。このポーリング処理を組み込みます。

1秒毎に秒情報を更新

これは、時計の秒の桁の表示を更新する処理です。

今回の回路にはRTCを入れておりまして、このICが1Hzのパルスを出力します。この1Hzをマイコンで取得して秒情報の更新をします。

ここでも前述のポーリングを使用して1Hzを読み取ります。

最優先はダイナミック点灯

やることは色々あるのですが、最優先事項はダイナミック点灯です。

なぜなら、ニキシー管の表示は時計が時計である条件であり、ダイナミック点灯が後回しにされるとチラついて見えてしまう恐れがあるからです。

前回の記事で書いたダイナミック点灯の周期で動く様に作ります。

では、その点灯周期を実現するためにどの様にプログラムを組むかを考えます。

delay関数を使う選択肢

ダイナミック点灯の1桁あたりの点灯時間について先日記事に書きましたが、数msの単位で点灯/消灯を制御します。Arduinoのデフォルトライブラリには「delayMicroseconds」というus単位のDelay処理の関数がありますので、サンプルプログラムのLチカを真似してdelay関数で点灯/消灯を制御すること考えてみます。

/***************
* 1桁分の点灯
***************/

digitalWrite(pin, HIGH);    //点灯
delayMicroseconds(2400);    //2.4ms点灯時間

digitalWrite(pin, LOW);      //消灯
delayMicroseconds( 600);    //0.6ms消灯

こうすると、1桁の表示処理だけで見ると2.4msの点灯時間のルールを守れている様に思えます。

この様にDelay関数を使用すると、Delayしている間はマイコンは他のことをしません。時間が経過することを待っています。

やることがダイナミック点灯だけならこれでも良いのですが、他にもスイッチのポーリング等をします。delayとdelayの間にポーリングなどの他の処理を潜り込ませることになります。

そうなると、1桁表示する3msの合間にスイッチとRTCのポーリングをするため、ポーリングの周期がダイナミック点灯の周期に依存することになります。また、合間の処理に時間がかかるとダイナミック点灯の周期が崩れます。崩れた周期のバランスを直すために、その分delayMicrosecondsで指定する時間を減らす等の調整を行うことになります。

調整をかけてダイナミック点灯さえ問題なく表示されれば、時計としての実使用上はこれでも問題が無いと思えます。しかし、今回はオブジェクト指向を取り入れるというテーマもありますので、「点灯制御」,「スイッチポーリング」,「RTCのポーリング」処理が互いにdelay関数に依存しない構成にすることを考えました。

micros関数を使う選択肢

micros」という関数は、Arduinoがプログラムを実行してから現在までの時間をus単位で取得できます。

このus単位の時間を取得して、ダイナミック点灯,ポーリング,秒情報の取得の間隔を制御することを考えました。

loop内にdelayを入れずにグルグルと回して、micros関数で時間の間隔を測り、一定間隔ごとに処理を行います。

これで、ダイナミック点灯はON時間2.4ms, OFF時間0.6ms、スイッチのポーリングは1ms毎といった間隔をそれぞれ設定しやすくなると考えました。Arduino UNOの分解能は4usということですが、ms単位にとっては充分な分解能だと思います。

しかし、タイマ割込と違ってloop関数の中で定期的に時間を測っているため、loop内で処理に時間がかかる関数があった場合にそれが0.6ms以上かかると支障が出ます。このため、充分に早くloop関数を回す様に注意する必要がありますが、実際には時計として動かす処理であれば充分に早いです。

今回はこの方法でデジタル時計を制御します。

Arduino標準関数を使って力技で時計にするといった感じですから、正統派なプログラムの参考にはならないと思われます。ご了承下さい。


今回は時計として動かすためのプログラムの方式についてご紹介しました。

方式検討の内容に留まり、実際のプログラムのソースコードが出てこなくて恐縮です。

次回以降は実際にソースコードをご紹介したいと思います。

それでは、次回もよろしくお願いします。

コメント

タイトルとURLをコピーしました