/*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;
}