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








 

你可能感兴趣的:(单片机,驱动,C语言)