您的位置:首页 > Web前端

GPIO模拟的I2C操作

2011-04-22 16:59 260 查看
嗯,是我写的,已经在上市产品中验证没有错误。呵呵

后来有一天我才知道,原来新的kernel中已经提供了一种通过两个gpio口调用i2c-core的机制,而且还能在这两个gpio口挂载多个设备,用起来就像真的i2c总线一样。所以以后我们都应该用kernel中的这种机制!毕竟自己写的模拟代码不是很可靠的,而且不方便挂载多个设备(当然,你可以通过复杂的逻辑和方法去实现,但是这不值得,除非你是本着学习的目的)

不过这个自己写的gpio模拟i2c的代码通过对gpio的不停的拉高拉低来模拟scl和sda线的动作可以让我们对i2c的操作和协议认识的更清楚。因此对于初学者来说还是有一较大价值的。其实,从经验上讲,每一个刚刚接触到嵌入式的同学都应该能够自己独立完成一个这样的模拟操作!这样你会提高的很快!

 

代码如下:

这不是完整的代码,仅仅提供模拟操作部分供大家参考。

 

/****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C****/
#define DELAY	1
#define SCL		89
#define SDA		20
#define RST		19
#define IRQ		108
void i2c_start(void)
{
gpio_direction_output(SDA, 1);
gpio_direction_output(SCL, 1);
udelay(DELAY);

gpio_set_value(SDA, 0);
udelay(DELAY);

gpio_set_value(SCL, 0);
udelay(DELAY);
}
void i2c_stop(void)
{
gpio_set_value(SCL, 0);
gpio_set_value(SDA, 0);
udelay(DELAY);

gpio_set_value(SCL, 1);
udelay(DELAY);
gpio_set_value(SDA, 1);
udelay(DELAY);
}
void i2c_send_ack(u8 ack)
{
if(ack)
gpio_direction_output(SDA, 1);
else
gpio_direction_output(SDA, 0);
udelay(DELAY);

gpio_set_value(SCL, 1);
udelay(DELAY);

gpio_set_value(SCL, 0);
udelay(DELAY);
}
u8 i2c_receive_ack(void)
{
u8 rc = 0;

gpio_direction_input(SDA);
gpio_set_value(SCL, 1);
udelay(DELAY);

if(gpio_get_value(SDA)) {
rc = 1;
}
gpio_set_value(SCL, 0);
gpio_direction_output(SDA, 1);
return rc;
}
u8 i2c_send_byte(u8 send_byte)
{
u8 rc = 0;
u8 out_mask = 0x80;
u8 value;
u8 count = 8;
while(count > 0) {
value = ((send_byte & out_mask) ? 1 : 0);
if (value == 1) {
gpio_set_value(SDA, 1);
}
else {
gpio_set_value(SDA, 0);
}
udelay(DELAY);

gpio_set_value(SCL, 1);
udelay(DELAY);

gpio_set_value(SCL, 0);
udelay(DELAY);

out_mask >>= 1;
count--;
}

gpio_set_value(SDA, 1);
rc = i2c_receive_ack();
return rc;
}
void i2c_read_byte(u8 *buffer, u8 ack)
{
u8 count = 0x08;
u8 data = 0x00;
u8 temp = 0;

gpio_direction_input(SDA);
while(count > 0) {
gpio_set_value(SCL, 1);
udelay(DELAY);
temp = gpio_get_value(SDA);
data <<= 1;
if (temp)
data |= 0x01;
gpio_set_value(SCL, 0);
udelay(DELAY);
count--;
}
i2c_send_ack(ack);//0 = ACK    1 = NACK
*buffer = data;
}
//向client的某个寄存器写入多个字节,len是要写入的数据的长度
u8 i2c_write(u8 device_id, u8 reg_address, u8* data, u8 len)
{
u8 rc = 0;
u8 i;
i2c_start();

rc |= i2c_send_byte( (device_id << 1) | 0x00 );
rc |= i2c_send_byte(reg_address);
if(data==NULL ||0==len) {
i2c_stop();
return rc;
}

for(i=0; i<len; i++) {
rc |= i2c_send_byte(*data);
data++;
}

i2c_stop();
if(rc) {
printk("ERROR!  ssd2531_i2c_write failed/n");
}
return rc;
}
//从某个register中读取len个字节放在长度为len的缓冲区buffer中
u8 i2c_read(u8 device_id, u8 reg_address, u8 *buffer, u8 len)
{
u8 rc = 0;
u8 i;

i2c_start();
rc |= i2c_send_byte( (device_id << 1) | 0x00 );
rc |= i2c_send_byte(reg_address);
i2c_start();//restart I2C
rc |= i2c_send_byte( (device_id << 1) | 0x01 );

for(i=0;i<len;i++) {
i2c_read_byte(buffer++, !(len-i-1));//  !(len-i-1)  这个用来保证在读到每个字节后发送一个ACK并能在最后一个字节读完后发送一个NACK
}

i2c_stop();
if(rc) {
printk("ERROR!   ssd2531_i2c_read failed/n");
return rc;
}
return rc;
}
/****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C*****I2C****/
 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c delay byte output buffer input