24c0x读写 大于256字节读写方式,以24c08为例(24c04/08/16同理)

最近在做一个点阵屏的项目,其中用到了储存芯片20c08,当找资料时时发现全网都是24c02的读写例程然后程序下进去后发现能用,就没有在意(开始测试的时候数据用的很少不到256个)。

当程序框架基本完成时我开始进行多数测试,突然发现我的程序只能进行0-255的数据存储,当数据超过255时就会重头开始。

后来我从网上找了很多资料发现都是24c02的程序,存储数量都不能超过256。于是经过一天的研究终于解决了这个问题。记录一下,希望能帮助与到同样问题的小伙伴。

第一部分 原理说明

在读写过程中24c0x是分页写的,每页可以存256个字节,网上的驱动程序多为24c02,默认为第一页,当输入大于256时需要加一个换页,以24c08为例,一共有1K字节,每页256,一共为4页,以下为I²C的发送命令格式,前面四个1010是eeprom的固定格式不能动,对应16进制为A;后面四位的前三位数据(P0,P1,P2)就是翻页所需的地址(也可以理解为页地址),第四位R/W为读写控制位,最重要的就是图中的P0,P1,P2数据位,因为24c08只有四页所以只需要两个二进制数据即可(P2位强制为0)

P1  P2值
00第0页
01第1页
10第2页
00第3页

第二部分 程序编写

我的程序并没有从头开始写,由于我是在24c02的基础上搭好了程序框架才发现的问题,所以我的程序修改宗旨就是:以最少的修改完成读写任务,

下面是我原本的24C02程序



#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit sda = P2 ^ 1;                          //IO口定义
sbit scl = P2 ^ 0;
//此为待写入24c02的数据。为了便于验证结果,数组的内容为周期重复的。
void UART_TX_Send(uchar i);

char code music[] = {
    0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0,
    0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0
};     //由于最后还要讲这些数据通过串口发送到电脑  波特率9600
uchar data buffer[100]; //用于缓存从24c02中读取的数据。
void delay(unsigned int m)
{
    unsigned int n, p;
    for (n = m; n>0; n--)
    for (p = 125; p>0; p--);
}
void nop()
{
    _nop_();
    _nop_();
}
/24C02读写驱动程序
void delay1(unsigned int m)
{
    unsigned int n;
    for (n = 0; n<m; n++);
}
void init()  //24c02初始化子程序
{
    scl = 1;
    nop();
    sda = 1;
    nop();
}
void start()        //启动I2C总线
{
    sda = 1;
    nop();
    scl = 1;
    nop();
    sda = 0;
    nop();
    scl = 0;
    nop();
}
void stop()         //停止I2C总线
{
    sda = 0;
    nop();
    scl = 1;
    nop();
    sda = 1;
    nop();
}
void writebyte(unsigned char j)  //写一个字节
{
    unsigned char i, temp;
    temp = j;
    for (i = 0; i<8; i++)
    {
        temp = temp << 1;
        scl = 0;
        nop();
        sda = CY;        //temp左移时,移出的值放入了CY中
        nop();
        scl = 1;        //待sda线上的数据稳定后,将scl拉高
        nop();
    }
    scl = 0;
    nop();
    sda = 1;
    nop();
}
unsigned char readbyte()   //读一个字节
{
    unsigned char i, j, k = 0;
    scl = 0; nop(); sda = 1;
    for (i = 0; i<8; i++)
    {
        nop(); scl = 1; nop();
        if (sda == 1)
            j = 1;
        else
            j = 0;
        k = (k << 1) | j;
        scl = 0;
    }
    nop();
    return(k);
}
void clock()         //I2C总线时钟
{
    unsigned char i = 0;
    scl = 1;
    nop();
    while ((sda == 1) && (i<255))
        i++;
    scl = 0;
    nop();
}
从24c02的地址address中读取一个字节数据/
unsigned char read24c02(unsigned char address)
{
    unsigned char i;
    start();
    writebyte(0xa0);
    clock();
    writebyte(address);
    clock();
    start();
    writebyte(0xa1);
    clock();
    i = readbyte();
    stop();
    delay1(100);
    return(i);
}
//向24c02的address地址中写入一字节数据info/
void write24c02(unsigned char address, unsigned char info)
{
    start();
    writebyte(0xa0);
    clock();
    writebyte(address);
    clock();
    writebyte(info);
    clock();
    stop();
    delay1(5000); //这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。
}
//从24c02的地址address中读取一个字节数据/

//串口初始化
void UARTInit()
{
   
	EA  = 1;	//打开总中断
	ES  = 1; //打开串口中断
	SM0 = 0;	
	SM1 = 1;//串口工作方式1,8位UART波特率可变
	REN = 1;//串口允许接收
	TR1 = 1;//启动定时器1
	TMOD |= 0x20;//定时器1,工作模式2 8位自动重装
	TH1 = 0xfd;
	TL1 = 0xfd;//设置比特率9600
	
}
//串口发送程序
void UART_TX_Send(uchar i)
{
		SBUF=i;
		while(!TI);
		TI=0;
}
void main()
{
    uchar add, j;
    init();        //初始化24C02
		UARTInit();

    while (add != sizeof(music))
    {
        write24c02(0x05 + add, music[add]);
        add++;
        if (add % 4 == 0)
            P1 = ~P1;
    }

    //到此为止,向24C02中写入数据的过程均已结束。下面的程序为附加的。
    //将已写入的数据再读出,送到串口助手
for (j=0;j<sizeof(music);j++)
{
	UART_TX_Send(read24c02(0x05+j));

		delay(50);


}
//	while (j != add)
//	{
//		
//		UART_TX_Send(read24c02(0x05+j));
//		j++;
//		delay(50);
//	}
	while (1);
}

经过分析后我仅仅修改了读写函数  以下是修改部分

主函数测试 直接从0xf5开始读写 最后打印的数据正常

 

 这个改法好处是其他部分的程序都不用动,直接往里面扔数据就行大于256也可以。

下面是改好的程序



#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit sda = P2 ^ 1;                          //IO口定义
sbit scl = P2 ^ 0;
//此为待写入24c02的数据。为了便于验证结果,数组的内容为周期重复的。
void UART_TX_Send(uchar i);

char code music[] = {
    0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0,
    0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0, 0x55, 0xaa, 0x0f, 0xf0
};     //由于最后还要讲这些数据通过串口发送到电脑  波特率9600
uchar data buffer[100]; //用于缓存从24c02中读取的数据。
void delay(unsigned int m)
{
    unsigned int n, p;
    for (n = m; n>0; n--)
    for (p = 125; p>0; p--);
}
void nop()
{
    _nop_();
    _nop_();
}
/24C02读写驱动程序
void delay1(unsigned int m)
{
    unsigned int n;
    for (n = 0; n<m; n++);
}
void init()  //24c02初始化子程序
{
    scl = 1;
    nop();
    sda = 1;
    nop();
}
void start()        //启动I2C总线
{
    sda = 1;
    nop();
    scl = 1;
    nop();
    sda = 0;
    nop();
    scl = 0;
    nop();
}
void stop()         //停止I2C总线
{
    sda = 0;
    nop();
    scl = 1;
    nop();
    sda = 1;
    nop();
}
void writebyte(unsigned char j)  //写一个字节
{
    unsigned char i, temp;
    temp = j;
    for (i = 0; i<8; i++)
    {
        temp = temp << 1;
        scl = 0;
        nop();
        sda = CY;        //temp左移时,移出的值放入了CY中
        nop();
        scl = 1;        //待sda线上的数据稳定后,将scl拉高
        nop();
    }
    scl = 0;
    nop();
    sda = 1;
    nop();
}
unsigned char readbyte()   //读一个字节
{
    unsigned char i, j, k = 0;
    scl = 0; nop(); sda = 1;
    for (i = 0; i<8; i++)
    {
        nop(); scl = 1; nop();
        if (sda == 1)
            j = 1;
        else
            j = 0;
        k = (k << 1) | j;
        scl = 0;
    }
    nop();
    return(k);
}
void clock()         //I2C总线时钟
{
    unsigned char i = 0;
    scl = 1;
    nop();
    while ((sda == 1) && (i<255))
        i++;
    scl = 0;
    nop();
}
unsigned int read24c02(unsigned int address)
{
    uchar i,addr;
	
		addr=(address/0xff*2); //address 0 1 2 3, addr 0 2 4 6
		//UART_TX_Send(addr);
    start();
    writebyte(0xa0+addr);//选页 写:第1页A0 ,2页A2 ,3页A4,4页A6 
    clock();
    writebyte(address%0xff);//写地址0-255
    clock();
    start();
    writebyte(0xa1+addr);///选页 读:第1页A1 ,2页A3 ,3页A4,4页A7 就是写+1
    clock();
    i = readbyte();
    stop();
    delay1(100);
    return(i);

}
//向24c02的address地址中写入一字节数据info/
void write24c02(unsigned int address, unsigned char info)
{
		uchar addr;
		addr=address/0xff*2; //address/0xff= 0 1 2 3, addr= 0 2 4 6
    start();
    writebyte(0xa0+addr);//选页 写:第1页A0 ,2页A2 ,3页A4,4页A6 
    clock();
    writebyte(address%0xff);//写地址0-255
    clock();
    writebyte(info);
    clock();
    stop();
    delay1(5000); //这个延时一定要足够长,否则会出错。因为24c02在从sda上取得数据后,还需要一定时间的烧录过程。
}
//从24c02的地址address中读取一个字节数据/

//串口初始化
void UARTInit()
{
   
	EA  = 1;	//打开总中断
	ES  = 1; //打开串口中断
	SM0 = 0;	
	SM1 = 1;//串口工作方式1,8位UART波特率可变
	REN = 1;//串口允许接收
	TR1 = 1;//启动定时器1
	TMOD |= 0x20;//定时器1,工作模式2 8位自动重装
	TH1 = 0xfd;
	TL1 = 0xfd;//设置比特率9600
	
}
//串口发送程序
void UART_TX_Send(uchar i)
{
		SBUF=i;
		while(!TI);
		TI=0;
}
void main()
{
    uchar add, j;
    init();        //初始化24C02
		UARTInit();

    while (add != sizeof(music))
    {
        write24c02(0xf5 + add, music[add]);
        add++;
        if (add % 4 == 0)
            P1 = ~P1;
    }

    //到此为止,向24C02中写入数据的过程均已结束。下面的程序为附加的。
    //将已写入的数据再读出,送到串口助手
for (j=0;j<sizeof(music);j++)
{
	UART_TX_Send(read24c02(0xf5+j));

		delay(50);


}
	while (1);
}

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要读取和写入AT24C512的多个字节,你可以使用循环来逐个处理字节。以下是一个简单的示例代码,用于在GD32F4上使用I2C接口读取和写入AT24C512的多个字节: ```c #include "gd32f4xx.h" #include "at24c512.h" // 初始化I2C接口 void i2c_init(void) { // I2C初始化配置,略去具体代码 } // 向AT24C512写入多个字节 void at24c512_write_bytes(uint16_t addr, uint8_t *data, uint16_t len) { i2c_start_on_bus(I2C0); i2c_flag_clear(I2C0, I2C_FLAG_SBSEND); i2c_master_addressing(I2C0, AT24C512_ADDR, I2C_TRANSMITTER); while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_data_transmit(I2C0, addr >> 8); while (!i2c_flag_get(I2C0, I2C_FLAG_TBE)); i2c_data_transmit(I2C0, addr & 0xFF); while (!i2c_flag_get(I2C0, I2C_FLAG_TBE)); for (uint16_t i = 0; i < len; i++) { i2c_data_transmit(I2C0, data[i]); while (!i2c_flag_get(I2C0, I2C_FLAG_TBE)); } i2c_stop_on_bus(I2C0); } // 从AT24C512读取多个字节 void at24c512_read_bytes(uint16_t addr, uint8_t *data, uint16_t len) { i2c_start_on_bus(I2C0); i2c_flag_clear(I2C0, I2C_FLAG_SBSEND); i2c_master_addressing(I2C0, AT24C512_ADDR, I2C_TRANSMITTER); while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_data_transmit(I2C0, addr >> 8); while (!i2c_flag_get(I2C0, I2C_FLAG_TBE)); i2c_data_transmit(I2C0, addr & 0xFF); while (!i2c_flag_get(I2C0, I2C_FLAG_TBE)); i2c_start_on_bus(I2C0); i2c_flag_clear(I2C0, I2C_FLAG_SBSEND); i2c_master_addressing(I2C0, AT24C512_ADDR, I2C_RECEIVER); while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); i2c_ack_config(I2C0, I2C_ACK_ENABLE); for (uint16_t i = 0; i < len; i++) { if (i == len - 1) { i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT); i2c_ack_config(I2C0, I2C_ACK_DISABLE); } while (!i2c_flag_get(I2C0, I2C_FLAG_RBNE)); data[i] = i2c_data_receive(I2C0); } i2c_stop_on_bus(I2C0); } ``` 上述代码中,`at24c512_write_bytes()` 函数用于向AT24C512写入多个字节。它首先发送起始信号和设备地址,并发送存储地址,然后使用一个循环逐个发送字节数据。最后,发送停止信号。 `at24c512_read_bytes()` 函数用于从AT24C512读取多个字节。它首先发送起始信号和设备地址,并发送存储地址,然后重新发送起始信号,并将设备地址设置为接收模式。接下来,使用一个循环逐个接收字节数据。在最后一个字节之前,使能ACK(应答),并将ACK位置为当前位置。在最后一个字节时,禁用ACK,以便在接收完最后一个字节后停止应答。最后,发送停止信号。 你可以根据你的具体需求和硬件连接适配代码,并进行相应的调试。希望这能帮助到你!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值