---
---
16F1459の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 | |||||||
| TRISB | TRISB7 | TRISB6 | TRISB5 | TRISB4 | ||||
| レジスタ | 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 | SSPEN | 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に表示する。
// 秋月(AQM0802A)I2C 8x2 LCD表示器への書き込み
// 「LCD Test」と液晶表示する。
// 1)Define I/O PORT
// SDA : PORTB(4) pin13
// SCL : PORTB(6) pin11
// 2)OSC
// 4MHz (内部クロック)
//
// Language: MPLABX XC8
// Target: PIC16F1459
// Copyright (c) 2015 iwamoto All Rights Reserved
//*********************************************************
#include <xc.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000
//*********************************************************************
// 調整用定数
//*********************************************************************
#define CONTRAST 0x28 // for 3.3V
// #define CONTRAST 0x18 // for 5.0V
//************* 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_posyx(char,char); // カーソル位置指定
// **************** printf Routen *****************************
// LCD で printf関数が使用できるようにするため putch を設定する
void putch(char data) {
LCD_dat(data); // LCD への一文字表示関数
}
//////////// Main //////////////////////////////////
void main(void){
char msgStart[] ="LCD Test";
unsigned char num = 0;
OSCCON = 0b00110110; // 内部クロック4Mhz
ANSELA = 0; // PortAをデジタルI/Oにする
TRISA4 = 1; // PortA4をデジタルInputにする
ANSELB = 0; // PortBをデジタルI/Oにする
TRISB = 0b11111111; // PortBを入力I/Oにする
nWPUEN = 0; // 弱プルアップをONにする
SSPCON1 = 0x28; // I2Cマスターモード指定
SSPSTAT = 0x00;
SSPADD = 0x09; // I2Cクロック周波数100KHz for 4MHz
LCD_int(); // LCD初期化
num=0;
printf("LCD Test"); // 上行に表示
while(1){
LCD_posyx(1,3); // 下行4文字目から
printf("%02X",num++); // 16進で2文字表示
__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); // 送信終了待ち
}
//********************************************************************
// 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; // 1行目
case 1: pcode=0xC0;break; // 2行目
}
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
}
*注意*
SCL SDAの2ピンはオープンドレインの回路にする必要があるため、TRISレジスタで入力モードに設定しておく必要があります。
SCL SDAの2ピンの配置は、PIC16F1455とPIC16F1459で異なります。注意が必要です。
pin10
pin9
pin11
pin13