STM32 模拟iic驱动 AT24C02

       最近在做一个需要驱动 AT24c02的项目,发现数据一直有出错的问题,芯片换掉之后出错的位置会变化,怀疑了各种问题,包括:(1)时序的问题  (2)引脚翻速度的问题  (3)芯片本身的问题   。最终发现问题出在停止信号的延时上,根据芯片的手册,每写一个数据到芯片,必须延时最少5ms ,等待at24c02芯片自己处理完毕,才能继续写入下一个数据。完整代码贴在下方

STM32 模拟iic驱动 AT24C02_第1张图片

 

 

#define SDA_H  GPIO_SetBits(EE_GPIO_PORT,EE_SDA)
#define SDA_L GPIO_ResetBits(EE_GPIO_PORT,EE_SDA)
#define SCL_H GPIO_SetBits(EE_GPIO_PORT,EE_SCL)
#define SCL_L GPIO_ResetBits(EE_GPIO_PORT,EE_SCL)
#define SDA_read GPIO_ReadInputDataBit(EE_GPIO_PORT,EE_SDA)
#define EEW_ADD 0XA0
#define EER_ADD 0XA1


/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*
*func:         I2C_GPIO_Config
*description:     I2C2 I/O configuration
*call :         internal
*/
static void I2C_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_IS;
    GPIO_IS.GPIO_Pin = EE_SCL|EE_SDA;
    GPIO_IS.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_IS.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_IS.GPIO_OType = GPIO_OType_OD;
    GPIO_Init(EE_GPIO_PORT,&GPIO_IS);
    SDA_H;
    SCL_H;
}

void I2C_OUT(void)    //SDA是输出方向
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin=EE_SDA;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;  //推挽输出模式
    GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //SDA_H;
    //SCL_H;
}

void I2C_IN(void)    //SDA是输入方向
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin=EE_SDA;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;  //输入上拉模式
    GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void I2C_EE_Init(void)
{
I2C_GPIO_Config();

}

uint8_t I2C_Start(void)
{
    #if 1
    I2C_OUT();
    SDA_H;
    SCL_H;
    Delay_10us(4);
    SDA_L;
    Delay_10us(4);
    SCL_L;
    return TRUE;
    #endif
}

void I2C_Stop(void)
{
    #if 1
    I2C_OUT();
    SCL_L;
    SDA_L;
    SCL_H;//改动位置
    Delay_10us(4);
    
    SDA_H;  
    Delay_10us(1000);//每个数据发送完毕之后,必须延时最少5ms,给eeprom芯片足够的处理时间,不然数据会出错
    #endif
}

void I2C_Ack(void)
{    
    #if 1
    I2C_OUT();
    SCL_L;

    SDA_L;
    Delay_10us(20);
    SCL_H;
    Delay_10us(20);
    SCL_L;
    #endif
}

void I2C_NoAck(void)
{    
    #if 1
    I2C_OUT();
    SCL_L;

    SDA_H;
    Delay_10us(2);
    SCL_H;
    Delay_10us(2);
    SCL_L;
    #endif
}

uint8_t I2C_WaitAck(void)      //返回为:=1有ACK,=0无ACK
{
    #if 1
    u16 ucErrTime=0;
    I2C_IN();
    SDA_H;            
    Delay_10us(1);
    SCL_H;
    Delay_10us(1);
    while(SDA_read)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            I2C_Stop();
            return FALSE;
        }     
    }
    SCL_L;
    return TRUE;
    #endif
}

void I2C_SendByte(uint8_t SendByte) //数据从高位到低位//
{
    #if 1
    uint8_t i=0;
    I2C_OUT();
    SCL_L;                                                               //拉低时钟开始数据传输
    for(i=0;i<8;i++)
    {              
        if(SendByte&0x80)
            SDA_H;  
        else 
            SDA_L; 
        SendByte<<=1;       
        Delay_10us(2);                                                           //对TEA5767这三个延时都是必须的
        SCL_H;
        Delay_10us(2); 
        SCL_L;     
        Delay_10us(2);
    }
    #endif
}

uint8_t I2C_ReceiveByte(u8 ack)  //数据从高位到低位//

#if 1
    unsigned char i,receive=0;  
    I2C_IN();
    for(i=0;i<8;i++ )
    {
        SCL_L; 
        Delay_10us(2);
        SCL_H;
        receive<<=1;
        if(SDA_read)receive++;   
        Delay_10us(1); 
    }
    SCL_L;
    if (!ack)
        I2C_NoAck();                                                            //发送nACK
    else
        I2C_Ack();                                                             //发送ACK   
    return receive;
    #endif
}

void I2C_WriteByte(uint8_t SendByte, uint8_t WriteAddress, uint8_t DeviceAddress)
{        

    I2C_Start();  
    I2C_SendByte(DeviceAddress);                                                    //发送器件写命令      
    I2C_WaitAck();       
    I2C_SendByte(WriteAddress);                                                       //发送低地址
    I2C_WaitAck();                                                           
    I2C_SendByte(SendByte);                                                       //发送字节                               
    I2C_WaitAck();                     
    I2C_Stop();    

}

uint8_t EepromReadByte(uint16_t FlashAddress,uint8_t Type)
{
    if(Type==Read_Eeprom)
    {
        u8 temp=0;                                                                                   
        I2C_Start();  
        I2C_SendByte(0XA0);                                                    //发送器件写命令        
        I2C_WaitAck(); 
        I2C_SendByte(FlashAddress);                                                      //发送低地址
        I2C_WaitAck();    

        I2C_Start();              
        I2C_SendByte(0XA0|1);                                                  //发送器件读命令               
        I2C_WaitAck();     
        temp=I2C_ReceiveByte(0);               
        I2C_Stop();  
        return temp;
    }
    else
    {
        return Sys_Value.Eeprom_Buf[(u8)FlashAddress];
    }
}
void __eeprom_write_8(unsigned short addr_eep,uint8_t data) 
{
//    Sys_Value.Eeprom_Buf[addr_eep]=data;
    I2C_WriteByte(data,addr_eep,0xA0);
}
 

 

 

你可能感兴趣的:(stm32)