Chinaunix首页 | 论坛 | 博客
  • 博客访问: 69965
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-12 19:50
文章分类

全部博文(13)

文章存档

2016年(1)

2015年(3)

2014年(9)

分类: LINUX

2014-02-18 13:25:34

原文地址:用s5pc100的GPIO模拟IIC 作者:草根老师

关于IIC的介绍,读者可以参看fs2410裸奔之IIC一文,这里重点介绍如何用GPIO模拟IIC。

先来看看LM75硬件的上的连线:



其中I2C_SDA0是数据线,I2C_SCL0是时钟线,它们分别接到s5pc100的GPD3和GPD4,如下图所示



在模拟IIC的时候,用GPD3引脚发送数据或读取数据,用GPD4引脚提供时钟信号即可。

由于s5pc100的GPD这一组的引脚很多,不好单独对其中的某一个引脚操作,为了能单独对其中的某一个管脚单独操作,这里使用了C语言的位域。

typedef struct
{
uint8 GPDDAT_0:1;
uint8 GPDDAT_1:1;
uint8 GPDDAT_2:1;
uint8 GPDDAT_3:1;
uint8 GPDDAT_4:1;
uint8 GPDDAT_5:1;
uint8 GPDDAT_6:1;
uint8 GPDDAT_7:1;

}gpddat_t;

#define GPD_DAT (* (volatile gpddat_t *)0xE0300084)

#define SDA GPD_DAT.GPDDAT_3
#define SCL GPD_DAT.GPDDAT_4

(1)产生IIC起始信号

SCL 为高电平时,SDA由高电平向低电平跳变,开始传送数据

/*IIC START:SCL = 1,SDA = 1->0*/
void iic_start()
{
SDA = HIGH;
SCL  = HIGH;
delay(50);
        
 //高到低的跳变产生start信号 
SDA = LOW;
delay(50);

 //在SCL高时,SDA必须保持稳定,SCL低时,SDA可以任意改变
 //此处将SCL拉低的目的是,接下来就要发送数据了
SCL = LOW;
delay(50);

        return;
}


(2)产生IIC停止信号

SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据

/*IIC STOP:SCL = 1,SDA = 0->1*/
void iic_stop()
{
SDA = LOW;
SCL = LOW;
delay(50);

SCL = HIGH;
delay(50);
        //SCL为高电平时,SDA从低电平跳变到高电平
        //,产生停止信号
SDA = HIGH;
delay(50);

return;
}

(3)发送数据

/*Write 1 Byte to IIC*/
void iic_write_byte(uint8 data)
{
uint8 loop;

for(loop = 8;loop > 0;loop --)
{
//先发送最高位,在SCL高电平时,SDA必须保持稳定
SDA = data >> 7;
SCL = HIGH;
delay(50);

//SCL为低电平时,SDA可以任意改变
SCL = LOW;
//低位向高位移动
data <<= 1;
delay(50);
}

return;
}

(4)读取数据

/*Read 1 byte from IIC*/
uint8 iic_read_byte()
{
uint8 loop;
uint8 value = 0;

for(loop = 8; loop > 0;loop --)
{
SCL = HIGH;

delay(50);

value <<= 1;

//读取1位数据
value |= SDA;

SCL = LOW;

delay(50);
        }

        return value;
}

(5)主机向从机发送ACK信号

void iic_send_ack()
{
SCL = HIGH;
SDA = LOW;
delay(50);

SCL = LOW;
delay(50);

return;
}

(6)获取从机给主机的ACK信号

uint8 iic_get_ack()
{
uint8 ret;

SCL = HIGH;
delay(50);

ret = SDA;

SCL = LOW;
delay(50);

return ret;
}

四、读取LM75测量的温度值

通过IIC读取LM75测量温度值的时序如下:



实例代码如下:

unsigned int __read_lm75()
{
uint8 ack;
uint8 high,low;

//设置IIC连接的pin为输出模式
SET_GPIO_MODE(GPD.GPDCON,3,1);
SET_GPIO_MODE(GPD.GPDCON,4,1);

delay(100);

//产生起始信号
iic_start();

//发送从机地址
iic_write_byte(0x91);

//设置IIC连接的pin(SDA)为输入模式
SET_GPIO_MODE(GPD.GPDCON,3,0);

//等待从机的ACK
do{
ack = iic_get_ack();
}while(ack);

//读取从机发送过来的数据
high = iic_read_byte();

//设置IIC连接的pin(SDA)为输出模式
SET_GPIO_MODE(GPD.GPDCON,3,1);

//发送ACK信号
iic_send_ack();

//设置IIC连接的pin(SDA)为输入模式
SET_GPIO_MODE(GPD.GPDCON,3,0);

//读取从机发送过来的数据
low = iic_read_byte();

//设置IIC连接的pin(SDA)为输出模式
SET_GPIO_MODE(GPD.GPDCON,3,1);

//发送停止信号
iic_stop();

return (high << 8) | low;
}

实验的经验:
1.读不到从机发送的ACK信号,原因是没有将SDA的那根线设为输入模式
2.在做的过程中,一开始每次读取的时候温度的值一直没有改变,后来发现是由于每次没有发送停止信号产生的。 
阅读(1448) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~