单片机
返回首页

STM32模拟IIC读写24CXX

2018-04-15 来源:eefocus

文件(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);

            }

        }

    }

}


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 如何调制IC555振荡器

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章