新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > CH451驅動的數碼管+按鍵+電子表+溫度程序

        CH451驅動的數碼管+按鍵+電子表+溫度程序

        作者: 時間:2012-08-15 來源:網絡 收藏
        //這是一個芯片驅動的++ds1302+ds18b20溫度的c語言程序
        //已經在51單片機開發板上測試通過,帶有溫度報警,有詳細的注釋.
        //程序的完整版本下載地址:http://www.51hei.com/f/ch451.rar
        //本程序版權所無您可以隨意修改.
        #include reg51.h>
        #include math.h>
        #include intrins.h>
        /*************************************************************
        _crol_ 字符循環左移
        _cror_ 字符循環右移
        _irol_ 整數循環左移
        _iror_ 整數循環右移
        _lrol_ 長整數循環左移
        _lror_ 長整數循環右移
        _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 //復位
        #define CH451_LEFTMOV 0x0300 //設置移動方式-作移
        #define CH451_LEFTCYC 0x0301 //設置移動方式-左循
        #define CH451_RIGHTMOV 0x0302 //設置移動方式-右移
        #define CH451_RIGHTCYC 0x0303 //設置移動方式-右循
        #define CH451_SYSOFF 0x0400 //關顯示、鍵盤、看門狗
        #define CH451_SYSON1 0x0401 //開顯示
        #define CH451_SYSON2 0x0403 //開顯示、鍵盤
        #define CH451_SYSON3 0x0407 //開顯示、鍵盤、看門狗功能
        #define CH451_DSP 0x0500 //設置默認顯示方式
        #define CH451_BCD 0x0580 //設置BCD譯碼方式
        #define CH451_TWINKLE 0x0600 //設置閃爍控制——正常顯示
        #define CH451_DIG0 0x0800 //位0顯示
        #define CH451_DIG1 0x0900 //位1顯示
        #define CH451_DIG2 0x0a00 //數碼管位2顯示
        #define CH451_DIG3 0x0b00 //數碼管位3顯示
        #define CH451_DIG4 0x0c00 //數碼管位4顯示
        #define CH451_DIG5 0x0d00 //數碼管位5顯示
        #define CH451_DIG6 0x0e00 //數碼管位6顯示
        #define CH451_DIG7 0x0f00 //數碼管位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; //串行數據時鐘上升延激活
        sbit ch451_din=P3^3; // 串行數據輸出,接CH451的數據輸人
        sbit ch451_load=P2^3; //串行命令加載,上升延激活
        sbit ch451_dout=P2^2; //鍵值數據輸入,接ch451數據輸出

        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
        };
        /*************精確延時函數*****************/
        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; //防止結束時候是低電平
        }
        /**********************4*******************/
        /*****************DS18B20******************/

        void Init_Ds18b20(void) //DS18B20初始化

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

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

        delay(60); //必須讓寫時序持續至少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); //溫度轉換指令
        Init_Ds18b20(); //初始化
        Write_One_Byte(0xcc); //忽略ROM指令
        Write_One_Byte(0xbe); //讀讀RAM的存儲器指令
        a=Read_One_Byte(); //讀取到的第一個字節為溫度LSB
        b=Read_One_Byte(); //讀取到的第二個字節為溫度MSB
        temp=b; //先把高八位有效數據賦于temp
        temp=8; //把以上8位數據從temp低八位移到高八位
        temp=temp|a; //兩字節合成一個整型變量
        t=temp*0.0625; //得到真實十進制溫度值
        //因為DS18B20可以精確到0.0625度
        //所以讀回數據的最低位代表的是0.0625度
        temp=t*10+0.5; //此處放大十倍
        //這樣做的目的將小數點后第一位也轉換為可顯示數字
        //同時進行一個四舍五入操作。
        return(temp);
        }
        /************************************************************************
        以上實現溫度傳感器的讀取數據
        *************************************************************************/
        /******************************DS1302*************************************/



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

        //數據讀取子程序
        uchar Read1302(uchar addr )
        {
        uchar i,t,dat1,dat2;
        RST=0;
        SCLK=0;
        RST=1;
        //發送地址
        for(i=8;i>0;i--) //循環8次移位
        {
        SCLK=0;
        t=addr;
        IO=(bit)(t0x01); //每次傳輸低字節
        addr>>=1; //右移一位
        SCLK=1;
        }
        //讀取數據
        for(i=8;i>0;i--)
        {
        ACC_7=IO;
        SCLK=1;
        ACC>>=1; //右移
        SCLK=0;
        }
        RST=0;
        dat1=ACC;
        dat2=dat1/16; //數據進制轉換
        dat1=dat1%16; //十六進制轉十進制
        dat1=dat1+dat2*10;
        return (dat1);
        }

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

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

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

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

        uchar i; //定義循環變量

        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; //產生時鐘上升沿鎖通知CH451輸入位數據
        }
        ch451_load=1; //產生加載上升沿通知CH451處理命令數據
        keycode=0; //清除keycode
        for(i=0;i7;i++){
        keycode=1; //數據作移一位,高位在前,低位在后
        keycode|=ch451_dout; //從高到低讀入451的數據
        ch451_dclk=0; //產生時鐘下升沿通知CH451輸出下一位
        ch451_dclk=1;
        }
        ch451_key=keycode; //保存上次的鍵值

        TL1=1; //重新裝載計數初值
        TH1=0; //此計數初值用來調試
        }

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


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


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

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

        b=Read1302(0xc1); //讀出數據所對應的時間——分
        c=Read1302(0xc3); //讀出數據所對應的時間——小時 */
        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個鍵時調出DS1302中產生溫度報警的時間
        case 0x43: { ch451_write(display[4]+0); //關顯示分鐘個位
        ch451_write(display[5]+0); //關顯示分鐘十位
        ch451_write(display[6]+0); //關顯示小時個位
        ch451_write(display[7]+0); //關顯示小時十位;
        } break; //按下第2個鍵關時間顯示
        case 0x41: speaker(); break; //按下第3個鍵時蜂鳴器響
        case 0x42: {
        A3=HIGH/1000; //千位
        A2=(HIGH%1000)/100; //百位
        A1=(HIGH%100)/10; //十位——這么處理的目的是顯示小數點,因為A1實際是溫度的個位
        A0=HIGH%10; //個位
        ch451_write(display[4]+BCD[A0]); //顯示溫度小數位
        ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數點
        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; //十位——這么處理的目的是顯示小數點,因為A1實際是溫度的個位
        A0=HIGH%10; //個位
        ch451_write(display[4]+BCD[A0]); //顯示溫度小數位
        ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數點
        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; //十位——這么處理的目的是顯示小數點,因為A1實際是溫度的個位
        A0=HIGH%10; //個位
        ch451_write(display[4]+BCD[A0]); //顯示溫度小數位
        ch451_write(display[5]+BCD[A1]+1); //顯示溫度個位 此處加一為了加入小數點
        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); //顯示負號
        ch451_write(display[3]+BCD[Read1302(READ_MINUTE)%10]); //顯示分鐘的個位
        ch451_write(display[4]+BCD[Read1302(READ_MINUTE)/10]); //顯示分鐘的十位
        ch451_write(display[5]+0x40); //顯示負號
        ch451_write(display[6]+BCD[Read1302(READ_HOUR)%10]); //顯示小時的個位
        ch451_write(display[7]+BCD[Read1302(READ_HOUR)/10]); //顯示分鐘的十位
        }
        } ; break; //按下第7個鍵動態顯示當前的時間——
        case 0x4a: ; break; //按下第8個鍵無效
        }

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

        }
        }
        蜂鳴器相關文章:蜂鳴器原理
        溫濕度控制器相關文章:溫濕度控制器原理


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 项城市| 当阳市| 淮安市| 花垣县| 平乐县| 沙洋县| 浏阳市| 五寨县| 奎屯市| 张家港市| 加查县| 遵化市| 通道| 门头沟区| 隆尧县| 景宁| 丹阳市| 灯塔市| 潞城市| 科技| 白河县| 日土县| 内江市| 万载县| 武强县| 略阳县| 香格里拉县| 盐源县| 临澧县| 静乐县| 开封县| 永昌县| 肥东县| 阿瓦提县| 衡东县| 芒康县| 突泉县| 溧水县| 桂林市| 巴青县| 玛纳斯县|