这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » GPIO模拟I2C快速入门

共7条 1/1 1 跳转至

GPIO模拟I2C快速入门

助工
2008-08-20 09:08:11     打赏

I2C是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。I2C是总线结构,1个Master,1个或多个Slave,各Slave设备以7位地址区分,地址后面再跟1位读写位,表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址,此时每个设备有读、写两个地址,高7位地址其实是相同的。
I2C数据格式如下:
无数据:SCL=1,SDA=1;
开始位(Start):当SCL=1时,SDA由1向0跳变;
停止位(Stop):当SCL=1时,SDA由0向1跳变;
数据位:当SCL由0向1跳变时,由发送方控制SDA,此时SDA为有效数据,不可随意改变SDA;
当SCL保持为0时,SDA上的数据可随意改变;
地址位:定义同数据位,但只由Master发给Slave;
应答位(ACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=0;
否应答位(NACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=1。
当数据为单字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,停止位。
当数据为一串字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,8位数据,应答,……,8位数据,应答,停止位。
需要注意的是:
1,SCL一直由Master控制,SDA依照数据传送的方向,读数据时由Slave控制SDA,写数据时由Master控制SDA。当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反。
2,开始位“Start”和停止位“Stop”,只能由Master来发出。
3,地址的8位传送完毕后,成功配置地址的Slave设备必须发送“ACK”。否则否则一定时间之后Master视为超时,将放弃数据传送,发送“Stop”。
4,当写数据的时候,Master每发送完8个数据位,Slave设备如果还有空间接受下一个字节应该回答“ACK”,Slave设备如果没有空间接受更多的字节应该回答“NACK”,Master当收到“NACK”或者一定时间之后没收到任何数据将视为超时,此时Master放弃数据传送,发送“Stop”。
5,当读数据的时候,Slave设备每发送完8个数据位,如果Master希望继续读下一个字节,Master应该回答“ACK”以提示Slave准备下一个数据,如果Master不希望读取更多字节,Master应该回答“NACK”以提示Slave设备准备接收Stop信号。
6,当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。


在实际应用中,并没有强制规定数据接收方必须对于发送的8位数据做出回应,尤其是在Master和Slave端都是用GPIO软件模拟的方法来实现的情况下,编程者可以事先约定数据传送的长度,不发送ACK,有时可以起到减少系统开销的效果。




关键词: 模拟     快速     入门     Master     Slave     地址         

菜鸟
2008-08-21 11:32:24     打赏
2楼

给你一个源码看看!

/********************************************************************/

void i2c_init(void)
{
 PACNT_init;
 PADDR_init;
 PADAT_init;
 
 SCL_high;
 SDA_high;
}
 
/********************************************************************/

uint8 i2c_write(uint8 slave_address, uint8 *buffer, int byte_count, int freq)
{
    uint8 out_mask = 0x80;
    uint8 value = 0x00;
  uint8 send_byte = 0x00;
  uint8 status = 0x81;
  int count = 8;
  int clk_count = 0;
 int i = 0;
 
 /* Set delay value based on frequency. */
 int D = (int) ((4000/freq) - 14);
 
 slave_address = (slave_address & 0xFE);
         
  i2c_start();
  delay(500);
 
   send_byte = slave_address;
        
   for(i = 0; i <= byte_count; i++)
   {    
    count = 8; 
    out_mask = 0x80;
         
    /* Send data bytes one bit at a time. */   
    while(count > 0)
    {            
     value = ((send_byte & out_mask) ? 1 : 0);
      if (value == 1)
      {
       PADAT_init;
        SDA_high;}
      else
      {
       PADAT_init;
       SDA_low;}
       
      delay(D);     
                   
        PADAT_init;
      SCL_high;
      
      /* Clock stretching wait statement.  Wait until clock is released
      by slave.  Only effects program on first iteration.  */
   while (((GPIO_PADAT & 0x0200) ? 1 : 0) == 0){;}

      delay(2*D);  
       
      PADAT_init;
      SCL_low;
      delay(D); 
       
      out_mask >>= 1;
      count--;  
     }
     
     PADAT_init;
     SDA_high;  /* Let go of data pin. */
     delay(D); 
      
     if (((GPIO_PADAT & 0x0400) ? 1 : 0) == 1)
     { 
      status = 0xA1; /* Transfer complete, bus busy, acknowledge not received. */
      break; } /* If not acknowledged, exit loop. */
     
    PADAT_init;
     SCL_high;
     delay(2*D);  
   
     PADAT_init;
     SCL_low;
     status = 0xA0;  /* Transfer complete, bus busy, acknowledge received. */
     delay(D); 
     
     send_byte = buffer[i];      
    }
    
    PADAT_init;
    SDA_high;
    SCL_low;  
 delay(100);
 return(status);
}

/********************************************************************/

uint8 i2c_read(uint8 slave_address, uint8 *buffer, int byte_count, int freq)
{
 uint8 input_byte = 0x00;
 uint8 value = 0x00;
 uint8 out_mask = 0x80;
 uint8 status = 0x81;
 int count = 8;
 int clk_count = 0;
 int i = 0;
 
 /* Set delay value based on frequency. */
 int D = (int) ((4000/freq) - 14);
 
 slave_address = (slave_address | 0x01);
   
 i2c_start();
 delay(500);
               
 /**********  Write Address Procedure **********/
  
   while(count > 0)
   {
    value = ((slave_address & out_mask) ? 1 : 0);
     if (value == 1)
     {
      PADAT_init;
       SDA_high;}
     else
     {
      PADAT_init;
      SDA_low;}
      delay(D);      
                   
      PADAT_init;
     SCL_high;
      
     /* Clock stretching wait.  Wait until clock is released
     by slave.  */
     while (((GPIO_PADAT & 0x0200) ? 1 : 0) == 0){;}

     delay(2*D); 
       
     PADAT_init;
     SCL_low;
     delay(D);  
       
     out_mask >>= 1;
     count--;        
  }
     
    PADAT_init;
  SDA_high;  /* Let go of data pin. */
    delay(D);
    SCL_high;
    delay(2*D);  
   
    /* If not acknowleged, set status accordingly and exit read process. */
    if (((GPIO_PADAT & 0x0400) ? 1 : 0) == 1)
    {
     status = 0xA1;
     return(status);}
   
    PADAT_init;
    SCL_low;
    delay(D);
 
 /**********  Begin Read Procedure **********/
 
 /* Release SDA and SCL to initiate transfer. */
 PADAT_init;    
 SDA_high;
 SCL_high;

 for(i = 0; i < byte_count; i++)
 {
  count = 8;
  input_byte = 0x00;
   
  PADAT_init;
  SCL_high;
   
  /* Clock stretching wait.  Wait until clock is released
     by slave.  */
  while (((GPIO_PADAT & 0x0200) ? 1 : 0) == 0){;}
           
  /* Loop for bit-by-bit read of data. */
  while(count > 0) 
  {
    PADAT_init;
    SCL_high;
    delay(D);  
    delay(4); /* Required to make read and write clocks the same freq. */
    
   if ((GPIO_PADAT & 0x0600) == 0x0600)
    input_byte++;
  
   delay(D);  
   
   PADAT_init;
   SCL_low;
   delay(2*D); 
      
   if (count == 1)
    break;
   else  
    input_byte <<= 1;
  
   count--;
  }
 
  /* Write input byte to "read_buffer". */
  buffer[i] = input_byte;
    
  if(i == (byte_count - 1))
   break;
     
     /* Below is the acknowledge procedure. */     
     PADAT_init;
     SDA_low;
     delay(D);  
     SCL_high;    
  delay(2*D);  
   
     PADAT_init;
     SCL_low;
     delay(D);  
     SDA_high; 
     status = 0xA0; 
 }     
 
 /* Standard protocol calls for the last read byte to
    not receive an acknowledge from the master. */    
 PADAT_init;
    SDA_high;
    SCL_high;    
 delay(2*D); 
    
   PADAT_init;
   SCL_low;
   delay(D);  
   SDA_high;
   status = 0xA1;
   return(status);
}

/********************************************************************/

void i2c_start(void)
{
 int clk_count = 0;
 uint8 compare = 0x00;
 
 PADAT_init;  
 SDA_high;
 delay(100);
 
 PADAT_init;  
 SCL_high;
 delay(100);
 
 /* Clock stretching wait.  Wait until clock is released
    by slave.  */
 while (((GPIO_PADAT & 0x0200) ? 1 : 0) == 0){;}    
  
 PADAT_init;
 SDA_low;
 delay(100);
     
    PADAT_init;  
 SCL_low;
 delay(100);

/********************************************************************/

uint8 i2c_stop(void)
{
 uint8 status = 0x00;
 int clk_count = 0;
  
 PADAT_init;
 SCL_low;
 delay(100);

 PADAT_init;
 SDA_low;
 delay(100);
   
    PADAT_init; 
 SCL_high;
 
 /* Clock stretching wait statement.  Wait until clock is released
    by slave.  */
 while (((GPIO_PADAT & 0x0200) ? 1 : 0) == 0){;}
      
 delay(100);
   
    PADAT_init; 
 SDA_high;
 status = 0x81; /* Set bus idle. */
 return(status);
}

/********************************************************************/

void delay(int value)
{
 int clk_count = 0;
 while (clk_count < value)
 {clk_count++;}
}

/********************************************************************/


助工
2008-08-22 10:17:43     打赏
3楼
源代有没验证过?

菜鸟
2008-08-27 16:44:09     打赏
4楼
freescale 公司提供的!应该不错的!

菜鸟
2008-08-30 23:18:04     打赏
5楼

不错,支持一下


菜鸟
2008-10-06 17:35:23     打赏
6楼
想问一下,PADAT_init的作用是什么?为什么每次对时钟和数据的值操作前都要执行它.

菜鸟
2008-10-07 00:23:07     打赏
7楼
  In order to use GPIO pins, a zero must be permanently written to the data register(PADAT_init) and the DDR (PADDR_init
)must be set to input or output mode depending on the desired level of the line

共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]