PIC16F84AやらPIC16F88やらとピンの配置に互換性のあるものばかりをLCDに接続したので、今度は配置も、そもそもピンの数も違うPIC16F1823でSC1602Bを駆動してみた。
改めて確認だが、大元のソースはPIC16F84を例にされているこちらのサイトを参考にさせていただいたものだ。
なので、PIC16F84AでもPIC16F88でもPIC16F648AでもConfiguration BitsとRegisterの変更だけでプログラムそのものに変更を加える必要はなかった。
参考にさせていただいているコードは、基本的にはPORTBを用い、データ用にbit4~7を、LCDのEnableにbit0、LCDのRSにbit1を割り当ててある。
今回は、PIC16F1823のPORTCを用いるのだが、ピン数の関係からかI/O用には6ピット分しか用意されていないので、データ用にbit0~3、RSにbit4、Enableにbit5を割り当てることにした。
というか、そう配線した。
データを上位下位に分けてLCDへ送ることと、そもそもデータ用にポートの下位4ビットを割り当てることから、C言語のド素人にはなかなか興味深い操作がしてあって楽しい。
手始めに簡単なところから書くと、
#define LCD_PORT PORTB
LCD_PORT=0x30;
となっているのはPORTBに0b01110000を出力するということだが、今回はデータ用に下位4ビットを使う。
そのため、下位へシフトさせて0b00000111としたものをPORTCへ書き込まなければいけないので、
#define LCD_PORT PORTC
LCD_PORT=0x03;
と変更することになる。
コードを勉強しながら眺めていてもっと面白かったのはこの部分、
void Putc_LCD4(char c, char rs){
LCD_RS=rs;
rs=LCD_PORT & 0x0F;
LCD_PORT=((c & 0xF0)+rs);
LCD_PORT=((c << 4)+rs);
}
こう変更する。
void Putc_LCD4(char c, char rs){
LCD_RS=rs;
rs=LCD_PORT & 0xF0;
LCD_PORT=((c >> 4)+rs);
LCD_PORT=((c & 0x0F)+rs);
}
上位下位を逆にしなければいけないということだ。
c & 0x0F
は上位4ビットをゼロにして下位4ビットは元のままにするということだし、
c >> 4
は上位4ビットを下位へシフトして上位4ビットはゼロにするということだ。
対象のポートから1バイト分読み込んで、下位の部分だけを書き換えて、ポートへ戻す。
しかも、その書き換える下位部分には、1度目は送りたいデータの上位4ビット、2度目に下位4ビットを分割してあてはめて送るわけだ。
こういう手を駆使して、ビットごとに1つづつデータを送るのではなく、バイト単位で読み込んでから必要な部分だけを書き換え、その後まとめてバイト単位で書き戻すという手法を使うのが特殊だ。
というわけで、相変わらずPICの型番は写っていないが、明らかにピン数の違うPICでもSC1602Bを駆動できているのはわかる今回のお題がこれ。
これで、とりあえずは6ピンあればどんなPICにもLCDを接続できるめどがついたことになる。
具体的な変更点
ヘッダファイルに変更はない。
メインのファイルのConfiguration Bitsの設定をMPLAB Xに吐き出させたものに置き換える。
// PIC16F1823 Configuration Bit Settings
#include
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
PORTCが初期値ではAnalog I/Oになっているので
ANSELC = 0b00000000;
を入れてDigital I/Oにする。
サブルーチンの変更
PORTCを使い、データ用にbit0:3、RSにbit4、Enableにbit5を使う設定に合わせてdefineを以下のように変更する。
#define _XTAL_FREQ 10000000
#define LCD_PORT PORTC
#define LCD_CONFIGREG TRISC
#define LCD_E RC5
#define LCD_RS RC4
初期化ルーチンで直接データを送る部分で、すべて右へ4ビットシフトした値に変更する。
LCD_PORT=0x30; —–> LCD_PORT=0x03;
LCD_PORT=0x20; —–> LCD_PORT=0x02;
1バイトの文字かデータを送るルーチンを以下のように変える。
void Putc_LCD4(char c, char rs){
__delay_us(52);
LCD_RS=rs;
rs=LCD_PORT & 0xF0;
LCD_PORT=((c >> 4)+rs);
STROBE;
LCD_PORT=((c & 0x0F)+rs);
STROBE;
}
ちなみにC言語素人の私は最初、
LCD_PORT=(((c & 0xF0) >> 4)+rs);
と書いていたが、
LCD_PORT=((c >> 4)+rs);
で良いらしい。
シフトすると勝手に0で埋められるんだって。