---
---
16F145xのMaster Synchronous Serial Port (MSSP) を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したLCD表示器のインターフェースだけを取り上げます。このため、I2C マスターモードが対象です。 SCL SDAの2ピンが対応しています。I2Cモードで使うときには、この2つのピンはオープンドレインの回路にする必要があるため、TRISレジスタで入力モードに設定しておく必要があります。 I2Cに関連するレジスター一覧を下表に示します。
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|---|
INTCON | GIE | PEIE | TMR0IE | INTE | IOCIE | TMR0IF | INTF | IOCIF |
PIE1 | TMR1GIE | ADIE | RCIE | TXIE | SSP1IE | - | TMR2IE | TMR1IE |
PIR1 | TMR1GIF | ADIF | RCIF | TXIF | SSP1IF | - | TMR2IF | TMR1IF |
PIE2 | OSFIE | C2IE | C1IE | - | BCL1IE | USBIE | ACTIE | - |
PIR2 | OSFIF | C2IF | C1IF | - | BCL1IF | USBIF | ACTIF | - |
SSPCON1 | WCOL | SSPOV | SSPEN | CKP | SSPM<3:0> | |||
SSPCON2 | GCEN | ACKSTAT | ACKDT | ACKEN | RCEN | PEN | RSEN | SEN |
SSPCON3 | ACKTIM | PCIE | SCIE | BOEN | SDAHT | SBCDE | AHEN | DHEN |
SSPSTAT | SMP | CKE | D/A | P | S | WnR | UA | BF |
SSPADD | ADD<7:0> | |||||||
SSPBUF | MSSP Receive Buffer/Transmit Register | |||||||
TRISC | TRISC7 | TRISC6 | TRISC5 | TRISC4 | TRISC3 | TRISC2 | TRISC1 | TRISC |
レジスタ | BIT | 名 | 説明 | 1 | 0 |
---|---|---|---|---|---|
INTCON | 7 | GIE | 全インタラプトの使用許可 | 許可 | 否 |
6 | PEIE | 周辺機能インタラプトの使用許可 | 許可 | 否 | |
PIE1 | 3 | SSP1IE | SSP インタラプトを使用許可 | 許可 | 否 |
PIR1 | 3 | SSP1IF | SSP インタラプト フラグ | 発生 | 未発生 |
PIE2 | 3 | BCL1IE | バス衝突 インタラプトを使用許可 | 許可 | 否 |
PIR2 | 3 | BCL1IF | バス衝突 インタラプト フラグ | 発生 | 未発生 |
SSPCON1 | 7 | WCOL | 送信時Bus衝突 | 発生 | なし |
6 | SSPOV | 受信時SSPBUFオーバーラン | 発生 | なし | |
5 | SSPOV | MSSPの動作 | ON | OFF | |
<3:0> | SSPM | I2C Master modeは、0b1000 に設定 | |||
SSPCON2 | 6 | ACKSTAT | ACK受信状況 | 未 | 受信済 |
5 | ACKDT | マスタ受信時のNACK/ACK指示 | NACK | ACK | |
4 | ACKEN | マスタ受信時のACKシーケンス開始 (自動リセット) | 開始 | 待ち | |
3 | RCEN | 受信機能を許可 | 許可 | 禁止 | |
2 | PEN | Stop 状況開始 (完了で自動リセット) | 開始 | 待ち | |
1 | RSEN | Repeat Start 状況開始 (完了で自動リセット) | 開始 | 待ち | |
0 | SEN | Start 状況開始 (完了で自動リセット) | 開始 | 待ち | |
SSPCON3 | 7 | ACKTIM | ACKタイミング状況 | ACK内 | ACK外 |
6 | PCIE | Stop 状況割込み | 許可 | 禁止 | |
5 | SCIE | Start 状況割込み | 許可 | 禁止 | |
3 | SDAHT | SCL立下り後のSDA Hold Time | 300 nS | 100 nS | |
SSPSTAT | 7 | SMP | Slew rate 制御の無効(100k用)/有効(400k用) | 100Hzk | 400kHz |
6 | CKE | スレッシュホールド電圧の異なるbusを使用 | SMbus | 標準 | |
5 | D/A | (Read only) 直前Byteの内容 | data | address | |
4 | P | (Read only) 直前にStop bit | なし | 検出 | |
3 | S | (Read only) 直前にStart bit | なし | 検出 | |
2 | R/W | (Read only) 送信状況 | 送信中 | 待機 | |
1 | UA | (Read only) 10-bit I2C mode only | |||
0 | BF | (Read only) SSPBUF状況 | フル | 空 |
I2C クロック周波数 | Fosc | ||
---|---|---|---|
48MHz | 16MHz | 4MHz | |
400 KHz | 0x1D | 0x18 | --- |
100 KHz | 0x77 | 0x63 | 0x09 |
I2Cクロック周波数と、SSPADDへの設定値
秋月(ACM1602NI)I2C LCD表示器へ文字を表示するプログラムです。 i2cは双方向性バスで受信(スレーブ)側の応答を確認したり、送受信信号が衝突した場合などのエラーを検出する機能を持っています。しかし、このプログラムでは、これら機能をすべて省略し、表示データや制御コードを一方的にLCD表示器に送信しています
<回路図>
<プログラム>
// データをLCDに表示する。 // 秋月(ACM1602NI)I2C LCD表示器への書き込み // 「LCD Disp Test」と液晶表示する。 // 1)Define I/O PORT // --PIC16F1455-- --PIC16F1459-- // SDA : PORTC(1) pin 9 PORTB(4) pin13 // SCL : PORTC(0) pin10 PORTB(6) pin11 // 2)OSC // 4MHz (内部クロック) // // Language: MPLABX XC8 // Target: PIC16F1455 // Copyright (c) 2012 iwamoto All Rights Reserved //********************************************************* #include <xc.h> #define _XTAL_FREQ 4000000 //************* Config *********************************** #pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF #pragma config BOREN = ON, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF #pragma config WRT = OFF, CPUDIV = NOCLKDIV, USBLSCLK = 48MHz, PLLMULT = 3x #pragma config PLLEN = DISABLED, STVREN = ON, BORV = LO, LPBOR = OFF, LVP = OFF //******************************************************** void i2cByteWrite(char, char, char); // i2c byte送信 void i2cTxData(char); // i2c SSPBUF セット void LCD_dat(char); // 1文字表示 void LCD_cmd(char); // コマンド出力 void LCD_clr(void); // 全消去 void LCD_int(void); // 初期化 void LCD_str(char *); // 文字列表示 void LCD_ROMstr(const char *); // ROM文字列表示 void LCD_posyx(char,char); // カーソル位置指定 void LCD_hex(char); // 16進文字変換表示 //////////// Main ////////////////////////////////// void main(void){ char msgStart[] ="LCD Test"; unsigned char num = 0; OSCCON = 0b00110100; // 内部クロック4Mhz ANSELC = 0; // PortCをデジタルI/Oにする TRISC = 0b11111111; // PortCを入力I/Oにする SSPCON1 = 0x28; // I2Cマスターモード指定 SSPSTAT = 0x00; SSPADD = 0x09; // I2Cクロック周波数100KHz for 4MHz LCD_int(); // LCD初期化 // ------------------------------------------------------ LCD_str(msgStart); // 1行目に表示 LCD_dat(' '); LCD_dat('!'); // ------------------------------------------------------ LCD_posyx(1,0); // 2行目に表示 LCD_ROMstr("1234567890123456"); while(1){ LCD_posyx(0,14); // 1行14文字目に表示 LCD_hex(num++); // 数値を表示し、+1する __delay_ms(1000); // 1000msec } } //-------- i2cで1byteデータを送信する ----------------------- // 以下の引数が必要 // addr : Slaveのアドレス // cont : Slaveへ制御コード // data : 送信するデータ // NACKやBus衝突などの対応は行っていない // ----------------------------------------------------------- void i2cByteWrite(char addr, char cont, char data){ SEN = 1; // Start condition 開始 while(SEN); // Start condition 確認 i2cTxData(addr); // アドレス送信 i2cTxData(cont); // 制御コード送信 i2cTxData(data); // データ送信 SSP1IF = 0; // 終了フラグクリア PEN = 1; // Stop condition 開始 while(PEN); // Stop condition 確認 } //-------- SSPBUFに1文字保存し送信終了を待つ ----------------- void i2cTxData(char data){ SSP1IF = 0; // 終了フラグクリア SSPBUF = data; // データセット while(!SSP1IF); // 送信終了待ち } //-------- 1文字表示 -------------------------------------- void LCD_dat(char chr){ i2cByteWrite(0xA0, 0x80, chr); __delay_us(60); // 60μsec } //-------- コマンド出力 -------------------------------------- void LCD_cmd(char cmd){ i2cByteWrite(0xA0, 0x00, cmd); if(cmd & 0xFC) // 上位6ビットに1がある命令 __delay_us(60); // 60usec else __delay_ms(3); // 3msec 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; // 1行目 case 1: pcode=0xC0;break; // 2行目 case 2: pcode=0x94;break; // 3行目 case 3: pcode=0xD4;break; // 4行目 } LCD_cmd(pcode += xpos); // 横位置を加える } //-------- 文字列出力 ----------------------------------------- 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 } //-------- 16進文字変換表示 -------------------------------- void LCD_hex(char c){ const char hexch[] ="0123456789ABCDEF"; LCD_dat(hexch[c >> 4]); //上位4bit表示 LCD_dat(hexch[c & 0xF]); //下位4bit表示 } //-------- 初期化 -------------------------------------- void LCD_int(void){ __delay_ms(100); // 電源安定するまでの時間 LCD_cmd(0x38); // 8bit 2行 表示命令モード LCD_cmd(0x0C); // Display on Cursor=0 Blink=0 LCD_cmd(0x06); // Entry Inc/Dec=1 Shift=0 LCD_cmd(0x01); // Clear Display }
*注意*
I2Cピンは、ICSP と共通ピンを使用しています。PICkitは内部でこの端子をプルダウンしているため、PICkit を接続したままでは、I2C機能が働きません。
プログラムの動作確認をするときには、必ずPICkitを回路から取り外します。