用s5pc100的GPIO模拟IIC

转载:http://blog.chinaunix.net/uid-26833883-id-3823530.html

 

一、硬件连线

先来看看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.在做的过程中,一开始每次读取的时候温度的值一直没有改变,后来发现是由于每次没有发送停止信号产生的。 

完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值