模拟IIC

本文详细介绍了在STM32F10x平台上的软I2C库函数,包括I2C初始化、发送起始/停止信号、数据的读写以及芯片探测,展示了如何配置GPIO和进行低级I2C控制操作。
摘要由CSDN通过智能技术生成


#include "soft_i2c.h"
//#include "i2c.h"
#include "global.h"

#define I2C_ACK        0        /* SDA level to ack a byte */
#define I2C_NOACK    1        /* SDA level to noack a byte */

#define I2C_DIR_WRITE    0
#define I2C_DIR_READ    1

//clk
void I2C_DELAY(void)
{
  u8 i;
  
  for(i=0; i<20; i++);      //84k
  return;
}


void sys_i2c_init_board(void)
{
    //初始化IO口,SCL配置为输出高
    GPIO_InitTypeDef PB6={GPIO_Pin_6,GPIO_Speed_2MHz,GPIO_Mode_Out_OD};
    GPIO_Init(GPIOB, &PB6);
    //初始化IO口,SDA配置为输出高
    GPIO_InitTypeDef PB7={GPIO_Pin_7,GPIO_Speed_2MHz,GPIO_Mode_Out_OD};
    GPIO_Init(GPIOB,&PB7);
}

//START: High -> Low on SDA while SCL is High
void soft_i2c_send_start(void)
{
    SET_SDA_OUT;
    I2C_DELAY();
    
    I2C_SDA(1);
    I2C_SCL(1);
    I2C_DELAY();
    
    I2C_SDA(0);
    I2C_DELAY();
    
    I2C_SCL(0);
    I2C_DELAY();
}

//STOP: Low -> High on SDA while SCL is High
void soft_i2c_send_stop(void)
{
    I2C_SCL(0);
    SET_SDA_OUT;
    I2C_SDA(0);
    I2C_DELAY();
    
  
    I2C_SCL(1);
    I2C_DELAY();

    I2C_SDA(1);
    I2C_DELAY();
}

void soft_i2c_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    sys_i2c_init_board();

    soft_i2c_send_stop();
}


 //ack should be I2C_ACK or I2C_NOACK
void soft_i2c_send_ack(int ack)
{
    SET_SDA_OUT;
    I2C_SDA(ack);
    I2C_DELAY();
    
    I2C_SCL(1);
    I2C_DELAY();
    I2C_DELAY();
    I2C_SCL(0);
    I2C_DELAY();
   
}


/*-----------------------------------------------------------------------
 * Send 8 bits and look for an acknowledgement.
 */
static int soft_i2c_write_byte(u8 data)
{
  int j;
  int nack;
  
  SET_SDA_OUT;
  for(j = 0; j < 8; j++) 
  {
    I2C_SDA(data & 0x80);
    I2C_DELAY();
    I2C_SCL(1);
    I2C_DELAY();
    I2C_DELAY();
    I2C_SCL(0);
    I2C_DELAY();
    
    data <<= 1;
  }

  /*
   * Look for an <ACK>(negative logic) and return it.
   */
  
  SET_SDA_IN;
  I2C_DELAY();
  I2C_SCL(1);
  I2C_DELAY();
  nack = I2C_SDA_VALUE_IN;
  I2C_DELAY();
  I2C_SCL(0);
  I2C_DELAY();
  
  SET_SDA_OUT;
  //I2C_SDA(1);
  return(nack);    /* not a nack is an ack */
}

/*-----------------------------------------------------------------------
 * if ack == I2C_ACK, ACK the byte so can continue reading, else
 * send I2C_NOACK to end the read.
 */
static u8 soft_i2c_read_byte(int ack)
{
  u8  data;
  int  j;
  
  SET_SDA_IN;
  
  data = 0;
  for(j = 0; j < 8; j++) 
  {
    I2C_DELAY();
    I2C_SCL(1);
    I2C_DELAY();
    data <<= 1;
    data |= I2C_SDA_VALUE_IN;
    I2C_DELAY();
    I2C_SCL(0);
    I2C_DELAY();
  }
  soft_i2c_send_ack(ack);
  
  return(data);
}

/*-----------------------------------------------------------------------
 * Probe to see if a chip is present.  Also good for checking for the
 * completion of EEPROM writes since the chip stops responding until
 * the write completes (typically 10mSec).
 */
int soft_i2c_probe(u8 chipaddr)
{
  int rc;
  
  /*
   * perform 1 byte write transaction with just address byte
   * (fake write)
   */
  soft_i2c_send_start();
  rc = soft_i2c_write_byte((chipaddr << 1) | 0);
  soft_i2c_send_stop();
  
  return (rc ? 1 : 0);
}

/*-----------------------------------------------------------------------
 * Read bytes
 */
int soft_i2c_read(u8 chipaddr, u32 internalAddr, u32 internalAddrLen, u8 *buffer, int len)
{
  int shift;

  /*
   * Do the addressing portion of a write cycle to set the
   * chip's address pointer.  If the address length is zero,
   * don't do the normal write cycle to set the address pointer,
   * there is no address pointer in this chip.
   */
  soft_i2c_send_start();
  if(internalAddrLen > 0) 
  {
    if(soft_i2c_write_byte(chipaddr << 1))     /* write cycle */
    {
      soft_i2c_send_stop();
      return(1);
    }
    shift = (internalAddrLen-1) * 8;
    while(internalAddrLen-- > 0) 
    {
      if(soft_i2c_write_byte(internalAddr >> shift)) 
      {
        //printf("i2c_read, internal address not <ACK>ed\n");
        return(1);
      }
      shift -= 8;
    }

  /* Some I2C chips need a stop/start sequence here,
   * other chips don't work with a full stop and need
   * only a start.  Default behaviour is to send the
   * stop/start sequence.
   */
#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
    soft_i2c_send_start();
#else
    soft_i2c_send_stop();
    soft_i2c_send_start();
#endif
  }
  /*
   * Send the chip address again, this time for a read cycle.
   * Then read the data.  On the last byte, we do a NACK instead
   * of an ACK(len == 0) to terminate the read.
   */
  soft_i2c_write_byte((chipaddr << 1) | 1);    /* read cycle */
  while(len-- > 0) 
  {
      *buffer++ = soft_i2c_read_byte(len == 0);
  }
  soft_i2c_send_stop();
  return(0);
}


/*-----------------------------------------------------------------------
 * Write bytes
 */
int soft_i2c_write(u8 chipaddr, u32 internalAddr, u32 internalAddrLen, u8 *buffer, int len)
{
    int shift, failures = 0;

    //printf("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",chip, addr, alen, buffer, len);

    soft_i2c_send_start();
    if(soft_i2c_write_byte(chipaddr<<1))     /* write cycle */
    {    
        soft_i2c_send_stop();
        //printf("i2c_write, no chip responded %02X\n", chipaddr);
        return(1);
    }
    shift = (internalAddrLen-1) * 8;
    while(internalAddrLen-- > 0) 
    {
        if(soft_i2c_write_byte(internalAddr >> shift)) 
        {
            //printf("i2c_write, address not <ACK>ed\n");
            return(1);
        }
        shift -= 8;
    }

    while(len-- > 0) 
    {
        if(soft_i2c_write_byte(*buffer++)) 
        {
            failures++;
        }
    }
    soft_i2c_send_stop();
    return(failures);
}


#ifndef __SOFT_I2C_H__
#define __SOFT_I2C_H__

#include "stm32f10x_map.h"

#define  Pin7_out 0x20000000
#define  Pin7_in   0x30000000


//PB2                                        
#define I2C_SCL(bit)    do{ \
                            if(bit)  GPIO_WriteBit(GPIOB,GPIO_Pin_6,Bit_SET); \
                            else    GPIO_WriteBit(GPIOB,GPIO_Pin_6,Bit_RESET);  \
                        }while(0)

//PB3
#define I2C_SDA(bit)    do{ \
                            if(bit) GPIO_WriteBit(GPIOB,GPIO_Pin_7,Bit_SET);  \
                            else    GPIO_WriteBit(GPIOB,GPIO_Pin_7,Bit_RESET); \
                        }while(0)

#define SET_SDA_OUT  do{( GPIOB->CRL)|=(Pin7_out);}while(0)     
#define SET_SDA_IN   do{( GPIOB->CRL)&=~(Pin7_in); }while(0)


#define    I2C_SDA_VALUE_IN  (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7))

void soft_i2c_init(void);
int soft_i2c_probe(u8 chipaddr);
int soft_i2c_read(u8 chipaddr, u32 internalAddr, u32 internalAddrLen, u8 *buffer, int len);
int soft_i2c_write(u8 chipaddr, u32 internalAddr, u32 internalAddrLen, u8 *buffer, int len);


#endif


 

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值