使用普中科技51單片機進行(I^2)C總線操作

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章