24cxx驱动- eeprom(i2c通信)

8 篇文章 2 订阅
7 篇文章 1 订阅

1、I2C驱动程序

/*****************************************************************************
FileName : i2c.c
Function : I2C协议驱动
Author   : mike
Email    : hxtiou@163.com
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_DATA_IN();
    iic_delay();
    IIC_CLK_HIGH();
    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    : hxtiou@163.com
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    : hxtiou@163.com
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_start();
	iic_write_byte(I2C_ADDR);	 			//eeprom写指令
	iic_response();
	iic_write_byte(addr); 				//写入数据的地址
	iic_response();
	iic_write_byte(dat);	 			//写入的数据
	iic_response();
	iic_stop();
	
	delay_ms(2);						//延时必须
}

u8 eeprom_read_byte(u16 addr)			//eeprom读一字节
{		
	u8 temp;
	iic_start();
	iic_write_byte(I2C_ADDR);	  			//eeprom写指令
	iic_response();
	iic_write_byte(addr);  				//读取数据的地址
	iic_response();
	iic_start();
	iic_write_byte(I2C_ADDR|0x01);	  			//eeprom读指令
	iic_response();		
	temp = iic_read_byte();
	iic_stop();
	return temp;
}

void eeprom_write_nbyte(u16 addr,u8 *pbuf,u8 len)	//eeprom写N字节	
{
#if 1
    while(len--)
    {
        eeprom_write_byte(addr++,*pbuf++);
        delay_ms(5); //24cxx写一字节后必须延时	
    }	
#else
    while(len)
    {
        eeprom_write_byte(addr,*pbuf);
        addr ++;
        pbuf ++;
        len --;
    }	
#endif
}
void eeprom_read_nbyte(u16 addr,u8 *pbuf,u8 len)	//eeprom读N字节	
{
#if 1
    while(len--)
    {
        *pbuf++ = eeprom_read_byte(addr ++);	
    }	
#else
    while(len)
    {
        *pbuf = eeprom_read_byte(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    : hxtiou@163.com
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 I2C_ADDR		            0xA0
#define I2C_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








  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是一个简单的在Linux系统下使用I2C协议读写AT24CXX系列EEPROM的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #define I2C_ADDR 0x50 // EEPROM的I2C地址 #define EEPROM_SIZE 256 // EEPROM的大小 int main(void) { int fd; char buf[EEPROM_SIZE], data[EEPROM_SIZE]; int i; // 打开I2C总线 if ((fd = open("/dev/i2c-1", O_RDWR)) < 0) { perror("Failed to open i2c bus"); exit(1); } // 设置从设备地址 if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) { perror("Failed to set i2c address"); exit(1); } // 读EEPROM if (read(fd, buf, EEPROM_SIZE) != EEPROM_SIZE) { perror("Failed to read from the i2c bus"); exit(1); } // 打印EEPROM中的数据 printf("Read data: "); for (i = 0; i < EEPROM_SIZE; i++) { printf("%02x ", buf[i]); } printf("\n"); // 写EEPROM for (i = 0; i < EEPROM_SIZE; i++) { data[i] = i & 0xff; } if (write(fd, data, EEPROM_SIZE) != EEPROM_SIZE) { perror("Failed to write to the i2c bus"); exit(1); } // 读EEPROM if (read(fd, buf, EEPROM_SIZE) != EEPROM_SIZE) { perror("Failed to read from the i2c bus"); exit(1); } // 打印EEPROM中的数据 printf("Read data: "); for (i = 0; i < EEPROM_SIZE; i++) { printf("%02x ", buf[i]); } printf("\n"); // 关闭I2C总线 close(fd); return 0; } ``` 在使用该代码之前,需要确保已经将I2C总线驱动加载到内核中,并且已经连接好了AT24CXX系列EEPROM。如果需要使用其他I2C从设备,只需要将I2C_ADDR修改为对应从设备的地址即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值