PIC18F Trainer - MCP23008 I2C 8-Bit I/O Expander.

0.Contents

PIC18F Trainer : PIC18F2620 @8MHz Internal oscillator.

1.MCP23008 Write in Byte Mode.

// Configuration register.
#pragma config IESO = OFF, FCMEN = OFF, OSC = INTIO7
#pragma config BORV = 3, BOREN = OFF, PWRT = OFF
#pragma config WDTPS = 32768, WDT = OFF
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC
#pragma config DEBUG = OFF, XINST = OFF, LVP = OFF, STVREN = ON
#pragma config CP3 = OFF, CP2 = OFF, CP1 = OFF, CP0 = OFF
#pragma config CPD = OFF, CPB = OFF
#pragma config WRT3 = OFF, WRT2 = OFF, WRT1 = OFF, WRT0 = OFF
#pragma config WRTD = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR3 = OFF, EBTR2 = OFF, EBTR1 = OFF, EBTR0 = OFF
#pragma config EBTRB = OFF

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
// PIC18F2620 - Compile with XC8(v1.44).
// PIC18F2620 - @8MHz Internal oscillator.

// MCP23008 - 8-bit I/O Expander - Write in Byte Mode.

// PIC18F Trainer Jumpers.
// JP1 - SCL Close.
// JP2 - SDA Close.
// JP3 - VEE Not use.
// JP4 - BCKL Not use.

// Definitions.
// I2C Port.
#define I2C_SCL					LATCbits.LATC3
#define I2C_SDA					LATCbits.LATC4
#define I2C_SCL_TRIS			TRISCbits.TRISC3
#define I2C_SDA_TRIS			TRISCbits.TRISC4
// MCP23008 Port.
#define MCP23008_RESET			LATBbits.LATB1
#define MCP23008_RESET_TRIS		TRISBbits.TRISB1
// MCP23008 Address Select Bits A2 A1 A0.
#define MCP23008_ADDRESS_40		0x40
#define MCP23008_ADDRESS_42		0x42
#define MCP23008_ADDRESS_44		0x44
#define MCP23008_ADDRESS_46		0x46
#define MCP23008_ADDRESS_48		0x48
#define MCP23008_ADDRESS_4A		0x4A
#define MCP23008_ADDRESS_4C		0x4C
#define MCP23008_ADDRESS_4E		0x4E
#define MCP23008_WRITE			0x00
#define MCP23008_READ			0x01
// MCP23008 Configuration Registers.
#define MCP23008_IODIR			0x00
#define MCP23008_IPOL			0x01
#define MCP23008_GPINTEN		0x02
#define MCP23008_DEFVAL			0x03
#define MCP23008_INTCON			0x04
#define MCP23008_IOCON			0x05
#define MCP23008_GPPU			0x06
#define MCP23008_INTF			0x07
#define MCP23008_INTCAP			0x08
#define MCP23008_GPIO			0x09
#define MCP23008_OLAT			0x0A
// MCP23008 Configuration Bits.
#define MCP23008_SEQOP			0x20
#define MCP23008_HAEN			0x08
#define MCP23008_ODR			0x04
#define MCP23008_INTPOL			0x02

// Function prototypes.
void i2c_initializeMaster(void);
uint8_t i2c_read(void);
void i2c_restart(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write(uint8_t u8Data);
void mcp23008_initialize(uint8_t u8Address);
uint8_t mcp23008_readData(uint8_t u8Address);
void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data);
void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register, uint8_t u8Data);
void mcu_initialize(void);

// Main.
int main(void)
{
	mcu_initialize();
	i2c_initializeMaster();
	mcp23008_initialize(MCP23008_ADDRESS_40);
	// Configure MCP23008 in Byte Mode.
	mcp23008_writeRegister(MCP23008_ADDRESS_40, MCP23008_IOCON, MCP23008_SEQOP);

	i2c_start();
	i2c_write(MCP23008_ADDRESS_40 | MCP23008_WRITE);
	i2c_write(MCP23008_OLAT);
	while(1){
		i2c_write(0x00);
		i2c_write(0x01);
	}
	return(0);
}

// Functions.
void i2c_initializeMaster(void)
{
	// I2C - Master.
	SSPSTAT = 0x80;
	SSPCON1 = 0x28;
	SSPCON2 = 0x00;
	// SSPADD = 0x13 ~100kHz.
	SSPADD = 0x13;
}

void i2c_start(void)
{
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
	SSPCON2bits.SEN = 1;
	while(SSPCON2bits.SEN);
}

void i2c_stop(void)
{
	SSPCON2bits.PEN = 1;
	while(SSPCON2bits.PEN);
}

void i2c_write(uint8_t u8Data)
{
	SSPBUF = u8Data;
	while(SSPSTATbits.BF);
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void mcp23008_initialize(uint8_t u8Address)
{
	MCP23008_RESET = 1;
	__delay_ms(1);

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	// IODIR - I/O Direction - 0b11111111 (Default).
	// IO7.0 = 0 PIN as configured as Output.
	// IO7.0 = 1 PIN as configured as Input.
	i2c_write(MCP23008_IODIR);
	i2c_write(0b00000000);
	// IPOL - Input Polarity - 0b00000000 (Default).
	// IP7.0 = 0 GPIO Register bit will reflect the same logic state of the input pin.
	// IP7.0 = 1 GPIO Register bit will reflect the opposite logic state of the input pin.
	i2c_write(0b00000000);
	// GPINTEN - Interrupt-on-change - 0b00000000 (Default).
	// GPINT7.0 = 0 Disable GPIO input PIN for interrupt-on-change event.
	// GPINT7.0 = 1 Enable GPIO input PIN for interrupt-on-change event.
	i2c_write(0b00000000);
	// DEFVAL - Default Compare Interrupt-on-change - 0b00000000 (Default).
	i2c_write(0b00000000);
	// INTCON - Interrupt Control - 0b00000000 (Default).
	// IOC7.0 = 0 PIN value is compared against the previous PIN value.
	// IOC7.0 = 1 Control how the associated PIN value is compared for interrupt-on-change.
	i2c_write(0b00000000);
	// IOCON - Configuration - 0b--00000- (Default).
	// SEQOP - Sequential Operation - 0 = Sequential enable, 1 = Sequential disable.
	// DISSLW - Slew Rate Control for SDA output - 0 = Slew rate enabled, 1 = Slew rate disabled.
	// ODR - Open-drain PIN output - 0 = Active driver output, 1 = Open-drain output.
	// INTPOL - Set the polarity of the INT output pin - 0 = Active LOW, 1 = Active HIGH.
	i2c_write(0b00000000);
	// GPPU - Pull-up resistor - 0b00000000 (Default).
	// PU7.0 = 0 Pull-up disabled.
	// PU7.0 = 1 Pull-up enabled.
	i2c_write(0b00000000);
	// INTF - Interrupt Flag - 0b00000000 (Default) - Read-only.
	// INT7.0 = 0 Interrupt not pending.
	// INT7.0 = 1 PIN caused interrupt.
	i2c_write(0b00000000);
	// INTCAP - Interrupt Capture - 0b00000000 (Default) Read-only.
	// ICP7.0 = 0 Logic-low.
	// ICP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// GPIO - Port GPIO - 0b00000000 (Default).
	// GP7.0 = 0 Logic-low.
	// GP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// OLAT - Output Latch - 0b00000000 (Default).
	// OL7.0 = 0 Logic-low.
	// OL7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	i2c_stop();
}

uint8_t mcp23008_readData(uint8_t u8Address)
{
	uint8_t u8Read;

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_GPIO);
	i2c_restart();
	i2c_write((uint8_t)(u8Address | MCP23008_READ));
	u8Read = i2c_read();
	i2c_stop();
	
	return(u8Read);
}

void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_OLAT);
	i2c_write(u8Data);
	i2c_stop();
}

void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register,  uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(u8Register);
	i2c_write(u8Data);
	i2c_stop();
}

void mcu_initialize(void)
{
	// Internal Oscillator 8MHz.
	OSCCONbits.IRCF2  = 1;
	OSCCONbits.IRCF1  = 1;
	OSCCONbits.IRCF0  = 1;
	OSCTUNEbits.PLLEN = 0;
	while(!OSCCONbits.IOFS);
	// I2C Port.
	I2C_SDA = 0;
	I2C_SCL = 0;
	I2C_SDA_TRIS = 1;
	I2C_SCL_TRIS = 1;
	// MCP23008 RESET.
	MCP23008_RESET = 0;
	MCP23008_RESET_TRIS = 0;
}
Size : 304bytes.
I2C @100kHz

2.MCP23008 Write in Sequential Mode.

// Configuration register.
#pragma config IESO = OFF, FCMEN = OFF, OSC = INTIO7
#pragma config BORV = 3, BOREN = OFF, PWRT = OFF
#pragma config WDTPS = 32768, WDT = OFF
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC
#pragma config DEBUG = OFF, XINST = OFF, LVP = OFF, STVREN = ON
#pragma config CP3 = OFF, CP2 = OFF, CP1 = OFF, CP0 = OFF
#pragma config CPD = OFF, CPB = OFF
#pragma config WRT3 = OFF, WRT2 = OFF, WRT1 = OFF, WRT0 = OFF
#pragma config WRTD = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR3 = OFF, EBTR2 = OFF, EBTR1 = OFF, EBTR0 = OFF
#pragma config EBTRB = OFF

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
// PIC18F2620 - Compile with XC8(v1.44).
// PIC18F2620 - @8MHz Internal oscillator.

// MCP23008 - 8-bit I/O Expander - Write in Sequential Mode.

// PIC18F Trainer Jumpers.
// JP1 - SCL Close.
// JP2 - SDA Close.
// JP3 - VEE Not use.
// JP4 - BCKL Not use.

// Definitions.
// I2C Port.
#define I2C_SCL					LATCbits.LATC3
#define I2C_SDA					LATCbits.LATC4
#define I2C_SCL_TRIS			TRISCbits.TRISC3
#define I2C_SDA_TRIS			TRISCbits.TRISC4
// MCP23008 Port.
#define MCP23008_RESET			LATBbits.LATB1
#define MCP23008_RESET_TRIS		TRISBbits.TRISB1
// MCP23008 Address Select Bits A2 A1 A0.
#define MCP23008_ADDRESS_40		0x40
#define MCP23008_ADDRESS_42		0x42
#define MCP23008_ADDRESS_44		0x44
#define MCP23008_ADDRESS_46		0x46
#define MCP23008_ADDRESS_48		0x48
#define MCP23008_ADDRESS_4A		0x4A
#define MCP23008_ADDRESS_4C		0x4C
#define MCP23008_ADDRESS_4E		0x4E
#define MCP23008_WRITE			0x00
#define MCP23008_READ			0x01
// MCP23008 Configuration Registers.
#define MCP23008_IODIR			0x00
#define MCP23008_IPOL			0x01
#define MCP23008_GPINTEN		0x02
#define MCP23008_DEFVAL			0x03
#define MCP23008_INTCON			0x04
#define MCP23008_IOCON			0x05
#define MCP23008_GPPU			0x06
#define MCP23008_INTF			0x07
#define MCP23008_INTCAP			0x08
#define MCP23008_GPIO			0x09
#define MCP23008_OLAT			0x0A
// MCP23008 Configuration Bits.
#define MCP23008_SEQOP			0x20
#define MCP23008_HAEN			0x08
#define MCP23008_ODR			0x04
#define MCP23008_INTPOL			0x02

// Function prototypes.
void i2c_initializeMaster(void);
uint8_t i2c_read(void);
void i2c_restart(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write(uint8_t u8Data);
void mcp23008_initialize(uint8_t u8Address);
uint8_t mcp23008_readData(uint8_t u8Address);
void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data);
void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register, uint8_t u8Data);
void mcu_initialize(void);

// Main.
int main(void)
{
	mcu_initialize();
	i2c_initializeMaster();
	mcp23008_initialize(MCP23008_ADDRESS_40);

	while(1){
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x00);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x01);
	}
	return(0);
}

// Functions.
void i2c_initializeMaster(void)
{
	// I2C - Master.
	SSPSTAT = 0x80;
	SSPCON1 = 0x28;
	SSPCON2 = 0x00;
	// SSPADD = 0x13 ~100kHz.
	SSPADD = 0x13;
}

void i2c_start(void)
{
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
	SSPCON2bits.SEN = 1;
	while(SSPCON2bits.SEN);
}

void i2c_stop(void)
{
	SSPCON2bits.PEN = 1;
	while(SSPCON2bits.PEN);
}

void i2c_write(uint8_t u8Data)
{
	SSPBUF = u8Data;
	while(SSPSTATbits.BF);
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void mcp23008_initialize(uint8_t u8Address)
{
	MCP23008_RESET = 1;
	__delay_ms(1);

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	// IODIR - I/O Direction - 0b11111111 (Default).
	// IO7.0 = 0 PIN as configured as Output.
	// IO7.0 = 1 PIN as configured as Input.
	i2c_write(MCP23008_IODIR);
	i2c_write(0b00000000);
	// IPOL - Input Polarity - 0b00000000 (Default).
	// IP7.0 = 0 GPIO Register bit will reflect the same logic state of the input pin.
	// IP7.0 = 1 GPIO Register bit will reflect the opposite logic state of the input pin.
	i2c_write(0b00000000);
	// GPINTEN - Interrupt-on-change - 0b00000000 (Default).
	// GPINT7.0 = 0 Disable GPIO input PIN for interrupt-on-change event.
	// GPINT7.0 = 1 Enable GPIO input PIN for interrupt-on-change event.
	i2c_write(0b00000000);
	// DEFVAL - Default Compare Interrupt-on-change - 0b00000000 (Default).
	i2c_write(0b00000000);
	// INTCON - Interrupt Control - 0b00000000 (Default).
	// IOC7.0 = 0 PIN value is compared against the previous PIN value.
	// IOC7.0 = 1 Control how the associated PIN value is compared for interrupt-on-change.
	i2c_write(0b00000000);
	// IOCON - Configuration - 0b--00000- (Default).
	// SEQOP - Sequential Operation - 0 = Sequential enable, 1 = Sequential disable.
	// DISSLW - Slew Rate Control for SDA output - 0 = Slew rate enabled, 1 = Slew rate disabled.
	// ODR - Open-drain PIN output - 0 = Active driver output, 1 = Open-drain output.
	// INTPOL - Set the polarity of the INT output pin - 0 = Active LOW, 1 = Active HIGH.
	i2c_write(0b00000000);
	// GPPU - Pull-up resistor - 0b00000000 (Default).
	// PU7.0 = 0 Pull-up disabled.
	// PU7.0 = 1 Pull-up enabled.
	i2c_write(0b00000000);
	// INTF - Interrupt Flag - 0b00000000 (Default) - Read-only.
	// INT7.0 = 0 Interrupt not pending.
	// INT7.0 = 1 PIN caused interrupt.
	i2c_write(0b00000000);
	// INTCAP - Interrupt Capture - 0b00000000 (Default) Read-only.
	// ICP7.0 = 0 Logic-low.
	// ICP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// GPIO - Port GPIO - 0b00000000 (Default).
	// GP7.0 = 0 Logic-low.
	// GP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// OLAT - Output Latch - 0b00000000 (Default).
	// OL7.0 = 0 Logic-low.
	// OL7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	i2c_stop();
}

uint8_t mcp23008_readData(uint8_t u8Address)
{
	uint8_t u8Read;

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_GPIO);
	i2c_restart();
	i2c_write((uint8_t)(u8Address | MCP23008_READ));
	u8Read = i2c_read();
	i2c_stop();
	
	return(u8Read);
}

void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_OLAT);
	i2c_write(u8Data);
	i2c_stop();
}

void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register,  uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(u8Register);
	i2c_write(u8Data);
	i2c_stop();
}

void mcu_initialize(void)
{
	// Internal Oscillator 8MHz.
	OSCCONbits.IRCF2  = 1;
	OSCCONbits.IRCF1  = 1;
	OSCCONbits.IRCF0  = 1;
	OSCTUNEbits.PLLEN = 0;
	while(!OSCCONbits.IOFS);
	// I2C Port.
	I2C_SDA = 0;
	I2C_SCL = 0;
	I2C_SDA_TRIS = 1;
	I2C_SCL_TRIS = 1;
	// MCP23008 RESET.
	MCP23008_RESET = 0;
	MCP23008_RESET_TRIS = 0;
}
Size : 282bytes.
I2C @100kHz

3.MCP23008 Chase in Byte Mode.

// Configuration register.
#pragma config IESO = OFF, FCMEN = OFF, OSC = INTIO7
#pragma config BORV = 3, BOREN = OFF, PWRT = OFF
#pragma config WDTPS = 32768, WDT = OFF
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC
#pragma config DEBUG = OFF, XINST = OFF, LVP = OFF, STVREN = ON
#pragma config CP3 = OFF, CP2 = OFF, CP1 = OFF, CP0 = OFF
#pragma config CPD = OFF, CPB = OFF
#pragma config WRT3 = OFF, WRT2 = OFF, WRT1 = OFF, WRT0 = OFF
#pragma config WRTD = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR3 = OFF, EBTR2 = OFF, EBTR1 = OFF, EBTR0 = OFF
#pragma config EBTRB = OFF

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
// PIC18F2620 - Compile with XC8(v1.44).
// PIC18F2620 - @8MHz Internal oscillator.

// MCP23008 - 8-bit I/O Expander - Chase in Byte Mode.

// PIC18F Trainer Jumpers.
// JP1 - SCL Close.
// JP2 - SDA Close.
// JP3 - VEE Not use.
// JP4 - BCKL Not use.

// Definitions.
// I2C Port.
#define I2C_SCL					LATCbits.LATC3
#define I2C_SDA					LATCbits.LATC4
#define I2C_SCL_TRIS			TRISCbits.TRISC3
#define I2C_SDA_TRIS			TRISCbits.TRISC4
// MCP23008 Port.
#define MCP23008_RESET			LATBbits.LATB1
#define MCP23008_RESET_TRIS		TRISBbits.TRISB1
// MCP23008 Address Select Bits A2 A1 A0.
#define MCP23008_ADDRESS_40		0x40
#define MCP23008_ADDRESS_42		0x42
#define MCP23008_ADDRESS_44		0x44
#define MCP23008_ADDRESS_46		0x46
#define MCP23008_ADDRESS_48		0x48
#define MCP23008_ADDRESS_4A		0x4A
#define MCP23008_ADDRESS_4C		0x4C
#define MCP23008_ADDRESS_4E		0x4E
#define MCP23008_WRITE			0x00
#define MCP23008_READ			0x01
// MCP23008 Configuration Registers.
#define MCP23008_IODIR			0x00
#define MCP23008_IPOL			0x01
#define MCP23008_GPINTEN		0x02
#define MCP23008_DEFVAL			0x03
#define MCP23008_INTCON			0x04
#define MCP23008_IOCON			0x05
#define MCP23008_GPPU			0x06
#define MCP23008_INTF			0x07
#define MCP23008_INTCAP			0x08
#define MCP23008_GPIO			0x09
#define MCP23008_OLAT			0x0A
// MCP23008 Configuration Bits.
#define MCP23008_SEQOP			0x20
#define MCP23008_HAEN			0x08
#define MCP23008_ODR			0x04
#define MCP23008_INTPOL			0x02
//
#define DELAY					200

// Function prototypes.
void i2c_initializeMaster(void);
uint8_t i2c_read(void);
void i2c_restart(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write(uint8_t u8Data);
void mcp23008_initialize(uint8_t u8Address);
uint8_t mcp23008_readData(uint8_t u8Address);
void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data);
void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register, uint8_t u8Data);
void mcu_initialize(void);

// Main.
int main(void)
{
	mcu_initialize();
	i2c_initializeMaster();
	mcp23008_initialize(MCP23008_ADDRESS_40);
	// Configure MCP23008 in Byte Mode.
	mcp23008_writeRegister(MCP23008_ADDRESS_40, MCP23008_IOCON, MCP23008_SEQOP);

	i2c_start();
	i2c_write(MCP23008_ADDRESS_40 | MCP23008_WRITE);
	i2c_write(MCP23008_OLAT);
	while(1){
		i2c_write(0x01);
		__delay_ms(DELAY);
		i2c_write(0x02);
		__delay_ms(DELAY);
		i2c_write(0x04);
		__delay_ms(DELAY);
		i2c_write(0x08);
		__delay_ms(DELAY);
		i2c_write(0x10);
		__delay_ms(DELAY);
		i2c_write(0x20);
		__delay_ms(DELAY);
		i2c_write(0x40);
		__delay_ms(DELAY);
		i2c_write(0x80);
		__delay_ms(DELAY);
		i2c_write(0x40);
		__delay_ms(DELAY);
		i2c_write(0x20);
		__delay_ms(DELAY);
		i2c_write(0x10);
		__delay_ms(DELAY);
		i2c_write(0x08);
		__delay_ms(DELAY);
		i2c_write(0x04);
		__delay_ms(DELAY);
		i2c_write(0x02);
		__delay_ms(DELAY);
	}
	return(0);
}

// Functions.
void i2c_initializeMaster(void)
{
	// I2C - Master.
	SSPSTAT = 0x80;
	SSPCON1 = 0x28;
	SSPCON2 = 0x00;
	// SSPADD = 0x13 ~100kHz.
	SSPADD = 0x13;
}

void i2c_start(void)
{
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
	SSPCON2bits.SEN = 1;
	while(SSPCON2bits.SEN);
}

void i2c_stop(void)
{
	SSPCON2bits.PEN = 1;
	while(SSPCON2bits.PEN);
}

void i2c_write(uint8_t u8Data)
{
	SSPBUF = u8Data;
	while(SSPSTATbits.BF);
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void mcp23008_initialize(uint8_t u8Address)
{
	MCP23008_RESET = 1;
	__delay_ms(1);

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	// IODIR - I/O Direction - 0b11111111 (Default).
	// IO7.0 = 0 PIN as configured as Output.
	// IO7.0 = 1 PIN as configured as Input.
	i2c_write(MCP23008_IODIR);
	i2c_write(0b00000000);
	// IPOL - Input Polarity - 0b00000000 (Default).
	// IP7.0 = 0 GPIO Register bit will reflect the same logic state of the input pin.
	// IP7.0 = 1 GPIO Register bit will reflect the opposite logic state of the input pin.
	i2c_write(0b00000000);
	// GPINTEN - Interrupt-on-change - 0b00000000 (Default).
	// GPINT7.0 = 0 Disable GPIO input PIN for interrupt-on-change event.
	// GPINT7.0 = 1 Enable GPIO input PIN for interrupt-on-change event.
	i2c_write(0b00000000);
	// DEFVAL - Default Compare Interrupt-on-change - 0b00000000 (Default).
	i2c_write(0b00000000);
	// INTCON - Interrupt Control - 0b00000000 (Default).
	// IOC7.0 = 0 PIN value is compared against the previous PIN value.
	// IOC7.0 = 1 Control how the associated PIN value is compared for interrupt-on-change.
	i2c_write(0b00000000);
	// IOCON - Configuration - 0b--00000- (Default).
	// SEQOP - Sequential Operation - 0 = Sequential enable, 1 = Sequential disable.
	// DISSLW - Slew Rate Control for SDA output - 0 = Slew rate enabled, 1 = Slew rate disabled.
	// ODR - Open-drain PIN output - 0 = Active driver output, 1 = Open-drain output.
	// INTPOL - Set the polarity of the INT output pin - 0 = Active LOW, 1 = Active HIGH.
	i2c_write(0b00000000);
	// GPPU - Pull-up resistor - 0b00000000 (Default).
	// PU7.0 = 0 Pull-up disabled.
	// PU7.0 = 1 Pull-up enabled.
	i2c_write(0b00000000);
	// INTF - Interrupt Flag - 0b00000000 (Default) - Read-only.
	// INT7.0 = 0 Interrupt not pending.
	// INT7.0 = 1 PIN caused interrupt.
	i2c_write(0b00000000);
	// INTCAP - Interrupt Capture - 0b00000000 (Default) Read-only.
	// ICP7.0 = 0 Logic-low.
	// ICP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// GPIO - Port GPIO - 0b00000000 (Default).
	// GP7.0 = 0 Logic-low.
	// GP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// OLAT - Output Latch - 0b00000000 (Default).
	// OL7.0 = 0 Logic-low.
	// OL7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	i2c_stop();
}

uint8_t mcp23008_readData(uint8_t u8Address)
{
	uint8_t u8Read;

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_GPIO);
	i2c_restart();
	i2c_write((uint8_t)(u8Address | MCP23008_READ));
	u8Read = i2c_read();
	i2c_stop();
	
	return(u8Read);
}

void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_OLAT);
	i2c_write(u8Data);
	i2c_stop();
}

void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register,  uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(u8Register);
	i2c_write(u8Data);
	i2c_stop();
}

void mcu_initialize(void)
{
	// Internal Oscillator 8MHz.
	OSCCONbits.IRCF2  = 1;
	OSCCONbits.IRCF1  = 1;
	OSCCONbits.IRCF0  = 1;
	OSCTUNEbits.PLLEN = 0;
	while(!OSCCONbits.IOFS);
	// I2C Port.
	I2C_SDA = 0;
	I2C_SCL = 0;
	I2C_SDA_TRIS = 1;
	I2C_SCL_TRIS = 1;
	// MCP23008 RESET.
	MCP23008_RESET = 0;
	MCP23008_RESET_TRIS = 0;
}
Size : 712bytes.

4.MCP23008 Chase in Sequential Mode.

// Configuration register.
#pragma config IESO = OFF, FCMEN = OFF, OSC = INTIO7
#pragma config BORV = 3, BOREN = OFF, PWRT = OFF
#pragma config WDTPS = 32768, WDT = OFF
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC
#pragma config DEBUG = OFF, XINST = OFF, LVP = OFF, STVREN = ON
#pragma config CP3 = OFF, CP2 = OFF, CP1 = OFF, CP0 = OFF
#pragma config CPD = OFF, CPB = OFF
#pragma config WRT3 = OFF, WRT2 = OFF, WRT1 = OFF, WRT0 = OFF
#pragma config WRTD = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR3 = OFF, EBTR2 = OFF, EBTR1 = OFF, EBTR0 = OFF
#pragma config EBTRB = OFF

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
// PIC18F2620 - Compile with XC8(v1.44).
// PIC18F2620 - @8MHz Internal oscillator.

// MCP23008 - 8-bit I/O Expander - Chase in Sequential Mode.

// PIC18F Trainer Jumpers.
// JP1 - SCL Close.
// JP2 - SDA Close.
// JP3 - VEE Not use.
// JP4 - BCKL Not use.

// Definitions.
// I2C Port.
#define I2C_SCL					LATCbits.LATC3
#define I2C_SDA					LATCbits.LATC4
#define I2C_SCL_TRIS			TRISCbits.TRISC3
#define I2C_SDA_TRIS			TRISCbits.TRISC4
// MCP23008 Port.
#define MCP23008_RESET			LATBbits.LATB1
#define MCP23008_RESET_TRIS		TRISBbits.TRISB1
// MCP23008 Address Select Bits A2 A1 A0.
#define MCP23008_ADDRESS_40		0x40
#define MCP23008_ADDRESS_42		0x42
#define MCP23008_ADDRESS_44		0x44
#define MCP23008_ADDRESS_46		0x46
#define MCP23008_ADDRESS_48		0x48
#define MCP23008_ADDRESS_4A		0x4A
#define MCP23008_ADDRESS_4C		0x4C
#define MCP23008_ADDRESS_4E		0x4E
#define MCP23008_WRITE			0x00
#define MCP23008_READ			0x01
// MCP23008 Configuration Registers.
#define MCP23008_IODIR			0x00
#define MCP23008_IPOL			0x01
#define MCP23008_GPINTEN		0x02
#define MCP23008_DEFVAL			0x03
#define MCP23008_INTCON			0x04
#define MCP23008_IOCON			0x05
#define MCP23008_GPPU			0x06
#define MCP23008_INTF			0x07
#define MCP23008_INTCAP			0x08
#define MCP23008_GPIO			0x09
#define MCP23008_OLAT			0x0A
// MCP23008 Configuration Bits.
#define MCP23008_SEQOP			0x20
#define MCP23008_HAEN			0x08
#define MCP23008_ODR			0x04
#define MCP23008_INTPOL			0x02
//
#define DELAY					200

// Function prototypes.
void i2c_initializeMaster(void);
uint8_t i2c_read(void);
void i2c_restart(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write(uint8_t u8Data);
void mcp23008_initialize(uint8_t u8Address);
uint8_t mcp23008_readData(uint8_t u8Address);
void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data);
void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register, uint8_t u8Data);
void mcu_initialize(void);

// Main.
int main(void)
{
	mcu_initialize();
	i2c_initializeMaster();
	mcp23008_initialize(MCP23008_ADDRESS_40);

	while(1){
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x01);
		__delay_ms(DELAY);        
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x02);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x04);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x08);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x10);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x20);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x40);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x80);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x40);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x20);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x10);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x08);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x04);
		__delay_ms(DELAY);
		mcp23008_writeData(MCP23008_ADDRESS_40, 0x02);
		__delay_ms(DELAY);
	}
	return(0);
}

// Functions.
void i2c_initializeMaster(void)
{
	// I2C - Master.
	SSPSTAT = 0x80;
	SSPCON1 = 0x28;
	SSPCON2 = 0x00;
	// SSPADD = 0x13 ~100kHz.
	SSPADD = 0x13;
}

void i2c_start(void)
{
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
	SSPCON2bits.SEN = 1;
	while(SSPCON2bits.SEN);
}

void i2c_stop(void)
{
	SSPCON2bits.PEN = 1;
	while(SSPCON2bits.PEN);
}

void i2c_write(uint8_t u8Data)
{
	SSPBUF = u8Data;
	while(SSPSTATbits.BF);
	while((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void mcp23008_initialize(uint8_t u8Address)
{
	MCP23008_RESET = 1;
	__delay_ms(1);

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	// IODIR - I/O Direction - 0b11111111 (Default).
	// IO7.0 = 0 PIN as configured as Output.
	// IO7.0 = 1 PIN as configured as Input.
	i2c_write(MCP23008_IODIR);
	i2c_write(0b00000000);
	// IPOL - Input Polarity - 0b00000000 (Default).
	// IP7.0 = 0 GPIO Register bit will reflect the same logic state of the input pin.
	// IP7.0 = 1 GPIO Register bit will reflect the opposite logic state of the input pin.
	i2c_write(0b00000000);
	// GPINTEN - Interrupt-on-change - 0b00000000 (Default).
	// GPINT7.0 = 0 Disable GPIO input PIN for interrupt-on-change event.
	// GPINT7.0 = 1 Enable GPIO input PIN for interrupt-on-change event.
	i2c_write(0b00000000);
	// DEFVAL - Default Compare Interrupt-on-change - 0b00000000 (Default).
	i2c_write(0b00000000);
	// INTCON - Interrupt Control - 0b00000000 (Default).
	// IOC7.0 = 0 PIN value is compared against the previous PIN value.
	// IOC7.0 = 1 Control how the associated PIN value is compared for interrupt-on-change.
	i2c_write(0b00000000);
	// IOCON - Configuration - 0b--00000- (Default).
	// SEQOP - Sequential Operation - 0 = Sequential enable, 1 = Sequential disable.
	// DISSLW - Slew Rate Control for SDA output - 0 = Slew rate enabled, 1 = Slew rate disabled.
	// ODR - Open-drain PIN output - 0 = Active driver output, 1 = Open-drain output.
	// INTPOL - Set the polarity of the INT output pin - 0 = Active LOW, 1 = Active HIGH.
	i2c_write(0b00000000);
	// GPPU - Pull-up resistor - 0b00000000 (Default).
	// PU7.0 = 0 Pull-up disabled.
	// PU7.0 = 1 Pull-up enabled.
	i2c_write(0b00000000);
	// INTF - Interrupt Flag - 0b00000000 (Default) - Read-only.
	// INT7.0 = 0 Interrupt not pending.
	// INT7.0 = 1 PIN caused interrupt.
	i2c_write(0b00000000);
	// INTCAP - Interrupt Capture - 0b00000000 (Default) Read-only.
	// ICP7.0 = 0 Logic-low.
	// ICP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// GPIO - Port GPIO - 0b00000000 (Default).
	// GP7.0 = 0 Logic-low.
	// GP7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	// OLAT - Output Latch - 0b00000000 (Default).
	// OL7.0 = 0 Logic-low.
	// OL7.0 = 1 Logic-high.
	i2c_write(0b00000000);
	i2c_stop();
}

uint8_t mcp23008_readData(uint8_t u8Address)
{
	uint8_t u8Read;

	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_GPIO);
	i2c_restart();
	i2c_write((uint8_t)(u8Address | MCP23008_READ));
	u8Read = i2c_read();
	i2c_stop();
	
	return(u8Read);
}

void mcp23008_writeData(uint8_t u8Address, uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(MCP23008_OLAT);
	i2c_write(u8Data);
	i2c_stop();
}

void mcp23008_writeRegister(uint8_t u8Address, uint8_t u8Register,  uint8_t u8Data)
{
	i2c_start();
	i2c_write((uint8_t)(u8Address | MCP23008_WRITE));
	i2c_write(u8Register);
	i2c_write(u8Data);
	i2c_stop();
}

void mcu_initialize(void)
{
	// Internal Oscillator 8MHz.
	OSCCONbits.IRCF2  = 1;
	OSCCONbits.IRCF1  = 1;
	OSCCONbits.IRCF0  = 1;
	OSCTUNEbits.PLLEN = 0;
	while(!OSCCONbits.IOFS);
	// I2C Port.
	I2C_SDA = 0;
	I2C_SCL = 0;
	I2C_SDA_TRIS = 1;
	I2C_SCL_TRIS = 1;
	// MCP23008 RESET.
	MCP23008_RESET = 0;
	MCP23008_RESET_TRIS = 0;
}
Size : 738bytes.

01.2018