虽然博客可能会迟到,但永远不会缺席。本次学习如何使用IIC协议操作AT24C02。
IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或集电极开路(OC)输出。
AT24C02是一个2K位串行CMOS E2PROM, 内部含有256个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24C02有一个8字节页写缓冲器。该器件通过IIC总线接口进行操作,有一个专门的写保护功能。
AT24C02支持I2C,总线数据传送协议I2C,总线协议规定任何将数据传送到总线的器件作为发送器。任何从总线接收数据的器件为接收器。数据传送是由产生串行时钟和所有起始停止信号的主器件控制的。主器件和从器件都可以作为发送器或接收器,但由主器件控制传送数据(发送或接收)的模式,由于A0、A1和A2可以组成000~111八种情况,即通过器件地址输入端A0、A1和A2可以实现将最多8个AT24C02器件连接到总线上,通过进行不同的配置进行选择器件。
AT24C02 器件地址
前4位默认为1010 本例中A2,A1,A0接低电平,以及最有一位读写控制位,即器件地址为0xa0 |读写控制位
本例实验 数据初始化为0,按下按键K1,AT24C02存入数据至地址1,按下按键K2,AT24C02读取地址1中的数据并显示,按下按键K3,数据加一,加至大于255时,数据清零,按键K4也为数据清零键。显示模块使用74LS138 驱动4位数码管显示。
//IIC 头文件
#ifndef _IIC_H_
#define _IIC_H_
#include "Stc15.h"
#include "intrins.h"
#define u16 unsigned int
#define u8 unsigned char
#define Main_Fosc 11059200
extern void Delay_5us();
extern void IIC_Start(void);
extern void IIC_Stop(void);
extern unsigned char IIC_SendOneByte(u8 dat);
extern unsigned char IIC_ReceiveOneByte(void);
extern void AT24C02_WriteOneData(u8 addr,u8 dat);
extern unsigned char AT24C02_ReadOneData(u8 addr);
#endif
#include "IIC.h"
sbit SDA = P2^0; //IIC EEPROM 数据线
sbit SCL = P2^1; //IIC EEPROM 时钟线
#define AT24C02_WriteAddr 0xa0 //器件地址+写
#define AT24C02_ReadAddr 0xa1 //器件地址+读
/* **************************************
* 函数名称:Delay_5us()
* 入口参数:无
* 出口参数:无
* 函数功能: 5us延时函数
*************************************** */
void Delay_5us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 11;
while (--i);
}
/* **************************************
* 函数名称:IIC_Start(void)
* 入口参数:无
* 出口参数:无
* 函数功能: IIC起始信号
*************************************** */
void IIC_Start(void)
{
SDA = 1;
Delay_5us();
SCL = 1;
Delay_5us();
SDA = 0 ;
Delay_5us();
SCL = 0;
Delay_5us();
}
/* **************************************
* 函数名称:IIC_Stop(void)
* 入口参数:无
* 出口参数:无
* 函数功能: IIC终止信号
*************************************** */
void IIC_Stop(void)
{
SDA = 0;
Delay_5us();
SCL = 1;
Delay_5us();
SDA = 1;
}
/* **********************************************
* 函数名称:unsigned char IIC_SendOneByte(u8 dat)
* 入口参数:u8 dat
* 出口参数:无
* 函数功能: IIC发送一个字节及其应答信号
********************************************** */
unsigned char IIC_SendOneByte(u8 dat)
{
unsigned char i=0;
unsigned char uiVal; //最大255,一个机器周期为1us,最大延时255us。
for(i=0;i<8;i++) //数据移位写入
{
SDA=dat>>7;
dat=dat<<1;
Delay_5us();
SCL=1;
Delay_5us();
SCL=0;
Delay_5us();
}
SDA=1;
Delay_5us();
SCL=1;
while(SDA) //等待应答
{
uiVal++;
if(uiVal>200) //如果超过200us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
Delay_5us();
return 0;
}
}
SCL=0;
Delay_5us();
return 1;
}
/* **********************************************
* 函数名称:unsigned char IIC_ReceiveOneByte(void)
* 入口参数:无
* 出口参数:数据 RecByte
* 函数功能: IIC接收字节数据
********************************************** */
unsigned char IIC_ReceiveOneByte(void)
{
u8 RecByte;
u8 i;
SDA = 1;
for(i=0;i<8;i++)
{
SCL = 0;
Delay_5us();
SCL = 1;
Delay_5us();
RecByte<<=1;
if(SDA)
{
RecByte |= 0x01;
}
}
SCL = 0;
return (RecByte);
}
/* **********************************************
* 函数名称:AT24C02_WriteOneData(u8 addr,u8 dat)
* 入口参数:u8 addr u8 dat
* 出口参数: 无
* 函数功能: AT24C02字节写入数据
********************************************** */
void AT24C02_WriteOneData(u8 addr,u8 dat)
{
IIC_Start();
IIC_SendOneByte(AT24C02_WriteAddr); //器件地址+写
IIC_SendOneByte(addr);
IIC_SendOneByte(dat);
IIC_Stop();
}
/* **********************************************
* 函数名称:AT24C02_ReadOneData(u8 addr)
* 入口参数:u8 addr
* 出口参数: 数据 temp
* 函数功能: AT24C02随机读取数据
********************************************** */
unsigned char AT24C02_ReadOneData(u8 addr)
{
u8 temp;
IIC_Start();
IIC_SendOneByte(AT24C02_WriteAddr); //器件地址+写
IIC_SendOneByte(addr);
IIC_Start();
IIC_SendOneByte(AT24C02_ReadAddr); //器件地址+读
temp = IIC_ReceiveOneByte();
IIC_Stop();
return (temp);
}
#include "IIC.h"
sbit LSA = P2^2; //74LS138控制端口
sbit LSB = P2^3;
sbit LSC = P2^4;
sbit K1 = P3^1;
sbit K2 = P3^0;
sbit K3 = P3^2;
sbit K4 = P3^3; //定义按键端口
char WriteDat=0;
u8 Display[4];
u8 code SmgDuan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
/* **********************************************
* 函数名称:Delay_MS(u16 ms)
* 入口参数:u16 ms
* 出口参数:无
* 函数功能: 不精确延时
********************************************** */
void Delay_MS(u16 ms)
{
unsigned int i;
do{
i = Main_Fosc/13000;
while(--i);
}while(--ms);
}
/*******************************************************************************
* 函数名 :KeyScan(void)
* 函数功能 :按键扫描函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Key_Scan(void)
{
if(K1==0)
{
Delay_MS(10); //延时消抖
if(K1==0)
{
AT24C02_WriteOneData(1,WriteDat); //在地址1内写入数据WriteDat
}
while(!K1);
}
if(K2==0)
{
Delay_MS(10); //延时消抖
if(K2==0)
{
WriteDat=AT24C02_ReadOneData(1); //读取EEPROM地址1内的数据保存在WriteDat中
}
while(!K2);
}
if(K3==0)
{
Delay_MS(10); //延时消抖
if(K3==0)
{
WriteDat++; //数据加1
if(WriteDat>255)WriteDat=0;
}
while(!K3);
}
if(K4==0)
{
Delay_MS(10); //延时消抖
if(K4==0)
{
WriteDat=0; //数据清零
}
while(!K4);
}
}
/*******************************************************************************
* 函数名 :DataProcess()
* 函数功能 :数据处理函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void DataProcess()
{
Display[0]=SmgDuan[WriteDat/1000];//千位
Display[1]=SmgDuan[WriteDat%1000/100];//百位
Display[2]=SmgDuan[WriteDat%1000%100/10];//个位
Display[3]=SmgDuan[WriteDat%1000%100%10];
}
/*******************************************************************************
* 函数名 :SmgDisplay()
* 函数功能 :数码管显示函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void SmgDisplay()
{
u8 i;
for(i=0;i<4;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0; break;//显示第3位
}
P0=Display[3-i];//发送数据
Delay_MS(2); //间隔一段时间扫描,让数据送入
P0=0x00;//消隐
}
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
while(1)
{
Key_Scan(); //按键扫描函数
DataProcess(); //数据处理函数
SmgDisplay(); //数码管显示函数
}
}