寻求以通俗的言语让小白能够更容易上手学单片机,在此同时稳固常识(很多图片来自江科大和普中,作者也是学这个来的,仅仅通过自己的言语想把它复述出来)。
本节将以AT24C02实现数据存储事例来驱动对AT24C02,IIC等的学习。
事例:接LCD1602显示屏、设置独立按键,当按下第一个按键为+1,第2个按键为-1,数据范围是0~65535(0-1->65535,65535+1->0);第三个按键按下会保存数据;第四个按键按下会跳到已保存的数据(不管值是多少,断过电否)。
重点:存储数据,取出数据
用到的模块有LCD1602,Delay(延时函数),Key(独立按键),IIC(数据传输)
ATC24C02的硬件原理
芯片介绍
如图,这儿的重点是–掉电不丢掉(永久保存)、通讯接口I2C总线,也就是咱们接下来会使用这两个点去实现数据存储。
存储器
由上面咱们可知道,AT24C02是一个存储器,那存储器又有什么常识点(重点)吗? 这儿简略给了个分类图(如下),不具体打开。后边有时间我会再具体讲一下。 能够知道,咱们用的AT24C02属于非易失性存储器(ROM)-即能够实现掉电不丢掉数据(能够实现永久保存数据,掉电后也能够有所设置的数据)。
引脚图(这个才是对于驱动程序来说,实际一点的东西)
- SDA、SCL为IIC接口,数据的传输(从单片机主机到存储器从机)必须用到这个。
- A0,A1,A2为三位的AT24C02存储器地址,能够将数据放在其中的某个地址,然后访问改地址。
- WP:AT24C02有一个写保护引脚,供给硬件数据保护。当连接到地(GND)时,写保护引脚允许正常读/写操作。当引脚连接到Vcc时,就会启用Write protection特性,不允许读写。
IIC的地址
如图,在IIC的模块中,咱们要连接AT24C02,要写入其地址,写为0xA0,读为0xA1.
怎么使得数据传输
全体思路(手写,字丑勿喷~)
-
为什么读数据有两个start?这是规则了的,恪守就行,做项目的时分查文档跟着来就能够。
-
为什么发送了两个地址?第一个地址为SLAVE ADDRESS(器件(芯片)地址,一般固定),第二个地址为 WORD ADDRESS(从机地址,一般可写什么0,1,2不过注意,每个地址只能存放256个字节,即比方65535,就得用/256部分存一个从机地址,%256存一个地址) 写很容易了解,但是读很容易混淆 照着来就行了
代码解读
到了严重又激动的时刻了,3、2、1上代码!
主函数
#include <REGX52.H>
#include "LCD1602.h"//引进显示屏,独立按键,AT24C02,延时函数
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"
unsigned char KeyNum;
unsigned int Num;
void main()
{
LCD_Init();
LCD_ShowNum(1,1,Num,5);
while(1)
{
KeyNum=Key();
if(KeyNum==1) //当等于1时,就++
{
Num++;
LCD_ShowNum(1,1,Num,5);
}
if(KeyNum==2) //当等于2时,就--
{
Num--;
LCD_ShowNum(1,1,Num,5);
}
if(KeyNum==3) //当等于3时,就保存
{
AT24C02_WriteByte(0,Num%256);//因为一个从机地址只能存8位,所以必须将十进制数分/256和%256部分
Delay(5);//最好写完推迟函数,保证数据能录入
AT24C02_WriteByte(1,Num/256);
Delay(5);
LCD_ShowString(2,1,"Write OK");
Delay(1000);
LCD_ShowString(2,1," ");
}
if(KeyNum==4) //读取存储的数据
{
Num=AT24C02_ReadByte(0);
Num|=AT24C02_ReadByte(1)<<8;//要将前面的部分左移并入NUM-
LCD_ShowNum(1,1,Num,5);//此时16位二进制数会转为十进制数
LCD_ShowString(2,1,"Read OK ");
Delay(1000);
LCD_ShowString(2,1," ");
}
}
}
LCD1602 显示屏
这儿是封装好的,今后能够用,不过由于篇幅,这儿不展示,能够去看我写的LCD1602文章,里边有封装
Key 独立按键
#include <REGX52.H>
#include "Delay.h"
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
IIC
#include <REGX52.H>
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
void I2C_Start(void)//开端
{
I2C_SDA=1;
I2C_SCL=1;//一定要在SCL置1时才时SDA下降沿
I2C_SDA=0;
I2C_SCL=0;
}
void I2C_Stop(void)
{
I2C_SDA=0;
I2C_SCL=1;
I2C_SDA=1;
}
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
I2C_SDA=Byte&(0x80>>i);//要先置SDA,再给上升沿,再下降
I2C_SCL=1;
I2C_SCL=0;
}
}
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);}//在SCL置1 时获取,然后置0
I2C_SCL=0;
}
return Byte;
}
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA=AckBit;
I2C_SCL=1;
I2C_SCL=0;
}
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA=1;
I2C_SCL=1;
AckBit=I2C_SDA;
I2C_SCL=0;
return AckBit;
}
AT24C02
#include <REGX52.H>
#include "I2C.h"
#define AT24C02_ADDRESS 0xA0
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();
}
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;
}
这就是数据存储的代码,每个模块要有一个XXX.h文件作为导入 欢迎交流!!