赞
踩
最近在做一个点阵屏的项目,其中用到了储存芯片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);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。