/*C51单片机学习打卡*/
/*观看郭天祥老师教学视频,使用普中科技51单片机开发板进行学习(I^2)C总线操作*/
/*功能:在开发版上进行999秒计时,在单片机掉电情况下可以记录最后一秒的数据*/
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit SDK=P2^0;
sbit SCL=P2^1;
void Delayms(uint xms); //延时xms
void delay(); //延时几微秒
void Display(uchar x,uchar y); //数码管显示函数,y为显示的数码管位数,x为显示的内容
void Initialize(); //初始化函数
void Start(); //起始函数
void Response(); //应答函数
void Stop(); //停止函数,表示全部数据已经发送完成
void Write_bite(uchar date); //写一个字节的数据(一个字节八个位)
uchar Read_bite(); //读取一个字节的数据(一个字节八个位)
void Write_address(uchar address,uchar date); //写数据
uchar Read_address(uchar date); //读数据
uchar num,hundred,ten,digit,write;
uint temp;
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};//显示0~F的值
void main()
{
Initialize();
// Write_address(2,5);
// Delayms(10);
temp=Read_address(2);
if(temp>1)
temp=0;
while(1)
{
hundred=temp/100;
ten=temp%100/10;
digit=temp%10;
Display(hundred,4);
Display(ten,3);
Display(digit,2);
if(write==1)
{
write=0;
Write_address(2,temp);
}
}
}
void T0_Timer() interrupt 1 //每50ms溢出一次
{
TH0=(65536-46080)/256;
TL0=(65536-46080)%256;
num++;
if(num==20)
{
num=0;
temp++;
write=1;
if(temp>999)
temp=0;
}
}
void Display(uchar x,uchar y)
{
switch(y)
{
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位
case(4):
LSA=0;LSB=0;LSC=1; break;//显示第4位
case(5):
LSA=1;LSB=0;LSC=1; break;//显示第5位
case(6):
LSA=0;LSB=1;LSC=1; break;//显示第6位
case(7):
LSA=1;LSB=1;LSC=1; break;//显示第7位
}
P0=table[x];
Delayms(10);
P0=0x00;
}
void delay() //延时几微秒
{
;
;
}
void Delayms(uint xms) //延时xms
{
uint i;
uchar j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void Initialize() //初始化函数
{
SCL=1; //初始化时已经默认SCL与SDK为高电平,在之后的程序编写时,理应注意这点
delay(); //我觉得这个初始化完全没有意义,所需要的SCL和SDK的定义都会在其他子函数中,得到定义
SDK=1; //最多只是为了确定一个初态
delay();
TMOD=0x01; //定时器0设定
TH0=(65536-46080)/256;
TL0=(65536-46080)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
ET1=1; //启动定时器0
TR0=1;
temp=0;
num=0;
}
void Start() //开始信号
{
SDK=1; //在SCL为高电平时,SDK由高电平变为低电平,即为开始信号
delay();
SCL=1; //增强程序的移植性,虽然初始化时已经将SDK和SCL拉为高电平
delay();
SDK=0;
delay();
}
void Responses() //应答信号
{ //前提是SDK此时已经为高电平
uchar i;
SCL=1; //应答信号:在SCL时钟线是高电平的前提下,SDK数据线由高电平转化为低电平
delay(); //若已经完成数据写入操作,SDK理应被拉成高电平
while((SDK==1)&&(i<250)) //SDK被拉为0,【或SDK没有被拉为0,而程序在此停留到i==250时表示应答(无应答表示默认收到数据)】
i++; //注:按照本次设计,方括号内情况不应出现,但为了严谨性,故加以编写
SCL=0; //将SCL拉为低电平,使下一步子函数操作更清晰
delay();
}
void Stop() //停止信号,表示全部数据已经发送完成
{
SDK=0; //当SCL为高电平时,SDK由低电平变为高电平,表示全部数据已经发送完毕,即停止信号
delay();
SCL=1;
delay();
SDK=1;
delay();
}
void Write_byte(uchar date) //写一个字节的数据(一个字节八个位)
{
uchar temp,i;
temp=date;
for(i=8;i>0;i--)
{ //时钟信号为高点平时,SDK数据线上的信号不允许改变
temp=temp<<1; //而此时SDK是高电平还是低电平,并不影响
SCL=0; //将时钟信号改为低电平,此时SDK数据线可以开始写入数据
delay();
SDK=CY; //SDK按位写入数据
delay();
SCL=1; //SCL时钟信号拉为高电平,关闭数据写入
delay();
}
SCL=0; //注意:不明白为何要拉为低电平,应答信号时又拉成高电平,似是前后矛盾,可能是写入完成的标志
delay();
SDK=1; //恢复初始化状态,为其他子函数的编写提供便利
delay();
}
uchar Read_byte() //读取一个字节的数据(一个字节八个位)
{
uchar k,i;
SCL=0;
delay();
// SDK=1;
// delay();
for(i=8;i>0;i--)
{
SCL=1; //当SCL置高时,SDK不可改变
delay();
k=(k<<1)|SDK; // 此时用“移位”和“按位或”的方法,将SDK上的八位数据一位位的复制给变量k
SCL=0;
delay();
}
return k;
}
void Write_address(uchar address,uchar date) //由时序图得
{
Start();
Write_byte(0xa0);
Responses();
Write_byte(address);
Responses();
Write_byte(date);
Responses();
Stop();
}
uchar Read_address(uchar address) //由时序图得
{
uchar date;
Start();
Write_byte(0xa0);
Responses();
Write_byte(address);
Responses();
Start();
Write_byte(0xa1);
Responses();
date=Read_byte();
Stop();
return date;
}