127 lines
2.3 KiB
C
127 lines
2.3 KiB
C
#define __16f1847
|
|
#include <pic16f1847.h>
|
|
#include <stdint.h>
|
|
#include "I2C.h"
|
|
|
|
/* set clock high (default state) */
|
|
#define release_SCL() LATB |= SCL
|
|
/* set clock low */
|
|
#define hold_SCL() LATB &= ~SCL
|
|
/* set data high (default state) */
|
|
#define release_SDA() LATB |= SDA
|
|
/* set data low */
|
|
#define hold_SDA() LATB &= ~SDA
|
|
|
|
/* a small delay for better clock */
|
|
#define WAIT 1
|
|
/*
|
|
void delay(void)
|
|
{
|
|
uint8_t wait=WAIT;
|
|
while (wait--);
|
|
}
|
|
*/
|
|
#define delay() __asm\
|
|
nop\
|
|
nop\
|
|
nop\
|
|
nop\
|
|
__endasm
|
|
|
|
/* read SDA
|
|
* don't forget to set SDA as input in the begining
|
|
* are set SDA as output in the end
|
|
*/
|
|
uint8_t read_SDA(void)
|
|
{
|
|
hold_SCL(); /* set clock to low for SDA to change */
|
|
delay(); /* wait for SDA to change */
|
|
delay();
|
|
delay();
|
|
release_SCL(); /* SDA should be valid when clock is high */
|
|
delay();
|
|
/* we don't verify the SCL state as only we can drive it */
|
|
if (PORTB&SDA) { /* read bit */
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t read_ack(void)
|
|
{
|
|
uint8_t ack = 0;
|
|
TRISB |= SDA; /* set as input */
|
|
ack = read_SDA();
|
|
TRISB &= ~SDA; /* set back to output */
|
|
hold_SCL();
|
|
return ack;
|
|
}
|
|
|
|
/* start bit is when SDA goes low while SCL is high */
|
|
void send_start(void)
|
|
{
|
|
release_SCL();
|
|
delay();
|
|
release_SDA(); /* ensure SDA is high on the beginning */
|
|
delay();
|
|
hold_SDA();
|
|
}
|
|
|
|
void send_stop(void)
|
|
{
|
|
hold_SDA(); /* be sure SDA is low */
|
|
release_SCL();
|
|
delay();
|
|
release_SDA(); /* set SDA high while SCL is high */
|
|
}
|
|
|
|
void send_1(void)
|
|
{
|
|
hold_SCL(); /* value can change when SCL is low */
|
|
delay();
|
|
release_SDA(); /* set the right state */
|
|
delay();
|
|
release_SCL(); /* value will be read when SCL goes high */
|
|
}
|
|
|
|
void send_0(void)
|
|
{
|
|
hold_SCL(); /* value can change when SCL is low */
|
|
delay();
|
|
hold_SDA(); /* set the right state */
|
|
delay();
|
|
release_SCL(); /* value will be read when SCL goes high */
|
|
}
|
|
|
|
/* send byte and get ack */
|
|
uint8_t send_byte(uint8_t byte)
|
|
{
|
|
uint8_t bit;
|
|
/* send every bit, MSb first */
|
|
for (bit = 0; bit < 8; bit++) {
|
|
if (byte&0x80) {
|
|
send_1();
|
|
} else {
|
|
send_0();
|
|
}
|
|
byte <<= 1;
|
|
}
|
|
return read_ack();
|
|
}
|
|
|
|
uint8_t read_byte(void)
|
|
{
|
|
uint8_t byte = 0;
|
|
uint8_t bit;
|
|
TRISB |= SDA; /* set as input */
|
|
/* read 8 bits */
|
|
for (bit=0; bit<8; bit++) {
|
|
byte += read_SDA();
|
|
byte <<= 1;
|
|
}
|
|
TRISB &= ~SDA; /* set back to output */
|
|
send_0(); /* send ack */
|
|
return byte;
|
|
}
|