STM32模拟IIC读写24CXX

版权声明:本文为小生原创,转载请注明出处,好吗好的,善哉善哉!!! https://blog.csdn.net/u010650845/article/details/77479933

文件(iic.h):

#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X80000000;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X30000000;}

#define IIC_SCL    PBout(6) 
#define IIC_SDA    PBout(7)  
#define READ_SDA   PBin(7) 

void bsp_iic_init(void);                             
void bsp_iic_start(void);               
void bsp_iic_stop(void);                
void bsp_iic_sendByte(u8 txd);      
u8 bsp_iic_readByte(unsigned char ack);
u8 bsp_iic_waitAck(void);           
void bsp_iic_ack(void);             
void bsp_iic_nAck(void);    

文件(iic.c):

/*
****************************************************************
**  brief : IIC 初始化,IO模拟IIC
**  note : SDA-PB7,SCL-PB6
****************************************************************
*/
void bsp_iic_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 
}

/*
***************************************************************
**  brief : IIC开始信号
**  note  : SCL为高电平时,SDA由高电平向低电平跳变
***************************************************************
*/
void bsp_iic_Start(void) 
{
    delay_5us();   
    SDA_OUT();     
    IIC_SDA=1;        
    IIC_SCL=1;
    delay_5us();
    IIC_SDA=0;
    delay_5us();
    IIC_SCL=0;
}
/*
***************************************************************
**  brief : IIC停止信号
**  note  : SCL为高电平时,SDA由低电平向高电平跳变
***************************************************************
*/

void bsp_iic_stop(void)
{
    delay_5us();   
    SDA_OUT();
    IIC_SCL=0;
    IIC_SDA=0;
    delay_5us();
    IIC_SCL=1; 
    delay_5us();
    IIC_SDA=1;
    delay_5us();                                
}

/*
********************************************************** 
**  brief : 等待应答信号到来
**  ret    : 1.接收应答失败
**            0.接收应答成功
*********************************************************
*/
u8 bsp_iic_waitAck(void)
{
    u8 ucErrTime=0;

    delay_5us();    
    SDA_IN();        
    IIC_SDA=1;
    delay_5us();       
    IIC_SCL=1;
    delay_5us();     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>100)
        {
            bsp_iic_stop();
            return 1;
        }
    }
    delay_5us();
    IIC_SCL=0;
    return 0;  
} 
/* brief : 产生应答信号*/
void bsp_iic_ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_5us();
    IIC_SCL=1;
    delay_5us();
    IIC_SCL=0;
}
/* brief : 产生非应答信号*/            
void bsp_iic_nAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_5us();
    IIC_SCL=1;
    delay_5us();
    IIC_SCL=0;
}                                        
/*
*************************************************
**  breif : IIC发送一个字节
*************************************************
*/
void bsp_iic_sendByte( u8 txd )
{
    u8 t;
    delay_5us();    
    SDA_OUT();      
    IIC_SCL=0;
    for(t=0;t<8;t++)
    {              
        if((txd&0x80)>>7)
            IIC_SDA=1;
        else
            IIC_SDA=0;
        txd<<=1;      
        delay_5us(); 
        IIC_SCL=1;
        delay_5us(); 
        IIC_SCL=0;  
        delay_5us();
    }    
}       
/*
**************************************************************************************
**  brief : 读1个字节
**  ack   :1.发送ACK,0.发送NACK
**  note  : 主机作为接收方,发送一个非应答信号表示数据传输结束
**                                                   发送一个应答信号表示数据接收成功
**            从机作为接收方,发送一个非应答信号表示数据接受失败
**                                                   发送一个应答信号表示数据接收成功
**************************************************************************************
*/
u8 bsp_iic_readByte(unsigned char ack)
{
    unsigned char i,receive=0;

    delay_5us();    
    SDA_IN();
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        delay_5us();
        IIC_SCL=1;
        receive<<=1;
        delay_5us();
        if(READ_SDA)receive++;   
        delay_5us(); 
    }
    if (!ack)
        bsp_iic_nAck();
    else
        bsp_iic_ack(); 

    return receive;
}

文件(24cxx.h)

u8 bsp_eeprom_readOneByte(u16 ReadAddr);                            
void bsp_eeprom_writeOneByte(u16 WriteAddr,u8 DataToWrite);     
void bsp_eeprom_writeLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);
u32 bsp_eeprom_readLenByte(u16 ReadAddr,u8 Len);                    
void bsp_eeprom_write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);    
void bsp_eeprom_read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   
u8 bsp_eeprom_writePage_zero(u16 WriteAddr, u8 data, u16 NumToWrite);

void bsp_eeprom_init(void);
void bsp_eeprom_reset(void);

文件(24cxx.c)

#define AT24C01     127
#define AT24C02     255
#define AT24C04     511
#define AT24C08     1023
#define AT24C16     2047
#define AT24C32     4095
#define AT24C64     8191
#define AT24C128    16383
#define AT24C256    32767

#define EE_TYPE AT24C256
#define EE_PAGE_SIZE 64   

/*
**************************************************************************
**  note : 1. EEPROM高四位地址固定为1010
**           2. 主设备在从从设备接收到最后一个字节后发送
**               一个NACK 。接收到NACK 后,从设备释放对SCL和SDA
**               线的控制;主设备就可以发送一个停止/ 重起始
**               条件
**           3. 在EEPROM的一次写循环中可以写多个字节,但一次
**               写入的字节数不能超过EEPROM的页大小
*************************************************************************
*/
void bsp_eeprom_init(void)
{
    bsp_eeprom_reset();
    delay_ms(1);
}
/* brief : EEPROM复位*/
void bsp_eeprom_reset(void)
{
    u32 i;
    //OSSchedLock();
    bsp_iic_Start();
    SDA_OUT();
    delay_us(1);
    IIC_SDA = 1;
    for(i=0; i<9; ++i) {
        delay_us(1);
        IIC_SCL = 1;
        delay_us(1);
        IIC_SCL = 0;
    }
    SDA_IN();
    bsp_iic_Start();
    IIC_Stop();
    //OSSchedUnlock();
}
/*
**********************************************************
**  brief : 读数据
**  ReadAddr : 待读数据地址
**  ret : 读出的数据
**********************************************************
*/
u8 bsp_eeprom_readOneByte(u16 ReadAddr)
{
    u8 temp=0;

    //OSSchedLock();

    bsp_iic_Start();  
    if(EE_TYPE>AT24C16)
    {
        bsp_iic_sendByte(0XA0);       /*发送写命令*/
        bsp_iic_waitAck();
        bsp_iic_sendByte(ReadAddr>>8);/*发送高地址*/
    } else {
        bsp_iic_sendByte(0XA0+((ReadAddr/256)<<1));/*发送器件地址0XA0,写数据*/    
    }
    bsp_iic_waitAck(); 
    bsp_iic_sendByte(ReadAddr%256);   /*发送低地址*/
    bsp_iic_waitAck();      
    bsp_iic_Start();           
    bsp_iic_sendByte(0XA1);           /*进入接收模式  */         
    bsp_iic_waitAck();   
    temp=bsp_iic_readByte(0);

    bsp_iic_stop();                   

    //OSSchedUnlock();

    return temp;
}
/*
*******************************************************************
**  brief : 指定地址写入数据
**  WriteAddr : 待写入地址
**  DataToWrite : 待写入数据
*******************************************************************
*/
void bsp_eeprom_writeOneByte(u16 WriteAddr,u8 DataToWrite)
{
    //OSSchedLock();

    bsp_iic_Start();  
    if(EE_TYPE>AT24C16)
    {
        bsp_iic_sendByte(0XA0);    
        bsp_iic_waitAck();

        bsp_iic_sendByte(WriteAddr>>8);
    }else
    {
        bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));
    }    
    bsp_iic_waitAck();

    bsp_iic_sendByte(WriteAddr%256);   
    bsp_iic_waitAck();

    bsp_iic_sendByte(DataToWrite);    
    bsp_iic_waitAck();

    bsp_iic_stop();                    

    //OSSchedUnlock();
    /*AT24C256的WriteCycle 最大5ms,所以这个世界绝对不能小于5ms*/
    delay_ms(10);
}

/*
***********************************************************************************************
**  brief : 指定地址写入指定长度的数据
**  WriteAddr : 待写入地址
**  datas : 待写入数据缓冲指针
**  NumToWrite : 待写入数据长度,调用方需要确保不超过页大小
**  ret : 0成功,否者失败
**  note : 在用Page 的方式进行离线数据写入时,会出现写入失败的情况.
***********************************************************************************************
*/ 
static u8 bsp_eeprom_writePage(u16 WriteAddr, u8 *datas, u16 NumToWrite)
{
    u8 result;
    u8 ret = 0;
    u32 i;

    //OSSchedLock();

    do {
        bsp_iic_Start();  
        if(EE_TYPE>AT24C16)
        {
            bsp_iic_sendByte(0XA0);    
            result = bsp_iic_waitAck();
            if(0 != result) {
                ret = 1;
                break;
            }
            bsp_iic_sendByte(WriteAddr>>8);
         } else {
            bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));  
        }
        result = bsp_iic_waitAck();
        if(0 != result) {
            ret = 1;
            break;
        }
        bsp_iic_sendByte(WriteAddr%256);   

        result = bsp_iic_waitAck();
        if(0 != result) {
            ret = 1;
            break;
        }

        i=0;
        while(NumToWrite--) {        /* 循环发送数据*/
            bsp_iic_sendByte(datas[i]);    
            ++i;
            result = bsp_iic_waitAck();
            if(0 != result) {
                ret = 1;
                break;
            }
        }
        bsp_iic_stop();
    }while(0);

    //OSSchedUnlock();

    delay_ms(10);    

    return ret;
}

/*
***********************************************************************************
**  brief : 指定地址写入指定长度的数据
**  WriteAddr : 待写入地址
**  data : 待写入数据
**  NumToWrite : 待写入数据长度,调用方需要确保不超过页大小
**  ret : 0成功,否者失败
***********************************************************************************
*/ 

u8 bsp_eeprom_writePage_zero(u16 WriteAddr, u8 data, u16 NumToWrite)
{
    u8 result;
    u8 ret = 0;

    //OSSchedLock();

    do {
        bsp_iic_Start();  
        if(EE_TYPE>AT24C16)
        {
            bsp_iic_sendByte(0XA0);    
            result = bsp_iic_waitAck();
            if(0 != result) {
                ret = 1;
                break;
            }

            bsp_iic_sendByte(WriteAddr>>8);
        } else {
            bsp_iic_sendByte(0XA0+((WriteAddr/256)<<1));   
        }
        result = bsp_iic_waitAck();
        if(0 != result) {
            ret = 1;
            break;
        }
        bsp_iic_sendByte(WriteAddr%256);   

        result = bsp_iic_waitAck();
        if(0 != result) {
            ret = 1;
            break;
        }

        while(NumToWrite--) {
            bsp_iic_sendByte(data);     
            result = bsp_iic_waitAck();
            if(0 != result) {
                ret = 1;
                break;
            }
        }

        bsp_iic_stop();
    }while(0);

    //OSSchedUnlock();
    delay_ms(10);   

    return ret;
}
/*
************************************************************************
**  breif : 指定地址写入指定长度数据
**  WriteAddr : 待写入地址
**  DataToWrite : 待写入数据
**  Len : 待写入数据长度1-4
************************************************************************
*/
void bsp_eeprom_writeLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{
    u8 b[4];
    b[0] = (u8)DataToWrite;
    b[1] = (u8)(DataToWrite>>8);
    b[2] = (u8)(DataToWrite>>16);
    b[3] = (u8)(DataToWrite>>24);
    bsp_eeprom_write(WriteAddr, b, Len);
}

/*
************************************************************************
**  breif : 指定地址开始读出长度为Len的数据
**            该函数用于读出16bit或者32bit的数据.
**  ReadAddr   : 开始读出的地址 
**  Len : 要读出数据的长度2,4
**  Ret : 读出的16bit或32bit数据
************************************************************************
*/
u32 bsp_eeprom_readLenByte(u16 ReadAddr,u8 Len)
{
    u8 buf[4];
    u32 temp=0;
    u32 v;
    if(Len == 0 || Len == 1 || Len == 3|| (Len > 4)) {
        return 0;
    }
    bsp_eeprom_read(ReadAddr, buf, Len);

    if(Len == 2) {
        v = buf[1];
        temp |= (v << 8);
        v = buf[0];
        temp |= v;
    }

    if(Len == 4) {
        v = buf[3];
        temp |= (v << 24);
        v = buf[2];
        temp |= (v << 16);
        v = buf[1];
        temp |= (v << 8);
        v = buf[0];
        temp |= v;
    }
    return temp;                                                    
}

/*
*****************************************************************************
**  breif : 指定地址读出指定长度的数据
**  ReadAddr : 待读取地址
**  buf : 待读出数据的缓冲指针
**  numToRead : 待读出的数据长度
*****************************************************************************
*/
void bsp_eeprom_read(u16 ReadAddr,u8 *buf,u16 numToRead)
{
    u8 temp=0;
    if(numToRead == 0) {
        return ;
    }
    //OSSchedLock();
    bsp_iic_Start();  
    if(EE_TYPE>AT24C16)
    {
        bsp_iic_sendByte(0XA0);    
        bsp_iic_waitAck();
        bsp_iic_sendByte(ReadAddr>>8);
    } else {
        bsp_iic_sendByte(0XA0+((ReadAddr/256)<<1));      
    }
    bsp_iic_waitAck(); 

    bsp_iic_sendByte(ReadAddr%256);  
    bsp_iic_waitAck();      
    bsp_iic_Start();           
    bsp_iic_sendByte(0XA1);            
    bsp_iic_waitAck();
    while(numToRead-1) {
        temp = bsp_iic_readByte(1);
        *buf = temp;
        ++buf;
        --numToRead;
    }
    temp = bsp_iic_readByte(0);
    *buf = temp;

    bsp_iic_stop();

    //OSSchedUnlock();
}
/*
*****************************************************************************
**  brief           : 将缓冲区的数据写到EEPROM 中
**  WriteAddr    : 待写入地址
**  pBuffer        : 数据缓冲区指针
**  NumToWrite : 待写入字节数
**  note            : http://wenku.baidu.com/view/4ffb2eb21a37f111f1855ba7.html
*****************************************************************************
*/
void bsp_eeprom_write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
    u16 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
    Addr = WriteAddr % EE_PAGE_SIZE;          /* 写入地址是不是64的整数倍*/
    count = EE_PAGE_SIZE - Addr;              /* 距离下一页页首的距离*/
    NumOfPage = NumToWrite / EE_PAGE_SIZE;    /* 一共多少页*/
    NumOfSingle = NumToWrite % EE_PAGE_SIZE;  /* 不够一页的数据余量*/

    if(Addr == 0)                   /* 首页地址*/
    {
        if(NumOfPage == 0)          /* 不足一页数据*/
        {        
            bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);
        }else                       /* 数据超过一页*/
        {
            while(NumOfPage -- ) 
            {
                bsp_eeprom_writePage(WriteAddr, pBuffer, EE_PAGE_SIZE);
                pBuffer += EE_PAGE_SIZE;
                WriteAddr += EE_PAGE_SIZE;
            }
            if(NumOfSingle > 0) 
            {
                bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);
            }
        }
    } else                           /* 非首页地址*/
    {
        if(NumOfPage == 0)           /* 不足一页数据*/
        {        
            bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);
        } else                       /* 数据超过一页*/
        {
            NumToWrite -= count;   
            NumOfPage = NumToWrite / EE_PAGE_SIZE;    /* 剩余的页数*/
            NumOfSingle = NumToWrite % EE_PAGE_SIZE;  /* 不足一页的数据*/
            if(count > 0) 
            {
                bsp_eeprom_writePage(WriteAddr, pBuffer, count);
                pBuffer += count;
                WriteAddr += count;
            }
            while(NumOfPage -- ) 
            {
               bsp_eeprom_writePage(WriteAddr, pBuffer, EE_PAGE_SIZE);
                pBuffer += EE_PAGE_SIZE;
                WriteAddr += EE_PAGE_SIZE;
            }
            if(NumOfSingle > 0)
            {
                bsp_eeprom_writePage(WriteAddr, pBuffer, NumOfSingle);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u010650845/article/details/77479933