alisa123 发表于 2015-7-12 19:56:29

stm32f3的软件模拟i2c

我用stm32f3 的PB8 (I2C1_SCL)和PB9(I2C1_SDA)模拟i2c,结果调试了好几天硬件的没有搞定,想用软件模拟,看时序感觉没问题,可是写地址后24c08没有应答信号,但是读的时候却能读出0xFF,不知哪里有问题,求高手帮忙看一下,谢谢。
代码如下:
#define SCL_L()               GPIOB->ODR&= ~(1<<8)
#define SCL_H()               GPIOB->ODR|= (1<<8)

#define SDA_L()               GPIOB->ODR&= ~(1<<9)                                 //GPIOB->BRR= GPIO_Pin_9
#define SDA_H()               GPIOB->ODR|= (1<<9)                              //GPIOB->BSRR = GPIO_Pin_9

#define SDA_out()               {GPIOB->MODER &= 0xFFF3FFFF;GPIOB->MODER |= 0x00040000;}
#define SDA_in()                {GPIOB->MODER &= 0xFFF3FFFF;GPIOB->MODER |= 0x00000000;}

#define SDA_High                GPIOB->IDR&GPIO_Pin_9
#define Write   0xfe
#define Read      0x01
#define A2      (1<<3)
#define P1_P0(Addr)      (((Addr / 256)& 0x03)<< 1)

unsigned char ack;
/**************************************************************
*Function
**************************************************************/
void I2c_delay(unsigned int t)
{
      while(t--);
}

void I2c_start(void)                //start: when scl is high,sda change grom high to low
{
      SDA_out();
      SDA_H();
//      I2c_delay(20);
      SCL_H();
      I2c_delay(500);
      SDA_L();
      I2c_delay(500);
      SCL_L();
      I2c_delay(50);
}

void I2c_stop(void)   //stop:when scl is high,sda change from low to high
{
      SDA_out();
      SCL_L();
      SDA_L();
      I2c_delay(500);
      SCL_H();
      I2c_delay(100);
      SDA_H();
      I2c_delay(500);
}

unsigned char I2c_wait_ack(void)
{
      unsigned char i;                        
      unsigned char I2c_bad;
      SDA_in();
      SDA_H();
      I2c_delay(100);
      SCL_H();
      I2c_delay(100);
      for(i=0; i<3; i++)
      {
                if(SDA_High)      
                {
                        I2c_bad=1;
                }
                else
                {
                        I2c_bad=0;
                        break;
                }
                I2c_delay(100);
      }
      SCL_L();
      I2c_delay(10);
//      SDA_out();
//      I2c_delay(10);
      returnI2c_bad;
}


void I2c_no_wait_ack(void)
{
//      SDA_out();
//      I2c_delay(20);
      SDA_H();
      I2c_delay(60);
      SCL_H();
      I2c_delay(100);
      SCL_L();
      I2c_delay(40);
}

void I2c_send_ack(void)
{
      SDA_out();
      SCL_L();
      I2c_delay(20);
      SDA_L();
      I2c_delay(200);
      SCL_H();
      I2c_delay(200);
      SCL_L();
      I2c_delay(20);
}

void I2c_send_noack(void)
{
      SDA_out();
      SCL_L();
      I2c_delay(10);
      SDA_H();
      I2c_delay(200);
      SCL_H();
      I2c_delay(200);
      SCL_L();
      I2c_delay(10);
      
}

void I2c_wr8bit(unsigned char c)
{
      unsigned char i;                        
      SDA_out();
      SCL_L();
      I2c_delay(10);
      for(i=0; i<8; i++)
      {
                if(c&0x80)
                        SDA_H();
                else      
                        SDA_L();
                I2c_delay(20);
                SCL_H();
                I2c_delay(200);
                SCL_L();
                I2c_delay(200);
                c=c<<1;               
                I2c_delay(200);
      }
      I2c_delay(10);
}

unsigned char I2c_rd8bit(void)
{
      unsigned char i, val=0;      
      SCL_H();
      SDA_in();
      I2c_delay(10);
/*      for(i=0x80; i>0;)            
      {
                SCL_H();                     
                I2c_delay(20);
                if(SDA_High)
                        val=(val | i);   
      //      I2c_delay(10);
                SCL_L();
                i>>=1;
      //      I2c_delay(20);
      }
      I2c_delay(20);                //
      
      return val;*/
      for(i = 0; i < 8;i++)
      {
                SCL_L();
                I2c_delay(200);
                SCL_H();
                val <<= 1;
                if(SDA_High)
                        val++;
                I2c_delay(100);
      }
      return val;
}

void I2c_write(unsigned char Addr,unsigned char Data,unsigned char DeviceID)
{
      INT8U Ack;
      
      I2c_start();
      I2c_wr8bit(DeviceID&Write);
      I2c_wait_ack();
      I2c_wr8bit(Addr);
      I2c_wait_ack();
      I2c_wr8bit(Data);
      I2c_wait_ack();
      I2c_stop();
      I2c_delay(1000);
}

unsigned char I2c_read(unsigned char Addr,unsigned char Data,unsigned char DeviceID)
{
      I2c_start();
      I2c_wr8bit(DeviceID&Write);
      I2c_wait_ack();
      I2c_wr8bit(Addr);
      I2c_wait_ack();
      I2c_start();
      I2c_wr8bit(DeviceID|Read);
      I2c_wait_ack();
      Data=I2c_rd8bit();
      I2c_no_wait_ack();
      I2c_stop();
      return Data;
}

void I2c_wr8bit_low(unsigned char c)
{
      char      i;                        
      SDA_out();
      for(i=0; i<8; i++)
      {
                if(c&0x01)
                        SDA_H();
                else      
                        SDA_L();
                I2c_delay(10);
                SCL_H();
                I2c_delay(10);
                SCL_L();
                c>>=1;                        
                I2c_delay(10);
      }
      SDA_H();                        
}

void Send_byte_low(unsigned char data_byte)
{
      I2c_wr8bit_low(data_byte);
      I2c_wait_ack();
}

void Send_byte (unsigned char data_byte)
{
      I2c_wr8bit(data_byte);
      I2c_wait_ack();
}

void sWriteI2C(INT8U *lubData,INT16U luwI2CAddr,INT8U lubDataLen)
{
      INT8U Len;
      
      I2c_start();
      
      I2c_wr8bit((0xa0 + P1_P0(luwI2CAddr))&Write);                                                //Write Device Address
      I2c_wait_ack();
      
      I2c_wr8bit(luwI2CAddr % 256);                                                                                        //Write Word Address
      I2c_wait_ack();
      
      for(Len = 0;Len < lubDataLen;Len++)
      {
                I2c_wr8bit(*lubData);                                                                                                //Write high byte
                I2c_wait_ack();               

                lubData++;
                luwI2CAddr++;
      }
      I2c_stop();
}

void sReadI2C(INT8U* lubData,INT16U luwI2CAddr,INT8U lubDataLen)
{
      INT8U Len;
      
      I2c_start();
      
      I2c_wr8bit((0xa0 + P1_P0(luwI2CAddr))&Write);                                        //Write Device Address
      I2c_wait_ack();
      
      I2c_wr8bit(luwI2CAddr % 256);                                                                              //Write Word Address
      I2c_wait_ack();

      I2c_start();
      I2c_wr8bit((0xa0 + P1_P0(luwI2CAddr))|Read);
      I2c_wait_ack();
      for(Len = 0;Len < lubDataLen - 1;Len++)
      {
                *lubData = I2c_rd8bit();
                I2c_send_ack();
                lubData++;
                luwI2CAddr++;
      }
      
      *lubData = I2c_rd8bit();
      I2c_no_wait_ack();
      
      I2c_stop();
}

左岸右岸 发表于 2015-7-12 21:38:09

没模拟过,帮顶:)

lkl0305 发表于 2015-7-12 23:12:10

楼主整个逻辑分析仪看下

lkl0305 发表于 2015-7-12 23:12:33

什么问题都能看出来:D:D

yanhaijian 发表于 2015-7-13 10:40:56

这就不要求助了,到各大电子论坛上一搜一大把。

ningzb 发表于 2015-7-13 17:02:01

1.可以确定的告诉你,模拟的可以运行
2.初始化时,时钟初始化成输出模式,数据初始化成开漏输出,外面要加上啦电阻,具体软件,你按照IIC协议来就行了,需要用示波器观察波形,注意你的速率,很多器件速率不能超过400k

数码小叶 发表于 2015-7-13 19:25:06

现在我才发现逻辑分析仪真的是个好东西,尤其分析IIC ,spi啥的,太方便了

alisa123 发表于 2015-7-13 21:18:17

ningzb 发表于 2015-7-13 17:02
1.可以确定的告诉你,模拟的可以运行
2.初始化时,时钟初始化成输出模式,数据初始化成开漏输出,外面要加 ...

谢谢你的详细回复,问题已经解决,是硬件电路出了问题。
页: [1]
查看完整版本: stm32f3的软件模拟i2c