来到51黑电子也有一段时间了,单片机萌新一个,一直都是看别人的贴子,很感谢论坛里热心指导的大佬们,今天萌新也来贡献一下代码吧,写了一个IIC读写EEPROM的源码,经过编译和烧录,成功在开发板上实现。
一个00~99的计数器,每秒计数一次,具有断电记忆功能(开机后,从关机前的最新数值继续计数),软件模拟IIC协议。
源码以及开发板上的与本源码相关的电路部分如下(第一次发文,不懂别人帖子里的源码框怎么弄,尴尬.gif):
AT89S52
数码管显示
EEPROM模块以及受影响的DS1302模块
单片机源程序如下:
#include<reg52.h>
#include<intrins.h>
bit x=0; //将计时值写入EEPROM的标志位
sbit SCL=P2^1;
sbit SDA=P2^0;
sbit X=P2^4; //引脚P2^4为开发板上DS1302模块的复位引脚
sbit DU=P2^6; //数码管模块段选位
sbit WE=P2^7; //数码管模块位选位
unsigned char num=0;
unsigned char i=0;
unsigned char LEDS[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共阴数码管的段码
void LEDS_IO() //数码管锁存
{
WE=1;
P0=1;
WE=0;
DU=1;
P0=0;
DU=0;
}
void Delay5ms()
{
unsigned char i,j;
i=9;
j=244;
do
{
while(--j);
}
while(--i);
}
void IIC_Delay()
{
_nop_();
_nop_();
}
void IIC_INIT() //IIC初始化
{
X=0; //DS1302模块的复位电平为低电平,令DS1302模块一直处于复位状态,使其I/O端口(P2^0)不输出,避免干扰EEPROM模块的SDA端口(P2^0)
SDA=1;
IIC_Delay();
SCL=1;
IIC_Delay();
}
void IIC_Start() //IIC起始信号
{
SDA=1;
IIC_Delay();
SCL=1;
IIC_Delay();
SDA=0;
IIC_Delay();
}
void IIC_Stop() //IIC停止信号
{
SDA=0;
IIC_Delay();
SCL=1;
IIC_Delay();
SDA=1;
IIC_Delay();
}
void IIC_ACK() //等待应答信号;“应答”信号:SDA=0;“非应答”信号:SDA=1
{
unsigned char i;
SCL=1;
IIC_Delay();
while((SDA==1)&&(i<256)) //若超时,则视为“非应答”
{
i++;
}
SCL=0;
IIC_Delay();
}
void IIC_Write(unsigned char DATA) //IIC发送数据
{
unsigned char i;
unsigned char temp;
temp=DATA;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=0;
IIC_Delay();
SDA=CY; //IIC数据的发送从高位开始,需要使用左移指令,而C语言的左移和右移指令,CY参与其中(CY并不是只有在进位和借位中用到),左移出来的一位赋给CY
IIC_Delay();
SCL=1;
IIC_Delay();
}
SCL=0; //将SCL置低电平,准备接收应答信号
IIC_Delay();
SDA=1; //释放SDA,准备接收从器件反馈的应答信号
IIC_Delay();
}
unsigned char IIC_Read() //IIC接收数据
{
unsigned char i;
unsigned char DATA;
SCL=0;
IIC_Delay();
SDA=1;
IIC_Delay();
for(i=0;i<8;i++)
{
SCL=1;
IIC_Delay();
DATA=(DATA<<1)|SDA;
SCL=0;
IIC_Delay();
}
return DATA;
}
void EEPROM_Write(unsigned char ADDRESS,unsigned char DATA) //写入EEPROM
{
IIC_Start();
IIC_Write(0xa0); //发送IIC从器件(EEPROM)地址,并选择“写”操作
IIC_ACK();
IIC_Write(ADDRESS); //发送将要写入的EEPROM的存储地址
IIC_ACK();
IIC_Write(DATA); //发送写入EEPROM的数据
IIC_ACK();
IIC_Stop();
}
unsigned char EEPROM_Read(unsigned char ADDRESS) //读取EEPROM
{
unsigned char DATA;
IIC_Start();
IIC_Write(0xa0);
IIC_ACK();
IIC_Write(ADDRESS);
IIC_ACK();
IIC_Start();
IIC_Write(0xa1); //发送IIC从器件(EEPROM)地址,并选择“读”操作
IIC_ACK();
DATA=IIC_Read();
IIC_Stop();
return DATA;
}
void LEDS_OUTPUT(unsigned char m,unsigned char n) //数码管显示
{
DU=0;
P0=LEDS[m];
DU=1;
DU=0;
WE=0;
P0=0x3e;
WE=1;
WE=0;
Delay5ms();
DU=0;
P0=LEDS[n];
DU=1;
DU=0;
WE=0;
P0=0x3d;
WE=1;
WE=0;
Delay5ms();
}
void main()
{
IIC_INIT();
LEDS_IO();
num=EEPROM_Read(0x00);
TMOD=0x01;
TH0=0x4c00;
TL0=0x4c00;
TR0=1;
ET0=1;
EA=1;
while(1)
{
LEDS_OUTPUT(num/10,num%10);
if(x==1)
{
x=0;
EEPROM_Write(0x00,num);
}
}
}
void T() interrupt 1 //每0.05秒中断一次
{
TH0=0x4c00;
TL0=0x4c00;
i++;
if(i==20) //中断20次,即1秒
{
i=0;
num++;
x=1;
if(num==100)
{
num=0;
}
}
}
|