历史上的今天
今天是:2024年08月27日(星期二)
2021年08月27日 | 51单片机-IIC&EEPROM合成文件
2021-08-27 来源:eefocus
1.浅释E2Write函数
宋老师的例程lesson14_3和lesson14_4里的“E2Write(unsigned char *buf, unsigned char addr, unsigned char len)”书写内容是不一样的,lesson14_4的E2Write函数比lesson14_3的E2Write函数运行高效,lesson14_3的E2Write函数是每写入一个字节就要经历起始信号,停止信号,写入下一个字节又要把这些步骤经历一遍。而lesson14_4的E2Write函数支持EEPROM页写入(参考《手把手教你学51单片机》文档14.3.3节),所以在建立起文件时我们选用lesson14_4的E2Write函数。
大家新建两个文件“iic.c”和“iic.h”,我们把IIC的相关函数和EEPROM的相关函数都合成在“iic.c”这个单独文件里。
2.iic.c的代码
#include #include #include #define I2CDelay() {_nop_();_nop_();_nop_();_nop_();} /* 产生总线起始信号 */ void I2CStart() { I2C_SDA = 1; //首先确保SDA、SCL都是高电平 I2C_SCL = 1; I2CDelay(); I2C_SDA = 0; //先拉低SDA I2CDelay(); I2C_SCL = 0; //再拉低SCL } /* 产生总线停止信号 */ void I2CStop() { I2C_SCL = 0; //首先确保SDA、SCL都是低电平 I2C_SDA = 0; I2CDelay(); I2C_SCL = 1; //先拉高SCL I2CDelay(); I2C_SDA = 1; //再拉高SDA I2CDelay(); } /* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */ unsigned char I2CWrite(unsigned char dat) { unsigned char ack; //用于暂存应答位的值 unsigned char mask; //用于探测字节内某一位值的掩码变量 for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行 { if ((mask&dat) == 0) //该位的值输出到SDA上 I2C_SDA = 0; else I2C_SDA = 1; I2CDelay(); I2C_SCL = 1; //拉高SCL I2CDelay(); I2C_SCL = 0; //再拉低SCL,完成一个位周期 } I2C_SDA = 1; //8位数据发送完后,主机释放SDA,以检测从机应答 I2CDelay(); I2C_SCL = 1; //拉高SCL ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值 I2CDelay(); I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线 return (!ack); //应答值取反以符合通常的逻辑: //0=不存在或忙或写入失败,1=存在且空闲或写入成功 } /* I2C总线读操作,并发送应答或者非应答信号,返回值-读到的字节 */ unsigned char I2CReadNAK_OR_ACK(unsigned char nak_or_ack) { unsigned char mask; unsigned char dat; I2C_SDA = 1; //首先确保主机释放SDA for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行 { I2CDelay(); I2C_SCL = 1; //拉高SCL if(I2C_SDA == 0) //读取SDA的值 dat &= ~mask; //为0时,dat中对应位清零 else dat |= mask; //为1时,dat中对应位置1 I2CDelay(); I2C_SCL = 0; //再拉低SCL,以使从机发送出下一位 } I2C_SDA = nak_or_ack; //8位数据发送完后,传入的参数NAK_OR_ACK决定是否应答,为1不应答,为0应答 I2CDelay(); I2C_SCL = 1; //拉高SCL I2CDelay(); I2C_SCL = 0; //再拉低SCL完成非应答位,并保持住总线 return dat; } /* E2读取函数,buf-数据接收指针,addr-E2中的起始地址,len-读取长度 */ void E2Read(unsigned char *buf, unsigned char addr, unsigned char len) { do { //用寻址操作查询当前是否可进行读写操作 I2CStart(); if (I2CWrite(0x50<<1)) //应答则跳出循环,非应答则进行下一次查询 { break; } I2CStop(); } while(1); I2CWrite(addr); //写入起始地址 I2CStart(); //发送重复启动信号 I2CWrite((0x50<<1)|0x01); //寻址器件,后续为读操作 while (len > 1) //连续读取len-1个字节 { *buf++ = I2CReadNAK_OR_ACK(0); //最后字节之前为读取操作+应答 len--; } *buf = I2CReadNAK_OR_ACK(1); //最后一个字节为读取操作+非应答 I2CStop(); } /* E2写入函数,buf-源数据指针,addr-E2中的起始地址,len-写入长度 */ void E2Write(unsigned char *buf, unsigned char addr, unsigned char len) { while (len > 0) { //等待上次写入操作完成 do { //用寻址操作查询当前是否可进行读写操作 I2CStart(); if (I2CWrite(0x50<<1)) //应答则跳出循环,非应答则进行下一次查询 { break; } I2CStop(); } while(1); //按页写模式连续写入字节 I2CWrite(addr); //写入起始地址 while (len > 0) { I2CWrite(*buf++); //写入一个字节数据 len--; //待写入长度计数递减 addr++; //E2地址递增 if ((addr&0x07) == 0) //检查地址是否到达页边界,24C02每页8字节, { //所以检测低3位是否为零即可 break; //到达页边界时,跳出循环,结束本次写操作 } } I2CStop(); } } 3.iic.h的代码 #ifndef __IIC_H__ #define __IIC_H__ sbit I2C_SCL = P3^7; sbit I2C_SDA = P3^6; void I2CStart();//产生总线起始信号 void I2CStop(); //产生总线停止信号 unsigned char I2CWrite(unsigned char dat);//I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 unsigned char I2CReadNAK_OR_ACK(unsigned char nak_or_ack);//I2C总线读操作,并发送应答或者非应答信号,返回值-读到的字节 void E2Read(unsigned char *buf, unsigned char addr, unsigned char len); //E2读取函数,buf-数据接收指针,addr-E2中的起始地址,len-读取长度 void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);//E2写入函数,buf-源数据指针,addr-E2中的起始地址,len-写入长度 #endif 4.部分代码的修改 “unsigned char I2CReadACK()”和“unsigned char I2CReadNAK()”这里我们合成了一个函数为 “unsigned char I2CReadNAK_OR_ACK(unsigned char nak_or_ack)”,利用参数的传递决定是否产生应答。 那么在main.c中,几乎也是只需要出现EEPROM的写函数“E2Write()”和读函数“E2Read()”而已了。 记得把“iic”添加到工程文件中 5.main.c测试代码 #include #include #include #include void main() { unsigned char buf[]={"We can learn SCM well!"};//我们可以学好单片机 unsigned char str[sizeof(buf)]; //数组长度与buf的一样 InitLcd1602(); //初始化液晶 E2Write(buf,0x8E,sizeof(buf));//把buf数组里面的内容在EEPROM中从地址0x8E开始写,直到把数组里的内容全部写完进去,在EEPROM中保存起来 delay_ms(1000); //过1秒之后再读出里面的内容显示在液晶屏上 E2Read(str,0x8E,sizeof(buf)); //用另一个数组存取从EEPROM中读出的内容 LcdShowStr_len(0, 0,str, 16); LcdShowStr(0, 1, str+16+1); while(1); } 
上一篇:51单片机-EEPROM简单使用
下一篇:51单片机-红外遥控
史海拾趣
|
本帖最后由 jameswangsynnex 于 2015-3-3 20:01 编辑 可不可以提供一些可以查芯片资料的网站。中文或英文都可以,方便就行!谢谢啦! … 查看全部问答> |
|
Q: 公司的芯片上有一个16Bits的DAC,由于以前一直做Digital IC测试,对这个器件的测试原理没有概念,只知道INL、DNL、THD、SNR等参数的定义,不知道在实际的测试中怎样进行测试?那位高手做过此方面的测试,能否告诉那些参数是必测的,怎样测试? ...… 查看全部问答> |
|
下面几个问题请高手帮忙解答: 1 设计信号处理器TMS320LF2407的最小系统原理框图,要求完成包括时钟,复位,微处理器监控和CPU的工作方式设置。 2 已知TMS320LF2407为核心的电能质量分析仪的外围设备空间分配如下,采用可编程逻辑器件GAL或CPLD完 ...… 查看全部问答> |
|
(一)功能:通过MSP430读取DS1302,获得时间信息,并将其通过液晶显示器进行显示。 (二)硬件信息: (1)主芯片:MSP430G2231--------------------->LAUCHPAD(正好用一下LAUCHPAD,没高兴用G2452,两个原因:1:我的IAR刚好只支持G2231不支持G ...… 查看全部问答> |
|
这是咱们EEworld主页上的的一篇报道,https://www.eeworld.com.cn/mcu/2012/0413/article_8446.html 比较了金刚狼和XLP的功耗,随着Cortex M0的推出,可以说在低功耗产品方面的竞争已经极其激烈。早在09年的时候,MicroChip和TI就有过一次“功耗之 ...… 查看全部问答> |




