目次>6章 第3ステップ(実用品)>1ピンで液晶ディスプレイを制御 >ソース
1ピンで液晶ディスプレイを制御(ソース)
(シリアル制御LCD)<PIC16F84A>PICC-Lite
更新日2008.1.14
以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。
// ========================== ここから ==============================
// PIC16F84A
// CLOCK : 20MHz
// 他のPICからシルアル通信風にデータを受信し、LCDに出力する
//
// 通信速度 以下をPBSで切り替える
// ・ 4800bps
// ・ 9600bps
// ・19200bps
// ・28800bps
// ・38400bps
// ・57600bps
//
// TMR0:ビット受信のサンプリング間隔
// 0.2μS×100=20μS : 50Kbps
// 通信速度 TMR0プリスケーラ 256-TMR0
// 4800 8 130
// 9600 4 130
// 19200 2 130
// 28800 2 87
// 38400 2 65
// 57600 2 43
//
//
// ↓スタートビット
// __
// ___| | | | |
// ↑ ↑ ↑
// | 20μS毎にサンプリング
// 立ち上がりから10μS遅らせる
//
//
//
// RA0:LCD_E
// RA1:LCD_R/W
// RA2:LCD_RS
// RA3:SW1(スピード切り替え)
// RA4:SW2
// RB0:LCD_DB4
// RB1:LCD_DB5
// RB2:LCD_DB6
// RB3:LCD_DB7
// RB4:
// RB5:LED(データ受信時点灯,バッファオーバラン時点灯)
// RB6:
// RB7:他のPICからシリアル受信(ピン変化割込み)
//
// LCD_V0 : 350ΩでGND
// LCD_DB0-3:GND
//
#include "pic.h"
#define LCD_E RA0
#define LCD_RW RA1
#define LCD_RS RA2
#define buffsize 40
#define RS_data 0x11
#define RS_cmd 0x12
#define EEsave 0
// スピード表示文字列のアドレス(EEPROM)
#define EEKbps 8 // 'Kbps' EEPROMアドレス
#define EE48 13 // '4.8' EEPROMアドレス
#define EE96 17 // '9.6' EEPROMアドレス
#define EE192 21 // '19.2' EEPROMアドレス
#define EE288 26 // '28.8' EEPROMアドレス
#define EE384 31 // '38.4' EEPROMアドレス
#define EE576 36 // '57.6' EEPROMアドレス
static void OverRun();
static void Delay_1ms();
static void Delay_ms(unsigned char);
static void pic_init();
static void LCD_send4(unsigned char);
static void LCD_Busy_wait();
static void LCD_cmd(unsigned char);
static void LCD_data(unsigned char);
static void LCD_init();
static void bufLCD();
static void sw_RA3_on();
static void EEtoLCD(unsigned char);
static void EEwrite(unsigned char, unsigned char);
static unsigned char EEread(unsigned char);
static void EEspeed();
static void speedDSP();
__CONFIG(HS & WDTDIS & PWRTEN & UNPROTECT);
__EEPROM_DATA(0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
__EEPROM_DATA('K', 'b', 'p', 's', 0x00, '4', '.', '8');
__EEPROM_DATA(0x00, '9', '.', '6', 0x00, '1', '9', '.');
__EEPROM_DATA('2', 0x00, '2', '8', '.', '8', 0x00, '3');
__EEPROM_DATA('8', '.', '4', 0x00, '5', '7', '.', '6');
__EEPROM_DATA(0x00, ' ', ' ', ' ', ' ', ' ', ' ', ' ');
__EEPROM_DATA(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
__EEPROM_DATA(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
static unsigned char buff[buffsize];
static unsigned char buffR; // バッファ読み込みポインタ
static unsigned char buffW; // バッファ書き込みポインタ
static unsigned char SW_RS; // LCD書き込みモード
static unsigned char comm_stat; // 通信状態
// 0:無通信
// 1:スタートビット受信,半ビット時間待ち
// 2:データビット受信中
// 3:データビット受信完了,ストップビット待ち
static unsigned char comm_char; // 受信データ
static unsigned char comm_bit; // 受信データのビット数
static unsigned char T0val; // TMR0設定値
static unsigned char sw_RA3; // RA3 SW状態
static unsigned char speed; // 通信速度(1:4800,2:9600,3:19200)
// =================== 割り込み処理 ====================
static void interrupt intr(void) {
if (T0IF) { // TMR0割り込み?
TMR0 = 256 - T0val; // TMR0
T0IF = 0; // TMR0割り込みクリア
RB4 ^= 1; // DEBUG
switch (comm_stat) {
case 1: // ■スタートビット受信開始,半ビット待ち
// if (RB7) { // スタートビット?
comm_stat = 2; // データビット受信中
comm_bit = 8; // 8ビット受信開始
// } else {
// comm_stat = 0; // 無通信
// }
break;
case 2: // ■データビット受信中
comm_char <<= 1;
if (RB7) {
comm_char |= 0x01;
}
comm_bit--;
if (!(comm_bit)) {
buff[buffW] = comm_char;
comm_stat = 3; // データビット受信完了,ストップビット待ち
// バッファ書き込みポインタの更新
buffW++;
// if (buffW < buffsize) { // バッファポインタは最終位置でない
// if (buffW == buffR) {
// OverRun(); // オーバーラン(LED点灯し停止する)
// }
// } else
if (buffW == buffsize) { // バッファポインタは最終位置?
// if (buffR != 0) {
buffW = 0;
// } else {
// OverRun(); // オーバーラン(LED点灯し停止する)
// }
}
}
break;
case 3: // ■ストップビット待ち
comm_stat = 0; // 無通信状態
if (!RB7) {
RB5 = 0; // LED消灯
}
RB4 = 0; // DEBUG
T0IE = 0;
RBIE = 1;
RBIF = 0;
break;
}
} else
if (RBIF) { // PORTBピン変化割り込み?
RB5 ^= 1;
if (RB7) { // スタートビット?
if (comm_stat == 0) { // ■無通信状態
comm_stat = 2; // データビット受信中
comm_bit = 8; // 8ビット受信開始
// comm_stat = 1; // スタートビット受信開始,半ビット待ち
// RB5 = 1; // LED点灯
RB4 = 0; // DEBUG
// TMR0 = 256 - (T0val >>1); // TMR0
// TMR0 = 256 - T0val + 20; // TMR0
// TMR0 = 256 - T0val - 10; // TMR0
TMR0 = 256 - T0val; // TMR0
T0IF = 0;
T0IE = 1;
// RBIE = 0;
}
}
RBIF = 0; // PORTBピン変化割り込みクリア
}
}
// ==================== メイン処理 ===========================
main() {
unsigned char i;
unsigned char c;
pic_init(); // PICの初期化
LCD_init(); // LCDの初期化
EEspeed();
buffW = 0;
buffR = 0;
SW_RS = 1; // LCD Data mode
Delay_ms(250);
Delay_ms(250);
comm_stat = 0;
RB7 = 0;
INTCON = 0x88; // GIE=1, RBIE=1
while(1) {
if (buffW != buffR) {
bufLCD();
}
if (RA3) { // RA3:1 (SW off)
sw_RA3 = 0;
} else { // RA3:0 (SW on)
sw_RA3_on();
}
}
}
// ==================== バッファオーバラン発生 ================
static void OverRun() {
RB5 = 1;
while(1) {}
}
// ==================== 1mSウェイトルーチン ================
static void Delay_1ms() {
unsigned int cnt;
unsigned int i;
cnt = 384;
for (i=0 ; i<cnt ; i++) {
NOP();
}
}
// ==================== 1mS×ms ウェイトルーチン ===========
static void Delay_ms(unsigned char ms) {
unsigned char c;
for (c=ms ; c>0 ; c--) {
Delay_1ms();
}
}
// ==================== PICの初期化 ===========================
static void pic_init() {
OPTION = 0x00; // TMR0プリスケーラ:2
TRISA = 0xF8; // RA0-2:out
TRISB = 0x80; // RB0-6:out
PORTA = 0x00;
PORTB = 0x00;
INTCON = 0x00; // GIE:0 ,T0IE:0 ,RBIE:0
}
// ==================== LCD 4ビット送信 =========================
static void LCD_send4(unsigned char c) {
PORTB = (PORTB & 0xF0) | c;
LCD_E = 1;
NOP();
LCD_E = 0;
}
// ==================== LCD Busy解除を待つ ====================
static void LCD_Busy_wait() {
LCD_E = 0;
LCD_RW = 1;
LCD_RS = 0;
TRISB = TRISB | 0x0F; // PORTB(3-0):input
while(1) {
LCD_E = 1; // 上位4ビット読み込み
NOP();
if (RB3 == 0) { // Busy = 0を待つ
LCD_E = 0;
break;
}
LCD_E = 0;
NOP();
LCD_E = 1; // 下位4ビット読み込み
NOP();
LCD_E = 0;
NOP();
}
LCD_E = 1; // 下位4ビット読み込み
NOP();
LCD_E = 0;
TRISB = TRISB & 0xF0; // PORTB(3-0):output
}
// ==================== LCDコマンドWRITE =================
static void LCD_cmd(unsigned char cmd) {
LCD_Busy_wait(); // Busy解除待ち
LCD_RS = 0;
LCD_RW = 0;
PORTB = (PORTB & 0xF0) | ((cmd >>4) & 0x0F);
LCD_E = 1; // 上位4ビット書き込み
NOP();
LCD_E = 0;
PORTB = (PORTB & 0xF0) | (cmd & 0x0F);
LCD_E = 1; // 下位4ビット書き込み
NOP();
LCD_E = 0;
}
// ==================== LCDデータWRITE =================
static void LCD_data(unsigned char cmd) {
LCD_Busy_wait(); // Busy解除待ち
LCD_RS = 1;
LCD_RW = 0;
PORTB = (PORTB & 0xF0) | ((cmd >>4) & 0x0F);
LCD_E = 1; // 上位4ビット書き込み
NOP();
LCD_E = 0;
PORTB = (PORTB & 0xF0) | (cmd & 0x0F);
LCD_E = 1; // 下位4ビット書き込み
NOP();
LCD_E = 0;
}
// ==================== LCDの初期化 ===========================
static void LCD_init() {
Delay_ms(15);
LCD_E = 0;
LCD_RW = 0;
LCD_RS = 0;
LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@
Delay_ms(5);
LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@
Delay_ms(1);
LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@
Delay_ms(1);
LCD_send4(0x02); // DB4-7に'2'を出力(4bitモードに)
Delay_ms(1);
// ここからは4bitモードで、Busyフラグが使える
LCD_cmd(0x28); // DL=0:4bit ,N=1:2lines ,F=0:5*7dot
LCD_cmd(0x08); // Display off
LCD_cmd(0x0C); // Display on ,cursor on ,no blink
LCD_cmd(0x06); // Entry mode (Inc ,No Shift)
LCD_cmd(0x01); // Clear Display
}
// =============== bufferの内容をLCDに出力 ===================
static void bufLCD() {
unsigned char c;
c = buff[buffR];
switch (c) {
case RS_cmd:
SW_RS = 0; // Command mode set
break;
case RS_data:
SW_RS = 1; // Data mode set
break;
default:
if (SW_RS) {LCD_data(c);}
else {LCD_cmd(c); }
}
buffR++;
if (buffR == buffsize) { // バッファポインタは最終位置?
buffR = 0;
}
}
// ==================== RA3スイッチON処理 ==============
// スピード切り替え
static void sw_RA3_on() {
Delay_ms(20); // チャタリングキャンセル
if (!RA3) { // RA3 on 確定
if (!(sw_RA3)) {
sw_RA3 = 1;
if (!(speed)) {speed = 6;}
LCD_cmd(0x01); // LCDクリア
speedDSP(); // スピードをLCDに表示
comm_stat = 0; // 無通信状態
EEwrite(EEsave,speed);
speed--;
}
}
}
// ============= EEPROMに保存したスピードをLCDに表示 ==========
static void EEspeed() {
speed = EEread(EEsave);
LCD_cmd(0x01); // LCDクリア
speedDSP(); // スピードをLCDに表示
}
// ==================== スピードをLCDに表示 =================
static void speedDSP() {
OPTION = 0x00; // TMR0プリスケーラ:2
switch(speed) {
case 1:
OPTION = 0x02; // TMR0プリスケーラ:8
T0val = 127; // 4.8Kbps
EEtoLCD(EE48);
break;
case 2:
OPTION = 0x01; // TMR0プリスケーラ:4
T0val = 124; // 9.6Kbps
EEtoLCD(EE96);
break;
case 3:
T0val = 119; // 19.2Kbps
EEtoLCD(EE192);
break;
case 5:
T0val = 54; // 38.4Kbps
EEtoLCD(EE384);
break;
case 6:
T0val = 32; // 57.6Kbps
EEtoLCD(EE576);
break;
default:
T0val = 76; // 28.8Kbps
speed = 4;
EEtoLCD(EE288);
break;
}
EEtoLCD(EEKbps);
}
// ============= EEPROM[addr]の内容を0x00までLCDに出力 ==========
static void EEtoLCD(unsigned char addr) {
unsigned char c;
unsigned char i;
i = addr;
while(1) {
c = EEread(i); // EEPROMの内容を読み込み
if (c == 0x00) {break;} // EEPROMの内容が0x00なら終了
LCD_data(c); // EEPROMから読み込んだ文字をLCDに表示
i++;
}
}
// ============= EEPROM 書き込み ================================
static void EEwrite(unsigned char addr, unsigned char dat) {
EEPROM_WRITE(addr , dat); // EEPROMに書き込み
}
// ============= EEPROM 読み込み ================================
static unsigned char EEread(unsigned char addr) {
return(EEPROM_READ(addr));
}
// =========================== ここまで ===============================