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

I2CでEEPROMを使う(ソース)
(PIC16F886 XC8)
作成日2012.6.24


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

// ========================== ここから ==============================
//ファイル名	I2C_EEPROM.c
//作成日	2010.10.9
//更新日	2012.6.23
//作成者	mit.ueno
//バージョン	1.1
//コンパイラ	MPLAB XC8
//PIC	PIC16F886
//クロック	8MHz(INTIO)
//
//概要
//	EEPROMの動作確認
//	I2C使用(マスタモード)
//
//使用ポート
//	RC3:RTC(SCL)
//	RC4:RTC(SDA)
//
//	RC6:LCD(RS)
//	RC7:LCD(E)
//	RB4:LCD(DB4)
//	RB5:LCD(DB5)
//	RB6:LCD(DB6)
//	RB7:LCD(DB7)
//
// LCD_V0   : 350ΩでGND
// LCD_R/W  : GND
// LCD_DB0-3: open
//

#include	"pic.h"

#define LCD_E  RC7
#define	LCD_RS RC6
#define I2C_SCL RC3
#define I2C_SDA RC4
#define I2C_SDA_TRIS TRISC4

#define EE_dev_addr 0xA0
#define EE_P0_0 0x00
#define EE_P0_1 0x02

static void pic_init();

static void I2C_start();
static void I2C_restart();
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_INTRC_NOCLKOUT & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & IESO_OFF & LVP_OFF);


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

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

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

	c = 0xAA;
	LCD_hex(0x82, c);
	I2C_snd_char(EE_P0_0 ,0xA1 ,0x00 ,c);
	wait_ms(5);
	c = 0xBB;
	LCD_hex(0x86, c);
	I2C_snd_char(EE_P0_1 ,0xA1 ,0x00 ,c);
	wait_ms(5);

	c = I2C_rcv_char(EE_P0_0 ,0xA1 ,0x00);		// read
	LCD_hex(0xC2, c);
	c = I2C_rcv_char(EE_P0_1 ,0xA1 ,0x00);		// read
	LCD_hex(0xC6, c);

	while(1) {}
}


// ==================== PICの初期化 ===========================
static void pic_init() {
	OSCCON = 0x70;		// INTOSC 8MHz
	ANSEL  = 0x00;		// AN未使用
	TRISB = 0x0F;		// RB4-7:out
	TRISC = 0x3F;		// RC3,6-7:out SDA/SCL:input
	PORTB = 0x00;
	PORTC = 0x00;

	SSPCON = 0x28;		// SSP enable & I2C Master mode, clock = FOSC / (4 * (SSPADD+1))
	SSPADD = 0x02;		// 0x00だと動作しない

	return;
}

// ==================== I2C Start =============================
static void I2C_start() {
	SEN = 1;
	while (SEN) {}

	return;
}

// ==================== I2C Start Repeat ======================
static void I2C_restart() {
	SSPIF = 0;
	RSEN = 1;
	while (RSEN) {}

	return;
}

// ==================== I2C Stop ==============================
static void I2C_stop() {
	SSPIF = 0;
	PEN = 1;
	while (PEN) {}
	SSPIF = 0;

	return;
}

// ==================== I2C Send ==============================
static void I2C_send(unsigned char send_data) {
	SSPIF = 0;
	SSPBUF = send_data;
	while (!SSPIF) {}

	return;
}

// ==================== I2C Recive ============================
static unsigned char I2C_rcv() {
	SSPIF = 0;
	RCEN = 1;
	while (RCEN) {}

	return(SSPBUF);
}

// ==================== 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;

	if (ACKSTAT) {
		i2c_data = 0xFF;
	} else {
		i2c_data = 0x00;
	}

	return(i2c_data);
}

// ==================== I2C ACK send ==========================
static void I2C_acksnd() {
	ACKDT = 0;
	ACKEN = 1;
	while (ACKEN) {}

	return;
}

// ==================== I2C NACK send =========================
static void I2C_nacksnd() {
	ACKDT = 1;
	ACKEN = 1;
	while (ACKEN) {}

	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) {
	PORTB = (PORTB & 0x0F) | (c << 4);
	LCD_E = 1;
	NOP();
	LCD_E = 0;

	return;
}

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

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

	wait_50us();

	return;
}


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

	PORTB = (PORTB & 0x0F) | (cmd <<4);
	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]);
	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;
}
// ========================== ここまで ==============================