TOP > MPLAB XC8編(PIC16F88) > I2CでEEPROMを使う(PIC16F88 XC8) > ソース

I2CでEEPROMを使う(ソース)
(PIC16F88 XC8)
作成日2012.6.10


以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。

// ========================== ここから ==============================
//ファイル名	I2C_EEPROM1.c
//作成日	2010.9.12
//更新日	2012.6.9
//作成者	mit.ueno
//バージョン	1.1
//コンパイラ	MPLAB XC8
//PIC	PIC16F88
//クロック	8MHz(INTIO)
//
//概要
//	EEPROM(AT24C1024B)の動作確認
//	I2C使用(マスタモード)ファームウェア制御
//	SCL/SDAの無通信時の状態
//		SCL output,1
//		SDA input,1
//
//	NOP() の数は20MHz動作前提
//
//使用ポート
//	RB1:EEPROM(SDA)
//	RB4:EEPROM(SCL)
//
//	RB2:LCD(RS)
//	RB3:LCD(E)
//	RA0:LCD(DB4)
//	RA1:LCD(DB5)
//	RA2:LCD(DB6)
//	RA3:LCD(DB7)
//
// LCD_V0   : 10KΩVRでGND
// LCD_R/W  : GND
// LCD_DB0-3: open
//
//	LCD表示形式
//		0123456789abcdef
//		W xxxxxxxxxxxxxx
//		R xxxxxxxxxxxxxx
//
// EEPROM_A1 : GND
// EEPROM_A2 : GND
// EEPROM_WP : GND
//

#include	"pic.h"

#define LCD_E  RB3
#define	LCD_RS RB2
#define I2C_SCL RB4
#define I2C_SDA RB1
#define I2C_SDA_TRIS TRISB1

// EEPROMアドレス(I2Cフォーマット)
#define EE_dev_addr 0xA0	// EEPROMアドレス
#define EE_P0_0 0x00	// EEPROMメモリアドレス最上位ビット:0
#define EE_P0_1 0x02	// EEPROMメモリアドレス最上位ビット:1

static void pic_init();

static void I2C_start();
static void I2C_send(unsigned char);
static unsigned char I2C_ackchk();
static void I2C_acksnd();
static void I2C_nacksnd();
static unsigned char I2C_rcv();
static void I2C_snd_char(unsigned char EE_P0 ,unsigned char addr1 ,unsigned char addr2 ,unsigned char send_data);
static unsigned char I2C_rcv_char(unsigned char EE_P0 ,unsigned char addr1 ,unsigned char addr2);
static void I2C_stop();

static void LCD_init();
static void LCD_ival();
static void LCD_cmd(unsigned char);
static void LCD_data(unsigned char);
static void LCD_hex(unsigned char, unsigned char);
static void LCD_send4(unsigned char);

static void wait_50us();
static void wait_1ms();
static void wait_ms(unsigned char);


__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & IESO_OFF & LVP_OFF);


const unsigned char hex_tbl[16] = "0123456789ABCDEF";


// ==================== メイン処理 ===========================
main()	{
	unsigned char c;

	pic_init();			// PICの初期化
	LCD_init();			// LCDの初期化
	LCD_ival();			// LCD初期表示

	// EEPROMに2バイト書き込む。そのデータをLCDに表示。
	LCD_hex(0x82, 0xA5);
	I2C_snd_char(EE_P0_0 ,0x00 ,0x00 ,0xA5);
	wait_ms(5);
	LCD_hex(0x84, 0x5B);
	I2C_snd_char(EE_P0_1 ,0xFF ,0x00 ,0x5B);
	wait_ms(5);

	// EEPROMより2バイト読み込み、そのデータをLCDに表示。
	c = I2C_rcv_char(EE_P0_0 ,0x00 ,0x00);		// read
	LCD_hex(0xC2, c);
	c = I2C_rcv_char(EE_P0_1 ,0xFF ,0x00);		// read
	LCD_hex(0xC4, c);

	while(1) {}
}


// ==================== PICの初期化 ===========================
static void pic_init() {
	OSCCON = 0x70;		// INTOSC 8MHz
	ANSEL  = 0x00;		// AN未使用
	TRISA = 0xF0;		// RA0-3:out
	TRISB = 0xE3;		// RB2-4:out SDAは通常input(開放)
	PORTA = 0x00;
	PORTB = 0x12;		// SCL=1,SDA=1

//	SSPCON = 0x2B;		// SSP enable & I2C Firmware Controlled Master mode
//	この設定をするとうまく動作しない

	return;
}

// ==================== I2C Start =============================
static void I2C_start() {
	I2C_SDA = 1;
	I2C_SDA_TRIS = 0;	// output
	I2C_SCL = 1;		// SCL high
	NOP();
	NOP();
	NOP();
	NOP();
	I2C_SDA = 0;		// SDA low : start
	NOP();
	NOP();
	NOP();
	NOP();
	I2C_SCL = 0;		// SCL low

	return;
}

// ==================== I2C Stop ==============================
static void I2C_stop() {
	I2C_SDA = 0;		// SDA low
	I2C_SDA_TRIS = 0;	// output
	I2C_SCL = 1;		// SCL high
	NOP();
	NOP();
	NOP();
	NOP();
	I2C_SDA_TRIS = 1;	// input(SDA high) : stop

	return;
}

// ==================== I2C Send ==============================
static void I2C_send(unsigned char send_data) {
	unsigned char i2c_data,i;

	I2C_SDA_TRIS = 0;	// SDA output

	i2c_data = send_data;
	for (i=8 ; i>0 ; i--) {
		if  (i2c_data & 0x80) {	// ビットセット
			I2C_SDA = 1;
		} else {
			I2C_SDA = 0;
		}
		i2c_data = i2c_data << 1;	// next bit set

		I2C_SCL = 1;	// 1ビット送信
		NOP();
		NOP();
		NOP();
		NOP();
		I2C_SCL = 0;
	}
	I2C_SDA_TRIS = 1;	// SDA input

	return;
}

// ==================== I2C Recive ============================
static unsigned char I2C_rcv() {
	unsigned char i2c_data,i;

	I2C_SDA_TRIS = 1;	// SDA input
	for (i=8 ; i>0 ; i--) {
		NOP();
		I2C_SCL = 1;	// 1ビット受信
		i2c_data = i2c_data <<1;
		if (PORTB & 0x02) {
			i2c_data = i2c_data | 0x01;
		} else {
			i2c_data = i2c_data & 0xFE;
		}
		I2C_SCL = 0;
	}

	return(i2c_data);
}

// ==================== I2C Send char ==========================
static void I2C_snd_char(unsigned char ee_p0 ,unsigned char addr1 ,unsigned char addr2 ,unsigned char send_data) {
	I2C_start();
	I2C_send(EE_dev_addr | ee_p0);	// スレーブアドレス & Write
	if  (I2C_ackchk()) {
		LCD_data('4');
	}
	I2C_send(addr1);		// 書き込みアドレス1
	if  (I2C_ackchk()) {
		LCD_data('5');
	}
	I2C_send(addr2);		// 書き込みアドレス2
	if  (I2C_ackchk()) {
		LCD_data('6');
	}
	I2C_send(send_data);	// 書き込み
	if  (I2C_ackchk()) {
		LCD_data('7');
	}

	I2C_stop();

	return;
}

// ==================== I2C Recive char ========================
static unsigned char I2C_rcv_char(unsigned char ee_p0 ,unsigned char addr1 ,unsigned char addr2) {
		unsigned char c;

		I2C_start();
		I2C_send(EE_dev_addr | ee_p0);		// スレーブアドレス & Write
		if  (I2C_ackchk()) {
			LCD_data('8');
		}
		I2C_send(addr1);		// 書き込みアドレス1
		if  (I2C_ackchk()) {
			LCD_data('9');
		}
		I2C_send(addr2);		// 書き込みアドレス2
		if  (I2C_ackchk()) {
			LCD_data('A');
		}

		I2C_start();
		I2C_send(EE_dev_addr | ee_p0 | 0x01);	// スレーブアドレス & Read
		if  (I2C_ackchk()) {
			LCD_data('B');
		}
		c = I2C_rcv();
		I2C_nacksnd();

		I2C_stop();

	return(c);
}

// ==================== I2C ACK check =========================
static unsigned char I2C_ackchk() {
	unsigned char i2c_data;

	I2C_SCL = 1;	// ACKビット受信
	NOP();
	i2c_data = PORTB & 0x02;
	I2C_SCL = 0;

	return(i2c_data);
}

// ==================== I2C ACK send ==========================
static void I2C_acksnd() {
	I2C_SDA = 0;		// ACK
	I2C_SDA_TRIS = 0;	// SDA output
	NOP();
	I2C_SCL = 1;		// ACK送信
	NOP();
	NOP();
	NOP();
	NOP();
	I2C_SCL = 0;
	I2C_SDA_TRIS = 1;	// SDA input

	return;
}

// ==================== I2C NACK send =========================
static void I2C_nacksnd() {
	I2C_SDA = 1;		// NACK
	I2C_SDA_TRIS = 0;	// SDA output
	I2C_SCL = 1;		// NACK送信
	NOP();
	I2C_SCL = 0;
	NOP();
	I2C_SDA_TRIS = 1;	// SDA input

	return;
}

// ==================== LCD 初期表示 ==========================
static void LCD_ival() {
//	0123456789abcdef
//	W
//	R

	LCD_cmd(0x80);
	LCD_data('W');
	LCD_cmd(0xC0);
	LCD_data('R');

	return;
}

// ==================== LCD 4bit 送信 =========================
static void LCD_send4(unsigned char c) {
	PORTA = (PORTA & 0xF0) | c;
	LCD_E = 1;
	NOP();
	LCD_E = 0;

	return;
}

// ==================== LCDコマンドWRITE =================
static void LCD_cmd(unsigned char cmd) {
	LCD_RS = 0;
	PORTA = (PORTA & 0xF0) | ((cmd >>4) & 0x0F);
	LCD_E = 1;			// 上位4ビット書き込み
	NOP();
	LCD_E = 0;

	PORTA = (PORTA & 0xF0) | (cmd & 0x0F);
	LCD_E = 1;			// 下位4ビット書き込み
	NOP();
	LCD_E = 0;

	wait_50us();

	return;
}


// ==================== LCDデータWRITE =================
static void LCD_data(unsigned char cmd) {
	LCD_RS = 1;
	PORTA = (PORTA & 0xF0) | ((cmd >>4) & 0x0F);
	LCD_E = 1;			// 上位4ビット書き込み
	NOP();
	LCD_E = 0;

	PORTA = (PORTA & 0xF0) | (cmd & 0x0F);
	LCD_E = 1;			// 下位4ビット書き込み
	NOP();
	LCD_E = 0;

	wait_50us();

	return;
}


// =============== 1バイトを16進数でLCDに出力 ==========
static void LCD_hex(unsigned char addr, unsigned char ad) {
	LCD_cmd(addr);
	LCD_data(hex_tbl[ad>>4 & 0x0F]);
	LCD_data(hex_tbl[ad & 0x0F]);
}


// ==================== LCDの初期化 ===========================
static void LCD_init() {
	wait_ms(15);
	LCD_E = 0;
	LCD_RS = 0;

	LCD_send4(0x03);	// DB4-7に'3'を出力(8bitモードに)@
	wait_ms(5);
	LCD_send4(0x03);	// DB4-7に'3'を出力(8bitモードに)A
	wait_ms(1);
	LCD_send4(0x03);	// DB4-7に'3'を出力(8bitモードに)B
	wait_ms(1);
	LCD_send4(0x02);	// DB4-7に'2'を出力(4bitモードに)
	wait_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
	wait_ms(2);

	return;
}

// ==================== 50μSウェイトルーチン =================
static void wait_50us() {
	unsigned char i;

	for	(i=32 ; i>0 ; i--) {}
	return;
}

// ==================== 1mSウェイトルーチン =================
static void wait_1ms() {
	unsigned char i;

	for	(i=179 ; i>0 ; i--) {
		NOP();
		NOP();
		NOP();
	}
	return;
}

// ==================== 1mS×ms ウェイトルーチン =============
static void wait_ms(unsigned char ms) {
	unsigned char c;
	for (c=ms ; c>0 ; c--) {
		wait_1ms();
	}
	return;
}
// ========================== ここまで ==============================