项目资源:
https://download.csdn.net/download/YLG_lin/86541001
在LCD1602液晶屏上显示一个无符号整型数字,按下K1按键数字减一,按下K2数字加一,按下K3数字向AT24C02写入该数据,断电重启后按下K4可以从AT24C02中读取该数据。
AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
存储介质:E2PROM
通讯接口:I2C总线
容量:256字节
- sbit I2C_SCL=P2^1;
- sbit I2C_SDA=P2^0;
起始条件:SCL高电平期间,SDA从高电平切换到低电平
空闲状态下 SDA与SCL默认置高电平;值得注意的是在应答之后SDA有可能为高电平也有可能为低电平(复合格式如下图),所以开始时要置高电平;
- void I2C_Start()
- {
- I2C_SDA=1;
- I2C_SCL=1;
- I2C_SDA=0;
- I2C_SCL=0;
- }
终止条件:SCL高电平期间,SDA从低电平切换到高电平
- void I2C_Stop()
- {
- I2C_SDA=0;
- I2C_SCL=1;
- I2C_SDA=1;
- }
SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
SCL置高后立马置低,不用加延迟,从机是能在高电平期间读到数据的;如果换到更快的单片机的话就要考虑它能承受的最快时间了,具体参考芯片手册;
- void I2C_SendByte(unsigned char Byte)
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- I2C_SDA=Byte&(0x80>>i);
- I2C_SCL=1;
- I2C_SCL=0;
- }
- }
SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
- unsigned char I2C_ReceiveByte(void)
- {
- unsigned char i,Byte=0x00;
- I2C_SDA=1;
- for(i=0;i<8;i++)
- {
- I2C_SCL=1;
- if(I2C_SDA){Byte|=(0x80>>i);}
- I2C_SCL=0;
- }
- return Byte;
- }
发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
- void I2C_SendAck(unsigned char AckBit)
- {
- I2C_SDA=AckBit;
- I2C_SCL=1;
- I2C_SCL=0;
- }
接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
- unsigned char I2C_ReceiveAck(void)
- {
- unsigned char AckBit;
- I2C_SDA=1;
- I2C_SCL=1;
- AckBit=I2C_SDA;
- I2C_SCL=0;
- return AckBit;
- }
AT24C02的固定地址为1010,可配置地址本开发板上为000
所以SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1
字节写:在WORD ADDRESS处写入数据DATA
- void AT24C02_WriteByte(unsigned char WordAddress,Data)
- {
- I2C_Start();
- I2C_SendByte(AT24C02_ADDRESS);
- I2C_ReceiveAck();
- I2C_SendByte(WordAddress);
- I2C_ReceiveAck();
- I2C_SendByte(Data);
- I2C_ReceiveAck();
- I2C_Stop();
- }
随机读:读出在WORD ADDRESS处的数据DATA
- unsigned char AT24C02_ReadByte(unsigned char WordAddress)
- {
- unsigned char Data;
- I2C_Start();
- I2C_SendByte(AT24C02_ADDRESS);
- I2C_ReceiveAck();
- I2C_SendByte(WordAddress);
- I2C_ReceiveAck();
- I2C_Start();
- I2C_SendByte(AT24C02_ADDRESS|0x01);
- I2C_ReceiveAck();
- Data=I2C_ReceiveByte();
- I2C_SendAck(1);
- I2C_Stop();
- return Data;
- }
读取数据的时候不用Delay(5);写的时候要加延时函数,写的时候需改变AT24C02的物理特性,让它永久保存数据,所以需要的时间长一点;具体时间可以查用户手册;ROM比RAM慢一些,就与ROM有个写入时间有关;keynum==3 中num是16位数据,在地址0写入num低8位,在地址1写入高八位;
- void main()
- {
- LCD_Init();
- LCD_ShowNum(1,1,Num,5);
- while(1)
- {
- KeyNum=Key();
- if(KeyNum==1) //K1按键,Num自增
- {
- Num++;
- LCD_ShowNum(1,1,Num,5);
- }
- if(KeyNum==2) //K2按键,Num自减
- {
- Num--;
- LCD_ShowNum(1,1,Num,5);
- }
- if(KeyNum==3) //K3按键,向AT24C02写入数据
- {
- AT24C02_WriteByte(0,Num%256);
- Delay(5); //延迟5ms,查芯片手册可知
- AT24C02_WriteByte(1,Num/256);
- Delay(5);
- LCD_ShowString(2,1,"Write OK");
- Delay(1000);
- LCD_ShowString(2,1," ");
- }
- if(KeyNum==4) //K4按键,从AT24C02读取数据
- {
- Num=AT24C02_ReadByte(0);
- Num|=AT24C02_ReadByte(1)<<8;
- LCD_ShowNum(1,1,Num,5);
- LCD_ShowString(2,1,"Read OK ");
- Delay(1000);
- LCD_ShowString(2,1," ");
- }
- }
- }