PIC16F1619には、Master Synchronous Serial Port (MSSP) があり、MSSP を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したLCD表示器とのインターフェースだけを取り上げます。このため、I2C マスターモードが対象です。
<回路図>
PI2Cを利用したLCD表示器(LCD-AQM0802A)「LCD Test / I2C com」と表示するプログラムを作成しました。通常 I2Cラインに取り付けるプルアップ抵抗は、PIC内の弱プルアップを利用しています。雑音の大きい環境で使用するときは、別途プルアップ抵抗を回路に取り付けてください。
<プログラム>
/********************************************************************* * データをLCDに表示する。 * 秋月(ACM1602NI)I2C LCD表示器を使用 * 1MHz (内部クロック) * RB6 SCL * RB4 SDA * * PIC16F1619 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved * *******************************************************************/ #include <xc.h> #define _XTAL_FREQ 1000000 //********************************************************************* // 調整用定数 //********************************************************************* #define CONTRAST 0x28 // for 3.3V // #define CONTRAST 0x18 // for 5.0V #define slaveDeviceAddress 0x7C // CONFIG1 #pragma config FOSC = INTOSC #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = ON #pragma config FCMEN = ON // CONFIG2 #pragma config WRT = OFF #pragma config PPS1WAY = ON #pragma config ZCD = OFF #pragma config PLLEN = OFF #pragma config STVREN = ON #pragma config BORV = LO #pragma config LPBOR = OFF #pragma config LVP = ON // CONFIG3 #pragma config WDTCPS = WDTCPS1F #pragma config WDTE = OFF #pragma config WDTCWS = WDTCWSSW #pragma config WDTCCS = SWC //******************* プロトタイプ ******************************* void i2cByteWrite(char, char, char); void i2cTxData(char); void LCD_dat(char); void LCD_cmd(char); void LCD_clr(void); void LCD_posyx(char,char); void LCD_int(void); void LCD_put(char); void LCD_str(char *); void LCD_ROMstr(const char *); /********************************************************* Main application *********************************************************/ void main(void) { OSCCON = 0x58; // FOSC; PLL disabled; 1MHz_HF; LATA = 0x00; // 全てクリア LATB = 0x00; LATC = 0x00; TRISA = 0xFF; // 全て入力 TRISB = 0xFF; TRISC = 0xFF; ANSELC = 0x00; // 全てデジタル ANSELB = 0x00; ANSELA = 0x00; WPUB = 0xFF; // 全て弱プルアップ WPUA = 0xFF; WPUC = 0xFF; OPTION_REGbits.nWPUEN = 0; ODCONB = 0b01010000; // RB6,RB4をオープンドレイン SSPCLKPPS = 0b00001110; // RB6をCLK入力に指定 RB6PPS = 0b00010000; // RB6をCLK出力に指定 SSPDATPPS = 0b00001100; // RB4をDATに入力指定 RB4PPS = 0b00010001; // RB4をDAT出力に指定 // SSP1設定 ----------------------------------------------- SSP1STAT = 0b10000000; // スルーレート制御はOff SSP1ADD = 3; // クロック設定 65k@1MHz SSP1CON1 = 0b00101000; // I2C Master modeにする // -------------------------------------------------------- char msgStart[] ="LCD Test"; LCD_int(); // LCDを初期化 LCD_str(msgStart); // LCD上段に"LCD Disp Test" LCD_posyx(1,1); // 下段にカーソル移動 LCD_ROMstr("I2C com"); // 下段に追記 while (1) { // Add your application code } } //******************************************************************** // I2C 関連 //******************************************************************** //-------- ByteI2C送信 void i2cByteWrite(char addr, char cont, char data){ SSP1CON2bits.SEN = 1; // Start condition 開始 while(SSP1CON2bits.SEN); // Start condition 確認 i2cTxData(addr); // アドレス送信 i2cTxData(cont); // 制御コード送信 i2cTxData(data); // データ送信 SSP1CON2bits.PEN = 1; // Stop condition 開始 while(SSP1CON2bits.PEN); // Stop condition 確認 } //-------- Data送信 void i2cTxData(char data){ PIR1bits.SSP1IF = 0; // 終了フラグクリア SSP1BUF = data; // データセット while(!PIR1bits.SSP1IF); // 送信終了待ち } //******************************************************************** // LCD 関連 //******************************************************************** //-------- 1文字表示 void LCD_dat(char chr){ i2cByteWrite(0x7C, 0x40, chr); __delay_us(50); // 50μsec } //-------- コマンド出力 void LCD_cmd(char cmd){ i2cByteWrite(0x7C, 0x00, cmd); if(cmd & 0xFC) // 上位6ビットに1がある命令 __delay_us(50); // 50usec else __delay_ms(2); // 2msec ClearおよびHomeコマンド } //-------- 全消去 void LCD_clr(void){ LCD_cmd(0x01); //Clearコマンド出力 } //-------- カーソル位置指定 void LCD_posyx(char ypos, char xpos){ unsigned char pcode; switch(ypos & 0x03){ case 0: pcode=0x80;break; case 1: pcode=0xC0;break; } LCD_cmd(pcode += xpos); } //-------- 初期化 void LCD_int(void){ __delay_ms(100); LCD_cmd(0x38); // 8bit 2行 表示命令モード LCD_cmd(0x39); // 8bit 2行 拡張命令モード LCD_cmd(0x14); // OSC BIAS 設定1/5 // コントラスト設定 LCD_cmd(0x70 + (CONTRAST & 0x0F)); LCD_cmd(0x5C + (CONTRAST >> 4)); LCD_cmd(0x6B); // Ffollwer __delay_ms(100); __delay_ms(100); LCD_cmd(0x38); // 表示命令モード LCD_cmd(0x0C); // Display On LCD_cmd(0x01); // Clear Display } //-------- 文字列出力 void LCD_str(char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 } //-------- Rom 文字列出力 void LCD_ROMstr(const char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 }