• <li id="00i08"><input id="00i08"></input></li>
  • <sup id="00i08"><tbody id="00i08"></tbody></sup>
    <abbr id="00i08"></abbr>
  • 新聞中心

    EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > CH451驅(qū)動的數(shù)碼管+按鍵+電子表+溫度程序

    CH451驅(qū)動的數(shù)碼管+按鍵+電子表+溫度程序

    作者: 時間:2012-08-15 來源:網(wǎng)絡(luò) 收藏
    //這是一個芯片驅(qū)動的++ds1302+ds18b20溫度的c語言程序
    //已經(jīng)在51單片機開發(fā)板上測試通過,帶有溫度報警,有詳細(xì)的注釋.
    //程序的完整版本下載地址:http://www.51hei.com/f/ch451.rar
    //本程序版權(quán)所無您可以隨意修改.
    #include reg51.h>
    #include math.h>
    #include intrins.h>
    /*************************************************************
    _crol_ 字符循環(huán)左移
    _cror_ 字符循環(huán)右移
    _irol_ 整數(shù)循環(huán)左移
    _iror_ 整數(shù)循環(huán)右移
    _lrol_ 長整數(shù)循環(huán)左移
    _lror_ 長整數(shù)循環(huán)右移
    _nop_ 空操作8051 NOP 指令
    *************************************************************/
    #define uchar unsigned char
    #define uint unsigned int
    /******************************DS1302宏定義******************/
    #define WRITE_SECOND 0x80
    #define WRITE_MINUTE 0x82
    #define WRITE_HOUR 0x84
    #define READ_SECOND 0x81
    #define READ_MINUTE 0x83
    #define READ_HOUR 0x85
    #define WRITE_PROTECT 0x8E
    /***********************宏定義************************/
    #define _RESET 0x0201 //復(fù)位
    #define CH451_LEFTMOV 0x0300 //設(shè)置移動方式-作移
    #define CH451_LEFTCYC 0x0301 //設(shè)置移動方式-左循
    #define CH451_RIGHTMOV 0x0302 //設(shè)置移動方式-右移
    #define CH451_RIGHTCYC 0x0303 //設(shè)置移動方式-右循
    #define CH451_SYSOFF 0x0400 //關(guān)顯示、鍵盤、看門狗
    #define CH451_SYSON1 0x0401 //開顯示
    #define CH451_SYSON2 0x0403 //開顯示、鍵盤
    #define CH451_SYSON3 0x0407 //開顯示、鍵盤、看門狗功能
    #define CH451_DSP 0x0500 //設(shè)置默認(rèn)顯示方式
    #define CH451_BCD 0x0580 //設(shè)置BCD譯碼方式
    #define CH451_TWINKLE 0x0600 //設(shè)置閃爍控制——正常顯示
    #define CH451_DIG0 0x0800 //位0顯示
    #define CH451_DIG1 0x0900 //位1顯示
    #define CH451_DIG2 0x0a00 //數(shù)碼管位2顯示
    #define CH451_DIG3 0x0b00 //數(shù)碼管位3顯示
    #define CH451_DIG4 0x0c00 //數(shù)碼管位4顯示
    #define CH451_DIG5 0x0d00 //數(shù)碼管位5顯示
    #define CH451_DIG6 0x0e00 //數(shù)碼管位6顯示
    #define CH451_DIG7 0x0f00 //數(shù)碼管位7顯示
    /*************************************************************/
    sbit ACC_7=ACC^7; //位尋址寄存器定義
    sbit SCLK=P2^1; //ds1302管腳定義
    sbit IO=P2^0;
    sbit RST=P1^7;

    sbit DQ=P1^6; //ds18b20定義
    sbit P26=P2^6;

    sbit ch451_dclk=P3^4; //串行數(shù)據(jù)時鐘上升延激活
    sbit ch451_din=P3^3; // 串行數(shù)據(jù)輸出,接CH451的數(shù)據(jù)輸人
    sbit ch451_load=P2^3; //串行命令加載,上升延激活
    sbit ch451_dout=P2^2; //鍵值數(shù)據(jù)輸入,接ch451數(shù)據(jù)輸出

    int temp;
    int tt; //真實溫度變量
    uchar ch451_key=0; // 存放鍵盤中斷中讀取的鍵值
    uint display[8]={0x0a00,0x0900,0x0b00,0x0800,
    0x0c00,0x0d00,0x0e00,0x0f00};
    uchar BCD[10]={0xbe,0x24,0xea,0xe6, //0,1,2,3,
    0x74,0xd6,0xde,0xa4, //4,5,6,7,
    0xfe,0xf6 //8,9
    };
    /*************精確延時函數(shù)*****************/
    void delay(uint i)
    {
    while(--i);
    }


    /************************蜂鳴器程序********/
    void speaker(void)
    {
    uchar i,j;
    for(j=0;j250;j++)
    for(i=0;i250;i++)
    {
    P26=~P26;
    for(i=0;i250;i++);
    }
    P26=1; //防止結(jié)束時候是低電平
    }
    /**********************4*******************/
    /*****************DS18B20******************/

    void Init_Ds18b20(void) //DS18B20初始化

    {
    DQ=0; //單片機拉低總線
    delay(500); //精確延時,維持至少480us
    DQ=1; //釋放總線,即拉高了總線
    delay(200); //此處延時有足夠,確保能讓DS18B20發(fā)出存在脈沖。
    }

    /*****************************************************************************************/
    uchar Read_One_Byte() //讀取一個字節(jié)的數(shù)據(jù)
    //讀數(shù)據(jù)時,數(shù)據(jù)以字節(jié)的最低有效位先從總線移出
    {
    uchar i=0;
    uchar dat=0;
    for(i=8;i>0;i--)
    {
    DQ=0; //將總線拉低,要在1us之后釋放總線
    //單片機要在此下降沿后的15us內(nèi)讀數(shù)據(jù)才會有效。
    _nop_();
    _nop_(); //至少維持了1us,表示讀時序開始
    dat>>=1; //讓從總線上讀到的位數(shù)據(jù),依次從高位移動到低位。
    DQ=1; //釋放總線,此后DS18B20會控制總線,把數(shù)據(jù)傳輸?shù)娇偩€上
    delay(1); //延時7us,此處參照推薦的讀時序圖,盡量把控制器采樣時間放到讀時序后的15us內(nèi)的最后部分
    if(DQ) //控制器進(jìn)行采樣
    {
    dat|=0x80; //若總線為1,即DQ為1,那就把dat的最高位置1;若為0,則不進(jìn)行處理,保持為0
    }
    delay(60); //此延時不能少,確保讀時序的長度60us--很重要
    }
    return (dat);
    }
    /********************************************************/
    void Write_One_Byte(uchar dat)
    {
    uchar i=0;
    for(i=8;i>0;i--)
    {
    DQ=0; //拉低總線
    _nop_();
    nop_(); //至少維持了1us,表示寫時序(包括寫0時序或?qū)?時序)開始
    DQ=dat0x01; //從字節(jié)的最低位開始傳輸
    //指令dat的最低位賦予給總線,必須在拉低總線后的15us內(nèi),
    //因為15us后DS18B20會對總線采樣。

    delay(60); //必須讓寫時序持續(xù)至少60us ----很重要
    DQ=1; //寫完后,必須釋放總線,
    /* _nop_(); */
    dat>>=1;
    //因為15us后DS18B20會對總線采樣。
    delay(1);

    }
    }

    /*************************************************************************/
    uint Get_Tmp() //獲取溫度
    {
    float t;
    uchar a=11,b=0;
    Init_Ds18b20(); //初始化
    Write_One_Byte(0xcc); //忽略ROM指令
    Write_One_Byte(0x44); //溫度轉(zhuǎn)換指令
    Init_Ds18b20(); //初始化
    Write_One_Byte(0xcc); //忽略ROM指令
    Write_One_Byte(0xbe); //讀讀RAM的存儲器指令
    a=Read_One_Byte(); //讀取到的第一個字節(jié)為溫度LSB
    b=Read_One_Byte(); //讀取到的第二個字節(jié)為溫度MSB
    temp=b; //先把高八位有效數(shù)據(jù)賦于temp
    temp=8; //把以上8位數(shù)據(jù)從temp低八位移到高八位
    temp=temp|a; //兩字節(jié)合成一個整型變量
    t=temp*0.0625; //得到真實十進(jìn)制溫度值
    //因為DS18B20可以精確到0.0625度
    //所以讀回數(shù)據(jù)的最低位代表的是0.0625度
    temp=t*10+0.5; //此處放大十倍
    //這樣做的目的將小數(shù)點后第一位也轉(zhuǎn)換為可顯示數(shù)字
    //同時進(jìn)行一個四舍五入操作。
    return(temp);
    }
    /************************************************************************
    以上實現(xiàn)溫度傳感器的讀取數(shù)據(jù)
    *************************************************************************/
    /******************************DS1302*************************************/



    //地址、數(shù)據(jù)發(fā)送子程序
    void Write1302(uchar addr,uchar dat )
    {
    uchar i,t;
    RST=0; //RST 引腳為低,數(shù)據(jù)傳送終止
    SCLK=0; //清零時鐘總線
    RST=1; //RST 引腳為高,邏輯控制有效
    //發(fā)送地址
    for(i=8;i>0;i--) //循環(huán)8次移位
    {
    SCLK=0;
    t=addr;
    IO=(bit)(t0x01); //每次傳輸?shù)妥止?jié)
    addr>>=1; //右移一位
    SCLK=1;
    }
    //發(fā)送數(shù)據(jù)
    for(i=8;i>0;i--)
    {
    SCLK=0;
    t=dat;
    IO=(bit)(t0x01);
    dat>>=1;
    SCLK=1;
    }
    RST=0;
    }

    //數(shù)據(jù)讀取子程序
    uchar Read1302(uchar addr )
    {
    uchar i,t,dat1,dat2;
    RST=0;
    SCLK=0;
    RST=1;
    //發(fā)送地址
    for(i=8;i>0;i--) //循環(huán)8次移位
    {
    SCLK=0;
    t=addr;
    IO=(bit)(t0x01); //每次傳輸?shù)妥止?jié)
    addr>>=1; //右移一位
    SCLK=1;
    }
    //讀取數(shù)據(jù)
    for(i=8;i>0;i--)
    {
    ACC_7=IO;
    SCLK=1;
    ACC>>=1; //右移
    SCLK=0;
    }
    RST=0;
    dat1=ACC;
    dat2=dat1/16; //數(shù)據(jù)進(jìn)制轉(zhuǎn)換
    dat1=dat1%16; //十六進(jìn)制轉(zhuǎn)十進(jìn)制
    dat1=dat1+dat2*10;
    return (dat1);
    }

    //初始化DS1302
    void Initial(void)
    {

    Write1302 (WRITE_PROTECT,0x00); //禁止寫保護(hù)
    Write1302 (WRITE_SECOND,0x00); //秒位初始化,開始計時
    Write1302 (WRITE_MINUTE,0x03); //分鐘初始化
    Write1302 (WRITE_HOUR,0x23); // 小時初始化——24小時模式
    //Write1302 (WRITE_PROTECT,0x80); // 允許寫保護(hù)
    // 調(diào)試證明必須禁止寫保護(hù)
    //不然修改不了初始值
    }
    /*********************************CH451**********************/
    //********************************************
    //設(shè)置定時器中斷__定時掃描鍵盤
    void ch451_init()
    {
    ch451_din=0; //先低后高,選擇4線輸入
    ch451_din=1;
    TMOD=0x10; //設(shè)置定時器T1工作在16位計時狀態(tài)
    EA=1; //開中斷總開關(guān)
    ET1=1; //允許中斷
    TR1=1; //開中斷
    PT1=0; //設(shè)置低優(yōu)先級
    TL1=1; //裝載計數(shù)初值
    TH1=0; //此計數(shù)初值用來調(diào)試
    }
    //*****************************************************
    //定義一無符號整型變量存儲12字節(jié)的命令字。
    void ch451_write(uint command)
    {
    uchar i;
    TR1=0; //禁止T1中斷
    ch451_load=0; //命令開始
    for(i=0;i12;i++){ //送入12位數(shù)據(jù),低位在前
    ch451_din=command1;
    ch451_dclk=0;
    command>>=1;
    ch451_dclk=1; //上升沿有效
    }
    ch451_load=1; //上升沿加載數(shù)據(jù)
    TR1=1; // 開啟T1中斷
    }

    //*************************************************
    //*************************************************

    //中斷子程序 使用定時器中斷T1,寄存器組1
    void ch451_inter() interrupt 3 using 1
    {

    uchar i; //定義循環(huán)變量

    uchar command,keycode; //定義控制字寄存器,和中間變量定時器

    command=0x07; //讀取鍵值命令的高4位0111B
    ch451_load=0; //命令開始
    for(i=0;i4;i++){
    ch451_din=command1; //低位在前,高位在后
    ch451_dclk=0;
    command>>=1; //右移一位
    ch451_dclk=1; //產(chǎn)生時鐘上升沿鎖通知CH451輸入位數(shù)據(jù)
    }
    ch451_load=1; //產(chǎn)生加載上升沿通知CH451處理命令數(shù)據(jù)
    keycode=0; //清除keycode
    for(i=0;i7;i++){
    keycode=1; //數(shù)據(jù)作移一位,高位在前,低位在后
    keycode|=ch451_dout; //從高到低讀入451的數(shù)據(jù)
    ch451_dclk=0; //產(chǎn)生時鐘下升沿通知CH451輸出下一位
    ch451_dclk=1;
    }
    ch451_key=keycode; //保存上次的鍵值

    TL1=1; //重新裝載計數(shù)初值
    TH1=0; //此計數(shù)初值用來調(diào)試
    }

    //***********************************************


    void main()
    {
    int HIGH=270; //定義溫度上限變量
    uchar A0,A1,A2,A3; //記錄溫度各位數(shù)的變量
    uchar b,c; //定義存放DS1302中數(shù)據(jù)的變量
    P26=1; //關(guān)閉蜂鳴器
    Initial(); //初始化DS1302
    //初始化以后此語句必須關(guān)掉 防止每次上電初始化DS1302
    //關(guān)掉此語句編譯時會為此產(chǎn)生一個警告
    /*改動*/
    ch451_init(); // 設(shè)置定時器中斷__定時掃描鍵盤
    ch451_write(CH451_RESET); //CH451復(fù)位
    ch451_write(CH451_SYSON2); //開顯示、鍵盤
    ch451_write(CH451_DSP); //設(shè)置BCD不譯碼方式 由于板畫錯了 此設(shè)置很重要
    ch451_write(CH451_TWINKLE); //設(shè)置閃爍控制——正常顯示


    while(1)
    {
    tt=Get_Tmp(); //讀出當(dāng)前溫度
    A3=tt/1000; //千位
    A2=(tt%1000)/100; //百位
    A1=(tt%100)/10; //十位——這么處理的目的是顯示小數(shù)點,因為A1實際是溫度的個位
    A0=tt%10; //個位
    ch451_write(display[0]+BCD[A0]); //顯示溫度小數(shù)位
    ch451_write(display[1]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數(shù)點
    ch451_write(display[2]+BCD[A2]); //顯示溫度十位
    ch451_write(display[3]+BCD[A3]); //顯示溫度百位

    if(Get_Tmp()>HIGH) //如果溫度大于上限度
    {
    delay(10); //延時是為了防止脈沖不穩(wěn)定干擾
    if(Get_Tmp()>HIGH) //可以消除蜂鳴器非正常響
    /*合理的改動*/
    {
    Write1302(0xc0,Read1302(READ_MINUTE)/10*16+Read1302(READ_MINUTE)%10); //寫入當(dāng)前記錄的數(shù)據(jù)所對應(yīng)的時間——分
    Write1302(0xc2,Read1302(READ_HOUR)/10*16+Read1302(READ_HOUR)%10); //寫入當(dāng)前記錄的數(shù)據(jù)所對應(yīng)的時間——小時
    /**寫入的應(yīng)該是16進(jìn)制而不是十進(jìn)制**/
    speaker(); //如果溫度大于 HIGH度,蜂鳴器報警
    }
    }
    if(Get_Tmp()0) //如果溫度小于0度
    {
    delay(10); //延時是為了防止脈沖不穩(wěn)定干擾
    if(Get_Tmp()0) //可以消除溫度非正常顯示為負(fù)
    /*合理的改動*/
    {
    tt=abs(tt);
    ch451_write(display[0]+BCD[A0]); //顯示溫度小數(shù)位
    ch451_write(display[1]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數(shù)點
    ch451_write(display[2]+BCD[A2]); //顯示溫度十位
    ch451_write(display[3]+BCD[A2]); //顯示溫度百位
    ch451_write(display[4]+0x40); //顯示負(fù)號
    }
    }
    //對各個進(jìn)行定義
    switch(ch451_key)
    {
    case 0x40: {

    b=Read1302(0xc1); //讀出數(shù)據(jù)所對應(yīng)的時間——分
    c=Read1302(0xc3); //讀出數(shù)據(jù)所對應(yīng)的時間——小時 */
    ch451_write(display[4]+BCD[b%10]); //顯示分鐘個位
    ch451_write(display[5]+BCD[b/10]); //顯示分鐘十位
    ch451_write(display[6]+BCD[c%10]); //顯示小時個位
    ch451_write(display[7]+BCD[c/10]); //顯示小時十位
    } break; //按下第1個鍵時調(diào)出DS1302中產(chǎn)生溫度報警的時間
    case 0x43: { ch451_write(display[4]+0); //關(guān)顯示分鐘個位
    ch451_write(display[5]+0); //關(guān)顯示分鐘十位
    ch451_write(display[6]+0); //關(guān)顯示小時個位
    ch451_write(display[7]+0); //關(guān)顯示小時十位;
    } break; //按下第2個鍵關(guān)時間顯示
    case 0x41: speaker(); break; //按下第3個鍵時蜂鳴器響
    case 0x42: {
    A3=HIGH/1000; //千位
    A2=(HIGH%1000)/100; //百位
    A1=(HIGH%100)/10; //十位——這么處理的目的是顯示小數(shù)點,因為A1實際是溫度的個位
    A0=HIGH%10; //個位
    ch451_write(display[4]+BCD[A0]); //顯示溫度小數(shù)位
    ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數(shù)點
    ch451_write(display[6]+BCD[A2]); //顯示溫度十位
    ch451_write(display[7]+BCD[A3]); //顯示溫度十位
    } break; //按下第4個鍵顯示上限溫度
    case 0x48: {
    delay(65000); //使增大溫度上限值得過程變慢
    HIGH=HIGH+1;
    A3=HIGH/1000; //千位
    A2=(HIGH%1000)/100; //百位
    A1=(HIGH%100)/10; //十位——這么處理的目的是顯示小數(shù)點,因為A1實際是溫度的個位
    A0=HIGH%10; //個位
    ch451_write(display[4]+BCD[A0]); //顯示溫度小數(shù)位
    ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數(shù)點
    ch451_write(display[6]+BCD[A2]); //顯示溫度十位
    ch451_write(display[7]+BCD[A3]); //顯示溫度百位
    } ; break; //按下第5個鍵增加溫度上限值
    case 0x4b: {
    delay(65000); //使按鍵減小溫度上限值得過程變慢
    HIGH=HIGH-1;
    A3=HIGH/1000; //千位
    A2=(HIGH%1000)/100; //百位
    A1=(HIGH%100)/10; //十位——這么處理的目的是顯示小數(shù)點,因為A1實際是溫度的個位
    A0=HIGH%10; //個位
    ch451_write(display[4]+BCD[A0]); //顯示溫度小數(shù)位
    ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數(shù)點
    ch451_write(display[6]+BCD[A2]); //顯示溫度十位
    ch451_write(display[7]+BCD[A3]); //顯示溫度十位

    } ; break; //按下第6個鍵減小溫度上限值
    case 0x49: {
    while(ch451_key!=0x43)
    {
    ch451_write(display[0]+BCD[Read1302(READ_SECOND)%10]); //顯示分鐘的個位
    ch451_write(display[1]+BCD[Read1302(READ_SECOND)/10]); //顯示秒的十位
    ch451_write(display[2]+0x40); //顯示負(fù)號
    ch451_write(display[3]+BCD[Read1302(READ_MINUTE)%10]); //顯示分鐘的個位
    ch451_write(display[4]+BCD[Read1302(READ_MINUTE)/10]); //顯示分鐘的十位
    ch451_write(display[5]+0x40); //顯示負(fù)號
    ch451_write(display[6]+BCD[Read1302(READ_HOUR)%10]); //顯示小時的個位
    ch451_write(display[7]+BCD[Read1302(READ_HOUR)/10]); //顯示分鐘的十位
    }
    } ; break; //按下第7個鍵動態(tài)顯示當(dāng)前的時間——
    case 0x4a: ; break; //按下第8個鍵無效
    }

    /****************************************************************/

    }
    }
    蜂鳴器相關(guān)文章:蜂鳴器原理
    溫濕度控制器相關(guān)文章:溫濕度控制器原理


    關(guān)鍵詞: CH451 數(shù)碼管 按鍵 電子表

    評論


    相關(guān)推薦

    技術(shù)專區(qū)

    關(guān)閉
    主站蜘蛛池模板: 四会市| 应城市| 怀宁县| 闸北区| 阳江市| 邹平县| 全椒县| 廉江市| 芦山县| 伊宁市| 海南省| 宁武县| 高邮市| 牡丹江市| 沾化县| 乌鲁木齐县| 大埔县| 乌兰浩特市| 泗洪县| 榆林市| 通江县| 称多县| 收藏| 左云县| 十堰市| 乌海市| 涪陵区| 洪雅县| 紫金县| 土默特右旗| 公主岭市| 凌海市| 司法| 杨浦区| 绥江县| 镇巴县| 盐城市| 台江县| 景洪市| 闻喜县| 齐河县|