/*  Filename     ZMCP23008.C
    Description  MCP23008 Example Program 
    Hardware     SLAB-51 + MCP23008
    Clock        11.0592 Mhz
    Compiler     Keil PK51 v7.10
    Engineer     Kriangsak B.
    Company      Sila Research Co.,Ltd. 
*/

#include <reg52.h>
#include <absacc.h>
#include <assert.h>
#include <ctype.h>
#include <intrins.h>
#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/********** I/O PORT **********/

sbit     IPSCL          = P1^5;             // mcp23008
sbit     IPSDA          = P1^6;

/********** SUB FUNCTION **********/

void dmsec (unsigned int count) {           // mSec Delay
    unsigned int i;                         // for Keil CA51 (Speed x 1)
    while (count) {
        i = 115; while (i>0) i--;
        count--;
    }
}

void ipdel (void) {                    // I2C delay 
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
    _nop_ ();
}

void ipchigh (void) {                  // I2C clock high 
    IPSCL = 1;
    ipdel ();
}

void ipclow (void) {                   // I2C clock low 
    IPSCL = 0;
    ipdel ();
}

void ipstart (void) {                  // start condition 
    IPSDA = 1;
    IPSCL = 1;
    IPSDA = 0;
    ipdel ();
    IPSCL = 0;
    IPSDA = 1;
}
                                        
void ipstop (void) {                   // stop condition 
    IPSDA = 0;
    IPSCL = 1;
    ipdel ();
    IPSDA = 1;
}

bit ipwrbyte (unsigned dat) {          // write one byte 
    unsigned char i;                   // return 0 = ok 
    bit outbit;                        // return 1 = error 
    for (i=1;i<=8;i++) {
        outbit = dat & 0x80;
        IPSDA = outbit;
        dat = dat << 1;
        ipchigh ();
        ipclow ();
    }
    IPSDA = 1;
    ipchigh ();
    outbit = IPSDA;
    ipclow ();
    return (outbit);
}

unsigned char iprdbyte () {            // read one byte 
    unsigned char i,dat;               // return 0xff = error 
    bit inbit;
    dat = 0;
    for (i=1;i<=8;i++) {
        ipchigh ();
        inbit = IPSDA;
        dat = dat << 1;
        dat = dat | inbit;
        ipclow ();
    }
    IPSDA = 1;
    ipchigh ();
    inbit = IPSDA;
    ipclow ();
    if (~inbit) dat = 0xff;
    return (dat);
}

void ip23008wr (unsigned char addr,com,dat) {         // mcp23008 write
    addr = ((addr << 1) & 0x0e) | 0x40;             
    ipstart ();                                  
    ipwrbyte (addr);
    ipwrbyte (com);
    ipwrbyte (dat);
    ipstop ();
}

unsigned char ip23008rd (unsigned char addr,com) {    // mcp23008 read
    unsigned char dat;                               
    ipstart ();
    addr = ((addr << 1) & 0x0e) | 0x40;
    ipwrbyte (addr);
	ipwrbyte (com);
	ipstop ();

    ipstart ();
    addr = ((addr << 1) & 0x0e) | 0x41;
    ipwrbyte (addr);
    dat = iprdbyte (); 
    ipstop ();
    return (dat);
}

/********** MAIN FUNCTION **********/

void main (void) {
    unsigned char i,j,a;

    SCON = 0x52;             	  // set RS232 parameter
    TMOD = 0x20;
    TH1 = 0xfd; PCON |= 0x80;     // 19200
    TR1  = 1;

	dmsec (500);
	ip23008wr (0,0xa,0xff);       // default port = 0xff
    ip23008wr (0,0,0);            // set all bit = out
	dmsec (500);
    for (j=0;j<=9;j++) {          // test port = out 
        a = 0xfe;
        for (i=0;i<=7;i++) {
            ip23008wr (0,0xa,a);
            a = (a << 1) | 0x1;
            dmsec (250);     
        }  
    }

    ip23008wr (0,0,0xff);         // set all bit = in
	while (1) {
        a = ip23008rd (0,0x9);  
		printf ("Port = %02bX\r\n",a);
		dmsec (250);
	}
}


