2008/04/13(日)キャラクタ液晶を使う

キャラクタLCDライブラリを使う

自作のLCDライブラリもありますが、フルアセンブラということもあり、WinAVRで即使用可能なものをググってみました。やっぱりありますよねぇ・・・。

あきぼう氏のコードを流用

あきぼうのAVRで遊ぶ日々を参照しましょう。AVRのLCD操作関数から、lcd.h, lcd.cとを持ってきます。

lcd.hで、使用する環境に合わせて変更するべき箇所があります。適当に抜粋します。

//#define LCD_RW_PORT	PORTB	// Port contains RS-pin
//#define LCD_RW_DDR	DDRB	// Port contains RS-pin
//#define LCD_RW		1		// portbitNo connected to LCD-RS
#define N_LINE	4
#define N_COL   20
#define lcd_4
//#define lcd_nostring

これ以外に、LCD接続ポートの設定があります。上記を引用したのは、RW信号を未使用とした設定だったからです。あと、データ信号が4本使用時のため。コメントアウトされているところに、F_CPUをMakefileで定義するように記述されています。WinAVRを入れたディレクトリのavr/include/avr/util/delay.h を見るとわかりますが、空回りでウェイトを作っています。割り込み処理が多い場合は、規定時間をより多く取ってしまいそうですね。本当はfree run coutnerでスマートに作りたいところですが... まぁいいでしょう.

上記シンボルたちが何者か、と、lcd.cをさっと眺めて見ましたが、4bit data時には結構冗長かもしれませんねぇ。自作コードをgccにポートしたほうが良いかもしれませんね。余力があればもってきましょう。

ポーリングしてねぇ(confirm)

順番にやればいいのにざっとフレームを作ろうとして敗退。実機動作確認に至らず。時間待ちナシのAD変換できたら順次回すことにして、表示タイミングとチャタリング除去にタイマを使う方向で検討中。無論、AD変換精度向上のために、sleep命令は使用することにしますよ...。

で、先ほどwarning/errorなし状態にできたのですが・・・。lcd.cは、ウェイトで逃げてますね('A`
RW信号使ってないとは思っていましたが、コード自体も検証されていない様子。エラー出るしー。やっぱり自前の持ってきたほうがよさそうだわ。ぁ-どうすっかな。とりあえずコレでやり過ごして、その後持ってきたほうがいいかな。どんどんと完成が遠のいているのがよくわかるぜw

計算方法

固定少数とかなんだとか....。今回ADW(10bit)と、Vrefが2.5Vということで、綺麗に整数演算を済ますことができないと思われます。仕方がないので、可能な限り有効桁数を持って生きつつも演算量を減らすことを考えたいと思うます。
おおまかな考え方だけ転記しておきます。適宜、読み替えたりしてください。もちろんADWは複数読み出してはいけませんよ。また、右詰めを想定しています。

	i = v / r
	v = 2.5  * (ADW / 1024)
	i = 2.5 / 1024 * ADW / 1 [A]
	i = 2.5 *1000 / 1024 * ADW [mA]
		=> 0x9C4 * ADW >> 10
		0x9C4 = ((0x27 << 6) | 0x04)

	i = ((0x27 * ADW) << 6 + (0x04 * ADW)) >> 10
		(0x27 * ADW) >> 4 + (0x04 * ADW) >> 10
		(0x27 * ADW) >> 4 + (ADW >> 8)

uint16_tだと16bit精度あるので, 10bit x 6bitまでならばoverflowしない、ということを用いています。uint16_t * uint16_tだと32bitの結果になるので、コードサイズが肥大化するのは目に見えていますから・・・。こういった制約がわかっている状況では、コードに素直に書く前に自力で展開してやることも必要ですネ。

ついでにr=10のときの数式も張っておきます。

R=10
	i = v / r
	v = 2.5 * (ADW / 1024)
	i = 2.5 / 1024 * ADW / 10 [A]
	i = 2.5 *100 / 1024 * ADW [mA]
		=> 0x0FA * ADW >> 10
		0x0FA = ((0x03 << 6) | 0x2A)
	i = ((0x03 * ADW) << 6 + (0x2A * ADW)) >> 10
		= ((0x03 * ADW) << 6 >> 10) + (0x2A * ADW) >> 10
		= ((0x03 * ADW) >>4) + (0x2A * ADW) >> 10