共1条
1/1 1 跳转至页
[推荐]51 flash文件系统DIY___I2C EEPROM的读写(2)
今天我们接着昨天来写I2C.c中的函数.
多个器件可以同时连到I2C总线上,靠不同的硬件地址来区分.24C256就有两个引脚是设
置硬件地址的,我们这里把他们都接到地.这样24C256的地址就是0xa0了(为什么是0xa0
你再仔细看看它的datasheet吧),为了防止我们将来还要在I2C总线上面接其他类型的器
件,我们用一个全局变量I2cDevAdd来记录硬件地址.然后再写一个函数让其他模快可以通
过这个接口来更改变量I2cDevAdd.如果要读写其他I2C器件时,要先设置器件地址.
把这一行放到I2c.c的所有函数前面:
uchar I2cDevAdd;
把下面的函数添加到I2c.c中
/***********************************************/
设置将要操作的I2c器件 输入:器件地址uchar dev
/***********************************************/
void SetI2cDev(uchar dev)
{
I2cDevAdd=dev;
}
下面是起始条件,停止条件.除了起始条件和停止条件I2c要求SDA必须在SCL为低时改
变.这一点在写起始条件函数时要注意.为了防止数据意外被送入每次操作后都将SCL置低.
起始条件要求在SCL为高时SCL由高变低,由于我们在送起始条件时不知道SDA是高还
是低所以我们先把它置高.
/***********************************************/
送出I2c起始条件
/***********************************************/
void I2cStart(void)
{
SCL=0; I2cDelay();
SDA=1; I2cDelay();
SCL=1; I2cDelay();
SDA=0; I2cDelay();
SCL=0; I2cDelay();
}
停止条件要求SCL为高时SDA由低变高.所以要先置SDA为低
/***********************************************/
送出I2c停止条件
/***********************************************/
void I2cStop(void)
{
SDA=0; I2cDelay();
SCL=1; I2cDelay();
SDA=1; I2cDelay();
SCL=0; I2cDelay();
}
I2C在每收到一个字节时都会给一个应答,也就是在下一个CLOCK将SDA拉低为了满足
时序要求有下面的函数
/***********************************************/
接收I2c的应答
/***********************************************/
void I2cSlvAck(void)
{
SCL=1; I2cDelay();
SCL=0;
}
然后就是数据的发送和接收了,I2C上所有的数据都是串行的,数据从字节的高位(MSB)
开始发送,所以我们用移位操作来接收和发送数据.SDA的状态改变只能在SCL为低时进行
这一点要留心。
/***********************************************/
发送一个字节到I2c总线 要发送的字节:uchar ch
/***********************************************/
void I2cSend(uchar ch)
{
uchar i;
for(i=0;i<8;i++)
{SCL=0;
SDA=(ch&0x80)?1:0;
SCL=1;
ch=ch<<1;
}
SCL=0;
}
/***********************************************/
从I2c总线接收一个字节 返回收到的字节
/***********************************************/
uchar I2cReceive(void)
{
uchar i, ch;
ch=0;
for(i=0;i<7;i++)
{SCL=1;
ch=ch|SDA;
ch=ch<<1;
SCL=0;
}
SCL=1;
ch=ch|SDA;
SCL=0;
return ch;
}
有了上面的几个函数我们就可以写出随机读写一个字节flash的函数了.在随机读写前
都要进行一次虚拟写操作来设定将要读写的flash地址,这个地址可不要与器件地址搞混
了,器件地址用来区分不同的芯片,这里的地址是字节在flash中的存储位置. 也许你已经
把datasheet看得很明白了,我就不多嘴了,下面就是这两个函数:
/***********************************************/
从地址add读取一个字节 返回:读取的字节
/***********************************************/
uchar I2cRdByte(uint add)
{
uchar ch;
I2cStart();
ch=I2cDevAdd&0xfe; /*虚拟写操作设定当前操作地址*/
I2cSend(ch);
I2cSlvAck();
ch=add/256; /*送出地址高8位 */
I2cSend(ch);
I2cSlvAck();
ch=add&0xff; /*送出地址低8位 */
I2cSend(ch);
I2cSlvAck();
ch=I2cDevAdd|0x01; /*送出读命令 */
I2cStart();
I2cSend(ch);
I2cSlvAck();
ch=I2cReceive(); /*接收一个字符 */
I2cStop();
return ch;
}
/***********************************************/
把字节wbyte写入flash 地址 add
/***********************************************/
void I2cWrByte(uchar wbyte,uint add)
{
uchar ch;
I2cStart();
ch=I2cDevAdd&0xfe; /*虚拟写操作设定当前操作地址*/
I2cSend(ch);
I2cSlvAck();
ch=add/256; /*送出地址高8位 */
I2cSend(ch);
I2cSlvAck();
ch=add&0xff; /*送出地址低8位 */
I2cSend(ch);
I2cSlvAck();
ch=wbyte;
I2cSend(ch);
I2cSlvAck();
I2cStop();
delay(10); /*写入延时10ms */
}
有了上面的读写一个字节的函数多字节读写不就可以利用用循环调用上面的两个函数
来实现吗?这个嘛,当然可以了.但是你发现没有,多字节读写写的时候每操作一个字节就要
送器件地址(1Byte)操作地址(2Byte),这样一来太不划算了,况且flash也有批量读和页写
的功能,只送一次器件地址和操作地址就行了,不用用每次都送那么多额外的字节,速度
嘛……那就快多了. 批量读数据的时候要求主器件(MCU)每收到一个字节要应答,就是把
SDA拉低,为了满足时序我们再写一个MCU的应答函数.
/***********************************************/
MCU应答从器件
/***********************************************/
void I2cMasAck(void)
{
SDA=0; I2cDelay();
SCL=1; I2cDelay();
SCL=0; I2cDelay();
SDA=1; I2cDelay();
}
/***********************************************/
从flash地址add处读取len个字节到
uchar * buf指向的地址
/***********************************************/
void I2cBatchRd(uchar * buf,uint add,uint len)
{
uint i;
uchar ch;
I2cStart();
ch=I2cDevAdd&0xfe;
I2cSend(ch);
I2cSlvAck();
ch=add/256;
I2cSend(ch);
I2cSlvAck();
ch=add&0xff;
I2cSend(ch);
I2cSlvAck();
ch=I2cDevAdd|0x01;
I2cStart();
I2cSend(ch);
I2cSlvAck();
for(i=0;ilen)
{I2cWrPage(buf,add,len); return;}
else I2cWrPage(buf,add,temp);
finishnum+=temp;
while(1)
{if((len-finishnum)>64)
{I2cWrPage(buf+finishnum,add+finishnum,64);
finishnum+=64;
continue;
}
else
{I2cWrPage(buf+finishnum,add+finishnum,len-finishnum);
break;
}
}
}
有了批量写函数写flash就快得多了,你在11.0592M的晶振上试一试我们的批量写函
数,全部写完32K的数据也只要20秒左右,而在SUPRO L+编程器上写一片24C256差不多要
三分钟,够你打个小盹儿了.串行flash的速度还凑活,赫赫,你说呢?
说到这里我们的I2c.c也写完了,保存文件,关掉记事本.再上网转一转,然后回家
去,不知道妈妈今天又做了什么好吃的.下一回我们来看并行flash的操作,下次见!
taowa 2002.10.14 19:20
关键词: 推荐 flash 文件 系统 EEPROM 读写
共1条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 | |
【分享评测,赢取加热台】使用8051单片机驱动WS2812被打赏40分 |