24cxx驅動- eeprom(i2c通信)

1、I2C驅動程序

/*****************************************************************************
FileName : i2c.c
Function : I2C協議驅動
Author   : mike
Email    : [email protected]
Version  : V1.0
Date     : 2019-10-19
Note     :
*****************************************************************************/
#include "include.h"
#include "i2c.h"

void iic_delay(void)
{
    _nop_();
    _nop_();
}
void iic_init(void)		//iic初始化---釋放總線
{
    IIC_DATA_HIGH();
    IIC_CLK_HIGH();
}
void iic_start(void)	//IIC開始---在SCL高電平時SDA有一個下降沿
{
    IIC_DATA_HIGH();
    iic_delay();
    IIC_CLK_HIGH();
    iic_delay();
    IIC_DATA_LOW();
    iic_delay();	
}
void iic_stop(void)			//IIC停止---在SCL高電平時SDA有一個上升沿
{
    IIC_DATA_LOW();
    iic_delay();
    IIC_CLK_HIGH();
    iic_delay();
    IIC_DATA_HIGH();
    iic_delay();
}

void iic_response(void)	//響應---等待返回一個sda=0或者i>=250,默認爲響應
{
    u8 retry = 0;
    IIC_CLK_HIGH();
    iic_delay();
    IIC_DATA_OUT();
    while(IIC_DATA_IS_HIGH() && retry++ < 250)
    {
        iic_delay();
    }		
    IIC_CLK_LOW();
    iic_delay();
}

void iic_write_byte(u8 dat)	 //iic寫一字節
{
    u8 i;
    IIC_CLK_LOW();
    iic_delay();
    IIC_DATA_OUT();

    for(i=8;i!=0;i--)	
    {
        if (dat & BIT(7))
            IIC_DATA_HIGH();
        else
            IIC_DATA_LOW();
        dat <<= 1;			//此句必須放在後面
		
        iic_delay();
        IIC_CLK_HIGH();
        iic_delay();
        IIC_CLK_LOW();
        iic_delay();
    }
    IIC_DATA_HIGH();
    iic_delay();
}

u8 iic_read_byte(void)	//iic讀一字節
{
    u8 i;
    u8 temp;
    IIC_CLK_LOW();
    iic_delay();
    IIC_DATA_HIGH();
    iic_delay();
    IIC_DATA_IN();
    for(i=8;i!=0;i--)	
    {
        IIC_CLK_HIGH();
        iic_delay();
        temp <<= 1;	//此句必須放前面	
        if(IIC_DATA_IS_HIGH())			
            temp |= BIT(0);

        IIC_CLK_LOW();
        iic_delay();
    }
    IIC_DATA_HIGH();
    iic_delay();
    return temp;	
}



/*****************************************************************************
FileName : i2c.h
Function : I2C協議驅動
Author   : mike
Email    : [email protected]
Version  : V1.0
Date     : 2019-10-19
Note     :
*****************************************************************************/
#ifndef I2C_H
#define I2C_H

#define BIT(n)                          (1<<(n))

//sbit IIC_SCL = P2^0;
//sbit IIC_SDA = P2^1;

#define IIC_DATA                        1   //P21
#define IIC_CLK                         0   //P20
#define IIC_DATA_CLK_OUT()              //DATA和CLK設爲輸出
#define IIC_DATA_IN()                   //DATA設爲輸入
#define IIC_DATA_OUT()                  //DATA設爲輸出
#define IIC_DATA_CLK_HIGH()             //DATA和CLK輸出高
#define IIC_DATA_HIGH()                 P2 |= BIT(IIC_DATA)	//DATA輸出高
#define IIC_DATA_LOW()                  P2 &= ~BIT(IIC_DATA)//DATA輸出低
#define IIC_CLK_HIGH()                  P2 |= BIT(IIC_CLK)	//CLK輸出高
#define IIC_CLK_LOW()                   P2 &= ~BIT(IIC_CLK)	//CLK輸出低
#define IIC_DATA_IS_HIGH()              (P2 & BIT(IIC_DATA))//判斷DATA是否爲高

void iic_init(void);
void iic_start(void);
void iic_stop();	
void iic_response(void);
void iic_write_byte(u8 dat);
u8 iic_read_byte(void);



#endif

2、24CXX驅動程序

/*****************************************************************************
FileName : eeprom_24cxx.c
Function : 24CXX eeprom驅動程序
Author   : mike
Email    : [email protected]
Version  : V1.0
Date     : 2019-10-19
Note     : 

 器件			總容量(bit)		總頁數			byte/頁			字地址長度
24C02			  2K			  32			   8				8位
24C04			  4K			  32			   16				9位
24C08			  8K			  64			   16				10位
24C16			  16K			  128			   16				11位
24C32			  32K			  128			   32				12位
24C64			  64K			  256			   32				13位
1byte = 8bit

注意:24C16以下空間的大於8位後的尋址高位地址在片選地址中選擇,詳細看芯片手冊.
另外要注意的就是字節頁,一次連續寫入的數據量不能超過一頁的數據量.有些老款的
芯片甚至不支持跨頁寫入.爲了適用也參照不跨頁寫入的方法寫這個程序.而讀取數據
沒有這個限制,只要單片機開闢的緩存夠大,可以一直連續讀下去.

eeprom有寫入壽命,一般壽命10萬次,避免頻繁擦寫
*****************************************************************************/
#include "include.h" 
#include "eeprom_24cxx.h"

void eeprom_write_byte(u16 addr,u8 dat)	//eeprom寫一字節---寫如果寫超出範圍,會從地址0開始覆蓋	
{
    iic_write_byte(EEPROM_24CXX_SLAVE_ADDR,addr,dat);

    delay_ms(5);						//24cxx寫一字節後必須延時	
}

u8 eeprom_read_byte(u16 addr)			//eeprom讀一字節
{		
    u8 temp;
    temp = iic_read_byte(EEPROM_24CXX_SLAVE_ADDR,addr);	
    return temp;
}

void eeprom_write_nbyte(u16 addr,u8 *pbuf,u8 len)	//eeprom寫N字節	
{
#if 1
    while(len--)
    {
        iic_write_byte(EEPROM_24CXX_SLAVE_ADDR,addr++,*pbuf++);
        delay_ms(5); //24cxx寫一字節後必須延時	
    }	
#else
    while(len)
    {
        iic_write_byte(EEPROM_24CXX_SLAVE_ADDR,addr,*pbuf);
        addr ++;
        pbuf ++;
        len --;
    }	
#endif
}
void eeprom_read_nbyte(u16 addr,u8 *pbuf,u8 len)	//eeprom讀N字節	
{
#if 1
    while(len--)
    {
        *pbuf++ = iic_read_byte(EEPROM_24CXX_SLAVE_ADDR,addr ++);	
    }	
#else
    while(len)
    {
        *pbuf = iic_read_byte(EEPROM_24CXX_SLAVE_ADDR,addr);	
        pbuf ++;
        addr ++;
        len --;
    }	
#endif
}
void eeprom_write_multi(u16 addr,u8 *pbuf,u8 len)	//eeprom寫N字節---支持跨頁
{
    u8 page, cnt;
/*
    if(num > EE_SIZE)	//如果超過eeprom最大容量地址
    {
        return 0;
    }
*/
    cnt = (addr%PAGE_SIZE >len)? len : addr%PAGE_SIZE;
    if(cnt) 
    {
        eeprom_write_nbyte(addr, pbuf, cnt);
        delay_ms(2);          //跨頁時要延時2ms
        addr += cnt;
        pbuf += cnt;
        len -= cnt;
    }

    page = len/PAGE_SIZE;
    cnt = len%PAGE_SIZE;

    while(page--) 
    {
        eeprom_write_nbyte(addr, pbuf, PAGE_SIZE);
        delay_ms(2);          //跨頁時要延時2ms
        addr += PAGE_SIZE;
        pbuf += PAGE_SIZE;
    }

    if(cnt) 
    {
        eeprom_write_nbyte(addr, pbuf, cnt);
        delay_ms(2);          //寫完要延時2ms
    }	
}
void eeprom_read_multi(u16 addr,u8 *value,u8 len)	//eeprom讀N字節---
{
    u8 i;
    for(i = 0; i < len; i++) 
    {
        *(value + i) = eeprom_read_byte(addr + i);
    }	
}

void eeprom_24cxx_init(void)	//返回0表示eeprom初始化成功
{
    u8 temp = 0;
    u8 det_flag = 0;
    iic_init(EEPROM_24CXX_SLAVE_ADDR,EEPROM_24CXX_SPEED);         //初始化IIC
    temp = eeprom_read_byte(EE_ADDR_MAX);		//讀取是否曾經寫入0xAA---開機時不用每次都寫入

    //printf("temp = 0x%02X\n",temp);
	
    if(temp != 0xAB)							//失敗---或者第一次開機
    {
        eeprom_write_byte(EE_ADDR_MAX,0xAB);	//再次寫入固定值0xAA	
        temp = eeprom_read_byte(EE_ADDR_MAX);	//再檢測寫入0xAA是否成功
        if(temp != 0xAB)						//讀取失敗---器件有問題
        {
            det_flag = 1;						//返回1
        }	
    }
#if DEBUG_LOG_EN
    if(!det_flag)
    {
        printf("24cxx eeprom init ok\n");//檢測成功
    }
    else
    {
        printf("24cxx eeprom init error\n");//檢測失敗
    }
#endif
}
/*****************************************************************************
FileName : eeprom_24cxx.h
Function : 24CXX eeprom驅動程序
Author   : mike
Email    : [email protected]
Version  : V1.0
Date     : 2019-10-19
Note     :
*****************************************************************************/
#ifndef __EEPROM_24CXX_H
#define __EEPROM_24CXX_H


/************************************************************
01 -> 24C01;   02 -> 24C02;  04 -> 24C04;   08 -> 24C08;
16 -> 24C16;   32 -> 24C32;  64 -> 24C64;   128 -> 24C128;
256-> 24C256;  512 -> 24C512;
************************************************************/

#define EE_24C01_SIZE               0x007F//127
#define EE_24C02_SIZE               0x00FF//255		//32頁,每頁8byte
#define EE_24C04_SIZE               0x01FF//511
#define EE_24C08_SIZE               0x03FF//1023	//64頁,每頁16byte
#define EE_24C16_SIZE               0x07FF//2047	//128頁,每頁16byte
#define EE_24C32_SIZE               0x0FFF//4095
#define EE_24C64_SIZE               0x1FFF//8191
#define EE_24C128_SIZE              0x3FFF//16383
#define EE_24C256_SIZE              0x7FFF//32767
#define EE_24C512_SIZE              0xFFFF//65535

#define EE_24C01                    1  //127
#define EE_24C02                    2  //255(32頁,每頁8byte)
#define EE_24C04                    4
#define EE_24C08                    8  //1023(64頁,每頁16byte)
#define EE_24C16                    16 //2047
#define EE_24C32                    32 //4095
#define EE_24C64                    64 //8191
#define EE_24C128                   128 //16383
#define EE_24C256                   256 //32767
#define EE_24C512                   512 //65535

#define EEPROM_TYPE                 EE_24C02
#define EE_ADDR_MAX                 EE_24C02
#define EEPROM_24CXX_ID_FLAG        0x55	//24CXX第一次開機標誌記憶地址

#if EEPROM_TYPE == EE_24C01
   #define PAGE_SIZE                8		//字節/頁
   #define EE_SIZE                  0x007F	//eeprom的總容量
#elif EEPROM_TYPE == EE_24C02
   #define PAGE_SIZE                16
   #define EE_SIZE                  0x00FF
#elif EEPROM_TYPE == EE_24C04
   #define PAGE_SIZE                16
   #define EE_SIZE                  0x01FF
#elif EEPROM_TYPE == EE_24C08
   #define PAGE_SIZE                16
   #define EE_SIZE                  0x03FF
#elif EEPROM_TYPE == EE_24C16
   #define PAGE_SIZE                16
   #define EE_SIZE                  0x07FF
#elif EEPROM_TYPE == EE_24C32
   #define PAGE_SIZE                32
   #define EE_SIZE                  0x0FFF
#elif EEPROM_TYPE == EE_24C64
   #define PAGE_SIZE                32
   #define EE_SIZE                  0x1FFF
#elif EEPROM_TYPE == EE_24C128
   #define PAGE_SIZE                64
   #define EE_SIZE                  0x3FFF
#elif EEPROM_TYPE == EE_24C256
   #define PAGE_SIZE                64
   #define EE_SIZE                  0x7FFF
#elif EEPROM_TYPE == EE_24C512
   #define PAGE_SIZE                128
   #define EE_SIZE                  0xFFFF
#endif


#define EEPROM_24CXX_SLAVE_ADDR     0xA0
#define EEPROM_24CXX_SPEED          100000



void eeprom_write_byte(u16 addr,u8 dat);
u8 eeprom_read_byte(u16 addr);
void eeprom_write_nbyte(u16 addr,u8 *pbuf,u8 len);
void eeprom_read_nbyte(u16 addr,u8 *pbuf,u8 len);
void eeprom_write_multi(u16 addr,u8 *pbuf,u8 len);
void eeprom_read_multi(u16 addr,u8 *value,u8 len);
void eeprom_24cxx_init(void);


#endif








 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章