新聞中心

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

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

        作者: 時(shí)間:2012-08-15 來源:網(wǎng)絡(luò) 收藏
        //這是一個(gè)芯片驅(qū)動(dòng)的++ds1302+ds18b20溫度的c語言程序
        //已經(jīng)在51單片機(jī)開發(fā)板上測試通過,帶有溫度報(bào)警,有詳細(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è)置移動(dòng)方式-作移
        #define CH451_LEFTCYC 0x0301 //設(shè)置移動(dòng)方式-左循
        #define CH451_RIGHTMOV 0x0302 //設(shè)置移動(dòng)方式-右移
        #define CH451_RIGHTCYC 0x0303 //設(shè)置移動(dòng)方式-右循
        #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ù)時(shí)鐘上升延激活
        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; //真實(shí)溫度變量
        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í)函數(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é)束時(shí)候是低電平
        }
        /**********************4*******************/
        /*****************DS18B20******************/

        void Init_Ds18b20(void) //DS18B20初始化

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

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

        delay(60); //必須讓寫時(shí)序持續(xù)至少60us ----很重要
        DQ=1; //寫完后,必須釋放總線,
        /* _nop_(); */
        dat>>=1;
        //因?yàn)?5us后DS18B20會(huì)對總線采樣。
        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的存儲(chǔ)器指令
        a=Read_One_Byte(); //讀取到的第一個(gè)字節(jié)為溫度LSB
        b=Read_One_Byte(); //讀取到的第二個(gè)字節(jié)為溫度MSB
        temp=b; //先把高八位有效數(shù)據(jù)賦于temp
        temp=8; //把以上8位數(shù)據(jù)從temp低八位移到高八位
        temp=temp|a; //兩字節(jié)合成一個(gè)整型變量
        t=temp*0.0625; //得到真實(shí)十進(jìn)制溫度值
        //因?yàn)镈S18B20可以精確到0.0625度
        //所以讀回?cái)?shù)據(jù)的最低位代表的是0.0625度
        temp=t*10+0.5; //此處放大十倍
        //這樣做的目的將小數(shù)點(diǎn)后第一位也轉(zhuǎn)換為可顯示數(shù)字
        //同時(shí)進(jìn)行一個(gè)四舍五入操作。
        return(temp);
        }
        /************************************************************************
        以上實(shí)現(xiàn)溫度傳感器的讀取數(shù)據(jù)
        *************************************************************************/
        /******************************DS1302*************************************/



        //地址、數(shù)據(jù)發(fā)送子程序
        void Write1302(uchar addr,uchar dat )
        {
        uchar i,t;
        RST=0; //RST 引腳為低,數(shù)據(jù)傳送終止
        SCLK=0; //清零時(shí)鐘總線
        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); //秒位初始化,開始計(jì)時(shí)
        Write1302 (WRITE_MINUTE,0x03); //分鐘初始化
        Write1302 (WRITE_HOUR,0x23); // 小時(shí)初始化——24小時(shí)模式
        //Write1302 (WRITE_PROTECT,0x80); // 允許寫保護(hù)
        // 調(diào)試證明必須禁止寫保護(hù)
        //不然修改不了初始值
        }
        /*********************************CH451**********************/
        //********************************************
        //設(shè)置定時(shí)器中斷__定時(shí)掃描鍵盤
        void ch451_init()
        {
        ch451_din=0; //先低后高,選擇4線輸入
        ch451_din=1;
        TMOD=0x10; //設(shè)置定時(shí)器T1工作在16位計(jì)時(shí)狀態(tài)
        EA=1; //開中斷總開關(guān)
        ET1=1; //允許中斷
        TR1=1; //開中斷
        PT1=0; //設(shè)置低優(yōu)先級
        TL1=1; //裝載計(jì)數(shù)初值
        TH1=0; //此計(jì)數(shù)初值用來調(diào)試
        }
        //*****************************************************
        //定義一無符號(hào)整型變量存儲(chǔ)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中斷
        }

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

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

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

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

        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)生時(shí)鐘上升沿鎖通知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)生時(shí)鐘下升沿通知CH451輸出下一位
        ch451_dclk=1;
        }
        ch451_key=keycode; //保存上次的鍵值

        TL1=1; //重新裝載計(jì)數(shù)初值
        TH1=0; //此計(jì)數(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)掉此語句編譯時(shí)會(huì)為此產(chǎn)生一個(gè)警告
        /*改動(dòng)*/
        ch451_init(); // 設(shè)置定時(shí)器中斷__定時(shí)掃描鍵盤
        ch451_write(CH451_RESET); //CH451復(fù)位
        ch451_write(CH451_SYSON2); //開顯示、鍵盤
        ch451_write(CH451_DSP); //設(shè)置BCD不譯碼方式 由于板畫錯(cuò)了 此設(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ù)點(diǎn),因?yàn)锳1實(shí)際是溫度的個(gè)位
        A0=tt%10; //個(gè)位
        ch451_write(display[0]+BCD[A0]); //顯示溫度小數(shù)位
        ch451_write(display[1]+BCD[A1]+1); //顯示溫度個(gè)位 此處加一為了加入小數(shù)點(diǎn)
        ch451_write(display[2]+BCD[A2]); //顯示溫度十位
        ch451_write(display[3]+BCD[A3]); //顯示溫度百位

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

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

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

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

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


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

        評論


        相關(guān)推薦

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

        關(guān)閉
        主站蜘蛛池模板: 开原市| 七台河市| 蛟河市| 介休市| 海城市| 海宁市| 临江市| 阆中市| 温宿县| 资溪县| 大竹县| 唐河县| 共和县| 栾川县| 华坪县| 马关县| 绿春县| 重庆市| 宜兰市| 司法| 龙山县| 长寿区| 延长县| 西乌珠穆沁旗| 延边| 格尔木市| 万全县| 合阳县| 南城县| 拜泉县| 赤城县| 六盘水市| 潮州市| 和龙市| 云浮市| 沿河| 青浦区| 拉孜县| 微博| 永嘉县| 蓬莱市|