// Port for the I2C
#define I2C_DDR DDRD
#define I2C_PIN PIND
#define I2C_PORT PORTD
// Pins to be used in the bit banging
#define I2C_CLK 0
#define I2C_DAT 1
#define I2C_DATA_HI()\
I2C_DDR &= ~ (1 << I2C_DAT);\
I2C_PORT |= (1 << I2C_DAT);
#define I2C_DATA_LO()\
I2C_DDR |= (1 << I2C_DAT);\
I2C_PORT &= ~ (1 << I2C_DAT);
#define I2C_CLOCK_HI()\
I2C_DDR &= ~ (1 << I2C_CLK);\
I2C_PORT |= (1 << I2C_CLK);
#define I2C_CLOCK_LO()\
I2C_DDR |= (1 << I2C_CLK);\
I2C_PORT &= ~ (1 << I2C_CLK);
void I2C_WriteBit(unsigned char c)
{
if (c > 0)
{
I2C_DATA_HI();
}
else
{
I2C_DATA_LO();
}
I2C_CLOCK_HI();
delay(1);
I2C_CLOCK_LO();
delay(1);
if (c > 0)
{
I2C_DATA_LO();
}
delay(1);
}
unsigned char I2C_ReadBit()
{
I2C_DATA_HI();
I2C_CLOCK_HI();
delay(1);
unsigned char c = I2C_PIN;
I2C_CLOCK_LO();
delay(1);
return (c >> I2C_DAT) & 1;
}
// Inits bitbanging port, must be called before using the functions below
//
void I2C_Init()
{
I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
I2C_CLOCK_HI();
I2C_DATA_HI();
delay(1);
}
// Send a START Condition
//
void I2C_Start()
{
// set both to high at the same time
I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
delay(1);
I2C_DATA_LO();
delay(1);
I2C_CLOCK_LO();
delay(1);
}
// Send a STOP Condition
//
void I2C_Stop()
{
I2C_CLOCK_HI();
delay(1);
I2C_DATA_HI();
delay(1);
}
// write a byte to the I2C slave device
//
unsigned char I2C_Write(unsigned char c)
{
for (char i = 0; i < 8; i++)
{
I2C_WriteBit(c & 128);
c <<= 1;
}
//return I2C_ReadBit();
return 0;
}
// read a byte from the I2C slave device
//
unsigned char I2C_Read(unsigned char ack)
{
unsigned char res = 0;
for (char i = 0; i < 8; i++)
{
res <<= 1;
res |= I2C_ReadBit();
}
if (ack > 0)
{
I2C_WriteBit(0);
}
else
{
I2C_WriteBit(1);
}
delay(1);
return res;
}
Tuesday, 14 October 2008
I2C on an AVR using bit banging
As a exercise I tried to talk to a I2C temperature sensor using bit banging, it was not as easy as I thought so I decided to post the code in case anyone needs to see the solution, if you happen to use my code drop me a line since that will encourage me to post more code :-)
Labels:
i2c avr atmel bitbanging
Subscribe to:
Post Comments (Atom)
9 comments:
hi raul! i think i'm gonna give your code a try. by the way, what device are you driving and what is your system clock? (for timing references)
do you have external pullup resistors?
thanks!
Damned handy example. Thank you kindly for it.
Hey, this is exactly what I need, I'll give it a try, thanks a bunch.
code is working fine i checked it with atmega16 on 12MHz...
Awesome Toshu, thanks for sharing!
The Atmega16 is the server?
Thx a lot. This is exactly what I want.
A nice code! Tested using ATtiny25&LCD module&DS18B20 temperature sensor&internal ATtiny sensor!
Thank you a lot!!
Marek (Czech Rep.)
A nice code! Tested using ATtiny25&LCD module&DS18B20 temperature sensor&internal ATtiny sensor!
Thank you a lot!!
Marek (Czech Rep.)
Thanks for the code example. Can you tell me why you are using DDRD when you want to set the port high or low? It seems backwards to me, like you would want PORTD, right?
For example, I'd think the only time you need to set the DDR (data direction) would be during the init, and then on it's always the same. Then when you send data you'd use the PORTD command, but instead you use DDRD to send data?
I'm just ramping up to AVRs so I might be confused. Would appreciate any clarification, thanks!
Post a Comment