PIC16F88での時計の表示の為のポート設定を検討した。なにかと言うとLCD表示をするときのポートの選択方法なのだ。LCD側とPICの接続は大概(RA0~RA3、RB0~RB3、RB4~RB7のどれかRA4,RA5,RA6,RA7はRA5が入力ポートなので連続使用不可)連続4ポートとLCD側4ポート(D7,D6,D5,D4、4ビット接続時)の接続例がほとんどだ。上位4ビット、または、下位4ビットでの連続ポートである。新たに作成する回路都合で問題が無い場合は良いが、いろいろと動作済みのものをマージ(合体)したい場合は、LCD接続用で全部が連続でない空きポートを使う必要がでてくる。今回は時計のSWポートをそのまま使い、LCDへ表示する為の第一段階として先の標準の3例のポート接続ができない場合(RA3ポートが時計のSW入力で使われてしまっている場合)のポート(RA0,RA1,RA2,RA6)対応を行ってみる。他のコンパイラではLCD専用関数でのコンフィグ設定で使用できるものがあるようだが、XC8での対応例はインターネット上では一切見つからなかった。皆さんは連続ポートでの使い方だけなのかな~?
通常時のLCD接続PICポート----->空きポート都合でのLCD接続PICポート
RA0,RA1,RA2,RA3----------->RA0,RA1,RA2,RA6
LCD端子側とのポート対応は以下となる
D7:RA6
D6:RA2
D5:RA1
D4:RA0
このために何を行うか?何となくLCDへデータを送るポート指定関連のプログラムを変えなきゃいけないというのが分ると思う。なので、早速、実際にLCDの制御プログラムであるlcd.cのプログラムを見てみるわけです。
やらなければいけないのはLCDの制御プログラム中のポート設定対応部を対応するポート用に作り直すということです。
まず、ポート出力するそれらしき部分の記載がある関数が2つ程ありました。
----------------------------------------------------------------------------------------
void lcd_data_byteset(unsigned char c){
PORTA = (PORTA & 0b11110000) | (c & 0b00001111); //Only low 4bit DATA
LCD_STROBE;
}
void lcd_data_set(unsigned char c){
PORTA = (PORTA & 0b11110000) | ( (c >>4 ) & 0b00001111 ) ; //Hi SIDE DATA
LCD_STROBE;
PORTA = (PORTA & 0b11110000) | (c & 0b00001111 ); //low SIDE DATA
LCD_STROBE;
}
----------------------------------------------------------------------------------------
lcd_data_bytestとlcd_data_setの2関数でのポート指定が連続のPIC4ポート用として書かれています。
まず初期化で使われているlcd_data_bytestについて
実際にパソコンになったつもりで動作を見てみると、PORTA(RA7,RA6,RA5,RA4,RA3,RA2,RA1,RA0)と0xF0とのANDをとり、入力データcと0x0FとのANDの結果とのORをとると最終結果PORTAには(RA7,RA6,RA5,RA4,RA3,RA2,RA1,RA0)が対応となる。これだと解りにくい。次のようなことなのだ。
---------------------------------------------
上位
RA7,RA6,RA5,RA4 はポートAの上位がそのまま入る(RA7,RA6,RA5,RA4)
---------------------------------------------
下位
RA3,RA2,RA1,RA0は引数cのデータの下位値が入る(RA3,RA2,RA1,RA0)
---------------------------------------------
またLCDへの出力対応ポートは
RA3,RA2,RA1,RA0なので結局引数cのデータの下位値が出力されるのです。上位はLCDポートにはなんら関係なし。
次にlcd_data_setについて
同様に実際にパソコンになったつもりで動作を見てみると、PORTA(RA7,RA6,RA5,RA4,RA3,RA2,RA1,RA0)と0xF0とのANDをとり、引数cを4ビット右シフトし0x0FとANDをとった結果とのORをとると最終結果PORTAには(RA7,RA6,RA5,RA4,RA7,RA6,RA5,RA4)が対応となる。これだともっと解りにくいかもしれない。次のようなことです。
---------------------------------------------
上位
RA7,RA6,RA5,RA4 はポートAの上位がそのまま入る(RA7,RA6,RA5,RA4)
---------------------------------------------
下位
RA3,RA2,RA1,RA0には引数cのデータの上位(RA7,RA6,RA5,RA4)が入る
またLCDへの出力対応ポートは
RA3,RA2,RA1,RA0なので結局引数cのデータの上位値が出力されるのです。上位はLCDポートにはなんら関係なし。
次のプログラム文はlcd_data_bytestの引数cの下位値出力とまったく同じです。
よって、lcd_data_setでは引数cの上位データを最初に送出し、つぎに引き数cの下位データを送出するというプログラムなのです。紛らわしいったらありゃしない。説明書くのも大変、あ~疲れた!
プログラム動作内容がわかったので、目的のポート変更への対応を考えてみる。対応する関数はlcd_data_setで他のlcd_data_bytesetは同じなので省略する。
cd_data_setでは要するに引数cの上位値、下位値を順番に(RA6,RA2,RA1,RA0)に出力するようにすればよいわけです。
引数に対しての上位ポート値(X7,X6,X5,X4)、下位ポート値(X3,X2,X1,X0)とするとLCDポート(D7,D6,D5,D4)にたいしては次のようになる。
LCDポート:PICポート:引数値-----説明
D7:RA6:X7----- PIC6ポートにX7
D6:RA2:X6----- PIC2ポートにX6
D5:RA1:X5----- PIC1ポートにX5
D4:RA0:X4----- PIC0ポートにX4
上記のようにPIC6ポートにX7なので1ビット右シフトして0x40(0x01000000)とのAND(6ビット目だけ取り出す)をとる。またPIC2,PIC1,PIC0ポートには上位のX6,X5,X4が対応なので、上位X7,X6,X5,X4を4ビット右シフトして0x07(0b00000111)とのANDをとり3ビット分だけ取り出し最初の結果とのORでポート設定する。これを素直にプログラムすると次のようになります。
---------------------------------------------------------------
PORTA = (((c >>4 ) & 0b00000111)|(((c >>1 ) & 0b01000000)));
---------------------------------------------------------------
これで、引数cの上位のデータがPORTA(RA6,RA2,RA1,RA0)に送出できるようになります。
次の下位のデータ送出も同様に
D7:RA6:X3----- PIC6ポートにX3
D6:RA2:X2----- PIC2ポートにX2
D5:RA1:X1----- PIC1ポートにX1
D4:RA0:X0----- PIC0ポートにX0
前と同じ考え方でPIC6ポートにX3なので3ビット左シフトして0x40(0x01000000)とのANDをとる。また必要な下位(X2,X1,X0)は引数cと0x07(0b00000111)との単純なANDで取り出し、最初の結果とのORでポート設定する。プログアムは次のようになります。
---------------------------------------------------------------
PORTA = ((c & 0b00000111)|((c<<3) & 0b01000000));
---------------------------------------------------------------
以上で引数cの下位のデータがPORTA(RA6,RA2,RA1,RA0)に送出できるようになります。
5000文字を超えたようなので次へつづく