Tech:pic:gc:ftf

出典: Tariki

目次

FTF賞

単なる電光掲示板である。何かに使うかと思い、秋月で8x8 x2色のドットマトリクスLEDを注文した (安い)。これを使って今回、一連の電子工作キャッシュのFTF賞・『FTF』と取ったキャッシュのGCコードが流れるおもちゃを作ろうと思ったわけだ。

コンセプトは、部品点数の最小化である。

スーパーダイナミック(笑)点灯

単なる電光表示・および流れる表示であれば、『学会タイマー』のときにもっと複雑なものを作っている。これは、横64×縦16のドットマトリクスLEDにロータリースイッチ・ボタン3つ・圧電ブザーがついたものを16F84A (たしか) で動かしているのだが、表示部分は実は、かつて秋月で売っていた出来合いのパネルを使っている。ラッチおよびドライブトランジスタが付いたパネルなので (それでも少ない信号線数でラッチにパラレル入力するため、シリアル→パラレル変換などの回路も付加した)、LED表示部分についてはあまり考えなくてもよかった。

今回の8x8表示は、ドライブトランジスタを使わずにやってみようと思った。通常のダイナミック点灯であれば、行ごとまたは列ごとに点灯する。例えば行がアノード、列がカソードでカソードコモンで列ごとに光らせるの場合、カソード側をひとつずつ0 (残りの列は1) にしながら、行の表示内容を正論理で与える。

この場合、カソードには最大で行数(今回ならば8) だけのLEDの電流が流れこむ。ダイナミック点灯は列数分の1の時間しか光らせていないため、LEDのデータシートのいわゆる連続点灯の電流値ではなく、『最大尖頭電流』の値で光らせる。だから50mA x8行分とかの電流がカソードに流れ込むわけで、ドライブトランジスタが必要になる。

PICの1ポートの電流は25mA (流れだし・流れこみとも) なので、ドライブトランジスタを省略するとすれば、LEDをひとつずつ順番にダイナミック点灯するしかない。最大尖頭電流はLEDの都合なので、1つのLEDを光らせるのに25mA以上流せない。

それから8x8 x2色と書いたが、PIC16F627Aを使ったので、出力に使えるピンはRA0-4、6-7とRB0-7の15本である (RA5は入力オンリーである。変態マイコンとよばれる所以である(笑))。だから行か列をひとつ減らすしかない。まあ文字表示なので、行を7行にしてもあまり違和感はないだろう (ASCII文字だと縦長のほうが一般的で、列を減らしたほうがよさそうだが、横に流れる表示にしたいので、列は8列フルにあったほうが良い)。また2色点灯もさらに8本のピンが必要になるため諦めて、輝度が高い赤だけにする。

単純計算で平均25mA÷(8x7) =0.5mA未満で光らせたときのLED表示って、はたして見えるものなのだろうか。心のなかで勝手に『スーパー(笑)ダイナミック点灯』と名付けることにする。

バージョン1: RA4の罠

テスト回路を作ってみた。テスト回路といっても、PICとパスコン・CR3032の電池ホルダのほかは電流制限抵抗7本 (数を減らしたいからこれは行に入れる)とLEDだけなので、まあ実機だ(笑)。回路図はあまりに簡単なので略す (いうまでもなく本数が少ない列 = PORTA側をアノード(正論理)とし制限抵抗を入れた。PORTB側がカソード(負論理)だ)。

試しに光らせてみる。いつもこのドットマトリクスLEDはどちらが右でどちらが左か、どちらが上でどちらが下かわからなくなるのだが、別に納品に制限がある仕事じゃなし、てきとーに作ってみて光らせて裏返しだったらソフトで反転すればよい。上下逆なら、製品の上下が逆だったことにすればよいだけだ(笑)。行と列を間違ったら上記目標仕様から流れる文字が悲しくなるわけであるが、その場合は90度回転させて使えばよいのだ(笑)。

さて行と列は間違えずに作って、1個だけ光らせてみてMSBとLSBのどっちがどっちか確かめ、ダイナミック表示のルーチン作成にかかる。

ソフト作成当初から絶対にミスしてはならないことがある。それは、同時に2つ以上のLEDを光らせると、PICが壊れてしまうということだ(笑)。ちなみにソフトのバグでコンピュータのハードを壊せる、という機会はきょうびなかなかない。一昔前ならCRTディスプレイの垂直同期の周波数を誤ると、ディスプレイから煙が出た。いやふつーのPCユーザはなかなかいじる機会がないのだが、UNIX端末でX Window systemの設定ファイルにはこれを書く。ソフトでハードウェアを壊せたわけだ。

ここではPICのエミュレータが絶対的に役に立つ。ダイナミック表示のルーチンはTMR0の割り込みに集約して書いたので、開発当初にテストルーチンを書いたもので、そのまま最後までいける。RAM上に8バイトのスクリーンRAM(笑)を取って、1画面(笑)リフレッシュ時間がトータルで10msec程度になるようにTMR0割り込みをかける。次に表示させるLEDの行・列番号の、スクリーンRAMのバイト・ビット位置を読み取って1ビットだけ1のマスク(正論理のPORTA)・全0または1ビットだけ0のマスク(負論理のPORTB)を作り出せば、間違って2つのLEDを点灯させることはない。

テストパターンをスクリーンRAMに書き込み、エミュレータでPORTA・PORTBのパターンを作るところにbreak pointを設定してテストする。ここでPORTAが『00101000』とか、PORTBが『10111101』とか、2ビット以上1/0になっていなければOKである。

結果的に、LEDは平均0.5mAを流してスタティック点灯したときよりも、ずっと明るく見えた。というか、ひとつのLEDのみを点灯した時よりもせいぜい半分くらいにしかなっていないような気がする。目の錯覚なのか、それともLEDの光量が電流に対して線形でないからなのかわからない。

ところが、RA4の行が光らない。PICの各ピンは、やれPWMだのコンパレータだのなんとかタイマの入力やクロックを出したり、さまざまな役割をする。変態マイコンと呼ばれる所以である(笑)。だから自分が作った回路に合わせてポートの初期化をする部分を書くのが、いちばん嫌だ。

今回も、RA4に割り当てられている余計な働きを全部切っているかどうかチェックしてみる。ふと、マニュアルにRA4はオープンドレインである、と記述がある。そうだ、忘れていた。

つまりオープンドレインということは、電流を流し込むのはOKであるが、電流を取ることができない。PORTAが7本しか使えないから行、LEDの行はアノードだから正論理、と単純に考えていたのが裏目に出た。

PORTAとPORTBの配線を交換するとなると、ほとんど回路を作り直すのと同じである。ならばもう一台作ったほうが早い。このバージョンはもう、ハードウェアをいじるのがイヤだったので、もう一行減らすことにした(爆笑)。

なんか寸詰まりになったが、無事動くことは動いた。

スーパーダイナミック点灯の光量増加と光量等化

1つのLEDごとに1/(7x8)だけの時間を割り当て、ON/OFFさせる単純なルーチンはできた。しかし、文字パターンでは実際には全体が光っているということはなくて、全体の数分の1のLEDしか光っていない。したがって、OFFになっているLEDをスキップしたら、全体の光量を増すことができるだろう。しかしこれにはひとつ問題がある。

通常の (スーパー(笑)じゃない) ダイナミック点灯をする場合、LEDの電流制限抵抗はトランジスタじゃない側 (先の例ではアノード側) に入れる必要がある。なぜかというと、トランジスタ側に電流制限抵抗を入れてやると、ある列の点灯するLEDの数によって、明るさがまちまちになるからである。少ない数のLEDがつくときは明るく、数が増えると暗くなる。

これと同じようなことがスーパーダイナミック点灯でも起きる。ただし全体のLEDのONになっている数による。少ない数しか光らせないパターンだと、1つのLEDに回ってくる述べON時間が増える。したがって全体が明るく見えてしまう。

実はこれも、LEDのON時間と明るさが線形にならないようで、それほど神経質にならなくてもよかったのだが、ちょっとプログラムでハマってしまった (全OFFのときに次に点灯しているドットを探し求めて無限ループに入ってしまった(笑)) 機会に、光量の等価をしてみようと思ったのである。

これも話は簡単で、ONになっているLEDの最大値を決めておく (最終的には7x8の40% = 20個とした)。全画面(笑)でONの数がこの数より少ない場合は、1画面スキャンが終わったら20割り込みになるまでどこも点灯しないで待っている。20割り込みになったら次の1画面のスキャン開始である。

もし20個より多くのLEDが点灯した場合には、光量は低下していく (実際には最大で22個点灯というパターンがあったが、あまり光量が低下しているようには見えなかった)。

これで単純なルーチンよりやや、明るくすることができた。

バージョン2・PICの出力ポートをフルに使いたい

今回のFTF賞は、賞としてあげてしまうのが2個、自分用が1個で計3個作る予定だった。したがって2個目以降は、ここから述べるバージョン2とした。

バージョン2では、なんとか6行×8列のLEDを、PICのスペックぎりぎりである7行×8列にしたかった。はなしは簡単で、PORTAを負論理で使えば7本の出力が取れるはずである。しかしLEDの行はアノードであり正論理である必要がある。

解決方法は簡単であった。LEDを90度回転させればよい(爆笑)。元(というかデータシート上で)行だったアノードは列になり、PORTBを正論理(1ビットだけ1、残り0)でドライブすれば8列取れる。行(データシート上で列)はカソードになるので、PORTAを負論理で使えば、無事RA4からも1行ドライブできる。

この90度回転で、行と列、右と左、上と下はさらにわけわかんなくなった(笑)。そのうえ、えいやっと決めて書いた配置のLSBとMSBを反対に配線してしまったが、やっぱりソフトウェアで修正した。

ちなみに今回はバージョン1もバージョン2も、スクリーンのバイトは列に対応させたが、アドレスの大きいほうが左となった。別にどちらがどちらでもよいのだが、アセンブラ上に文字パターンをRETLW命令でビジュアルに書くときは、やや気持ち悪い感じになる。

;C
	RETLW	B'00100010'
	RETLW	B'01000001'
	RETLW	B'01000001'
	RETLW	B'01000001'
	RETLW	B'00111110'

	RETLW	B'00000000'
;G
	RETLW	B'00101110'
	RETLW	B'01001001'
	RETLW	B'01001001'
	RETLW	B'01000001'
	RETLW	B'00111110'

上は先頭二文字分であるが、可視化するために頭を左に90度回せば'1'が点灯ビットに見えるようになっている。

バージョン1ではこのままの配置でPORTAの行に対応した(ただしどのみちRA4とRA5は飛ばす操作が必要である)が、バージョン2ではうっかり配線ミスによりMSBとLSBが入れ替わってしまった。その場合でもスーパーダイナミック点灯では1ビットしか一度に送出しないので、送出するPORTBの行に対応した'1'をMSBから右シフトして出力パターンを作り、文字パターンが0であるか1であるかの検査用マスクは'1'をLSBから左シフトするだけである。

まとめ

とまあくだらない光るおもちゃの製作であるが、たまには変態マイコンをだましだまし、こんなハード・ソフトをスクラッチから作らないと、頭が劣化してしまうような気がする。