久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1910|回復: 0
收起左側

這個程序 仿真 溫度顯示不正確 怎么弄?

[復制鏈接]
ID:248800 發表于 2017-11-14 19:45 | 顯示全部樓層 |閱讀模式
#include < reg52.h >
#include < intrins.h >         //用到nop()時使用
#define uchar unsigned char
#define uint  unsigned int

sbit  K5 = P1^4;                          //調節數位切換鍵
sbit  K6 = P1^5;                          //數值增加鍵
sbit  K7 = P1^6;                          //數值減小鍵
sbit  K8 = P1^7;                          //確認鍵
uchar K5flag = 0;

sbit  LCD_RS = P2^0;          //LCD1602數據/命令選擇端      
sbit  LCD_RW = P2^1;              //LCD1602讀/寫選擇端
sbit  LCD_EN = P2^2;              //LCD1602使能端
sbit  DQ=P3^3;                                  //DS18B20信號端
                                                          
uint year=2015;
uchar month=2;
uchar day=27,daytemp;
uchar weekdayflag=5;

char H=12;
char M=0;
char S=0;

uchar displaybuf[9];
uchar code cdis1[20]= {"0123456789:.C- "};
uchar code cdis2[7][5]=
{"Mon",
"Tue",
"Wed",
"Thu",
"Fir",
"Sat",
"Sun"};
/**********************************************************
5us 延時子程序         ms延時函數
**********************************************************/
void  delayNOP()
{
   _nop_();         //一個機器周期1us延時
   _nop_();
   _nop_();
   _nop_();
   _nop_();
}
void delay(uint ms)
{
   uint t;
   while(ms--)
   {
     for(t = 0; t <100; t++);
   }
}
/**********************************************************
1602液晶操作                                                              
**********************************************************/

//忙碌狀態判斷
bit lcd_busy() //RS/RW/EN=0/1/1為讀狀態
{                          
    bit result;
    LCD_RS = 0;                             //RS為1選擇數據,RS為0選擇命令
    LCD_RW = 1;                             //RW為1選擇讀操作,RW為0選擇寫操作
    LCD_EN = 1;                             //EN等于1可以讀取信息,等于0可以執行命令
    delayNOP();                             //5us延時
    result = (bit)(P0&0x80); //確保STA7為0,說明為“閑”狀態,為1位“忙”操作;(bit)(P0&0x80)為強制類型轉換
    LCD_EN = 0;                                 //讀取數據結束之后,復位執行使能操作
    return(result);
}
//寫命令
void write_control(uchar control)          //RS/RW/EN=0/0/高脈沖  為寫指令狀態
{
    while(lcd_busy());                       
    LCD_RS=0;                              //選擇命令操作                 
        LCD_RW=0;                                               //RW為0時寫數據;
    LCD_EN=0;                                               //1602執行命令
    delayNOP();
        P0=control;                            //發送高四位給1602數據P0口   
    LCD_EN = 1;                                               //EN高脈沖
    delayNOP();
    LCD_EN = 0;                                                           //高脈沖之后恢復EN=0
    delayNOP();
}
//寫地址
void write_address(uchar pos)              // 寫入顯示地址命令
{                          
   pos=(pos|0x80);                         //數據指針=80+地址變量
   write_control(pos);
}
//寫數據
void write_data(uchar temp)                //  RS/RW/EN=1/0/高脈沖  為寫數據狀態
{

   while(lcd_busy());                       
    LCD_RS=1;                             //選擇命令操作                 
        LCD_RW=0;                                              //RW為0時寫數據;
    LCD_EN=0;                                              //1602執行命令
    delayNOP();
        P0=temp;                              //發送數據給1602數據P0口   
    LCD_EN = 1;                                               //EN高脈沖
    delayNOP();
    LCD_EN = 0;                                                           //高脈沖之后恢復EN=0
    delayNOP();
}
//液晶初始化
void lcd_init()                                               //1602液晶初始化函數
{
    delay(5);
        write_control(0x38);                   //16*2顯示,5*7點陣,8位數據
    delay(1);
    write_control(0x38);                                    //重復寫入,確保成功
    delay(1);
           write_control(0x38);                                    //重復寫入,確保成功
    delay(1);
        write_control(0x0f);                   //光標移動
    delay(1);
        write_control(0x04);                                    //光標移動               
    delay(1);
        write_control(0x01);                                    //清除LCD的顯示內容              
    delay(5);                              //延時
}

//萬年歷時間判斷顯示函數

void date_display()
{

while(lcd_busy());
write_address(0x00);
write_data(cdis1[year/1000%10]);  
write_data(cdis1[year/100%10]);
write_data(cdis1[year/10%10]);
write_data(cdis1[year%10]);
write_data(cdis1[13]);
write_data(cdis1[month/10]);
write_data(cdis1[month%10]);
write_data(cdis1[13]);
write_data(cdis1[day/10]);
write_data(cdis1[day%10]);

}
//weekday顯示函數
void weekday_display()
{
int i=3;
while(lcd_busy());
write_address(0x0c);
write_control(0x0c);
for(i=0;i<3;i++)
{
write_data(cdis2[weekdayflag-1][i]);
}


}

//時間程序顯示函數
void TimeDisplay(jj) //時間程序顯示子函數
{
  uchar temp;
  displaybuf[0]=jj%10;
  displaybuf[1]=jj/10;
  displaybuf[3]=M%10;
  displaybuf[4]=M/10;
  displaybuf[6]=H%10;
  displaybuf[7]=H/10;
  while(lcd_busy());

  write_address(0x48);                 //寫入時十位

  temp=displaybuf[7];
  write_data(cdis1[temp]);
       
  temp=displaybuf[6];                //寫入時個位
  write_data(cdis1[temp]);
       
  write_data(cdis1[10]);        //寫入":"

  temp=displaybuf[4];                //寫入分十位
  write_data(cdis1[temp]);

  temp=displaybuf[3];            //寫入分個位
  write_data(cdis1[temp]);

  write_data(cdis1[10]);        //:
       
  temp=displaybuf[1];            //寫入秒十位
  write_data(cdis1[temp]);

  temp=displaybuf[0];                //寫入秒個位
  write_data(cdis1[temp]);  

}
//DS18B20操作函數                                                              

//初始化函數讀取應答信號

unsigned char time;                     //設置全局變量,專門用于嚴格延時
bit Init_DS18B20(void)       
{
        bit flag;                           //儲存DS18B20是否存在的標志,flag=0,表示存在;flag=1,表示不存在
        DQ = 1;                             //先將數據線拉高
        for(time=0;time<2;time++)           //略微延時約6微秒
     ;
        DQ = 0;                             //再將數據線從高拉低,要求保持480~960us
        for(time=0;time<200;time++)         //略微延時約600微秒
     ;                                 
        DQ = 1;                             //釋放數據線(將數據線拉高)
     for(time=0;time<10;time++)
     ;                                  //延時約30us(釋放總線后需等待15~60us讓DS18B20輸出存在脈沖)
        flag=DQ;                            //讓單片機檢測是否輸出了存在脈沖(DQ=0表示存在)      
    for(time=0;time<200;time++)         //延時足夠長時間,等待存在脈沖輸出完畢
      ;
    return (flag);                      //返回檢測成功標志,返回1表示存在,返回0表示不存在
}

//從DS18B20中讀取數據 ,讀取的數據從最低位開始
unsigned char ReadOneChar(void)
{
        unsigned char i=0;       
        unsigned char dat;                  //儲存讀出的一個字節數據
        for (i=0;i<8;i++)
        {
                DQ =1;                          // 先將數據線拉高
                _nop_();                            //等待一個機器周期         
                DQ = 0;                         //單片機從DS18B20讀書據時,將數據線從高拉低即啟動讀時序
                dat>>=1;                            //復合運算符,等于:dat=dat>>1;
                _nop_();                        //等待一個機器周期                  
                DQ = 1;                         //將數據線"人為"拉高,為單片機檢測DS18B20的輸出電平作準備
                for(time=0;time<2;time++)
             ;                          //延時約6us,使主機在15us內采樣
                if(DQ==1)
                dat|=0x80;                      //如果讀到的數據是1,則將1存入dat
            else
            dat|=0x00;                      //如果讀到的數據是0,則將0存入dat
                                                //將單片機檢測到的電平信號DQ存入r[i]       
                for(time=0;time<8;time++)
                              ;                       //延時3us,兩個讀時序之間必須有大于1us的恢復期       
        }                            
         return(dat);                       //返回讀出的十進制數據
}
//向DS18B20中寫入數據
void WriteOneChar(unsigned char dat)
{
        unsigned char i=0;
        for (i=0; i<8; i++)
        {
                DQ =1;                          // 先將數據線拉高
                _nop_();                            //等待一個機器周期         
                DQ=0;                           //將數據線從高拉低時即啟動寫時序      
                DQ=dat&0x01;                    //利用與運算取出要寫的某位二進制數據, 并將其送到數據線上等待DS18B20采樣       
                for(time=0;time<10;time++)       
                     ;                          //延時約30us,DS18B20在拉低后的約15~60us期間從數據線上采樣
                DQ=1;                           //釋放數據線                    
                for(time=0;time<1;time++)
                          ;                         //延時3us,兩個寫時序間至少需要1us的恢復期
                dat>>=1;                        //將dat中的各二進制位數據右移1位
        }
        for(time=0;time<4;time++)
                      ;                     //寫完數據之后稍作延時,給硬件一點反應時間
}
//溫度值計算及顯示函數
void Tdisplay()
{
         uchar TL;                         //儲存暫存器的溫度低位
     uchar TH;                         //儲存暫存器的溫度高位
     uchar TN;                         //儲存溫度的整數部分
     uchar TD;                         //儲存溫度的小數部分
         uchar i,j,k;                                                //計算溫度整數部分的個位,十位,百位

         Init_DS18B20();
         WriteOneChar(0xCC);                // 單線單DS18B20可以跳過讀序號列號的操作,節省時間
     WriteOneChar(0x44);                // 啟動溫度轉換命令
         for(time=0;time<100;time++)
                    ;                            //溫度轉換需要一點時間
         Init_DS18B20();                    //將DS18B20初始化
         WriteOneChar(0xCC);                //跳過讀序號列號的操作
         WriteOneChar(0xBE);                //讀取溫度寄存器,前兩個分別是溫度的低位和高位       
         TL=ReadOneChar();                  //先讀的是溫度值低位
         TH=ReadOneChar();                  //接著讀的是溫度值高位
         TN=TH*16+TL/16;                    //實際溫度值=(TH*256+TL)/16,即:TH*16+TL/16
                                                    //這樣得出的是溫度的整數部分,小數部分被丟棄了
         k=TN/100%10;                        //取溫度值的百位
         j=TN/10%10;                         //取溫度值的十位
         i=TN%10;                            //取溫度值的個位
          
         TD=(TL%16)*10/16;                  //計算溫度的小數部分,將余數乘以10再除以16取整,
                                                    //這樣得到的是溫度小數部分的第一位數字(保留1位小數)
         while(lcd_busy());
         write_address(0x41);                                //寫入液晶開始顯示溫度的位置
   //write_data(cdis1[k]);                                                //寫溫度值的百位
     write_data(cdis1[j]);                                                //寫溫度值的十位
     write_data(cdis1[i]);                            //寫溫度值的個位
         write_data(cdis1[11]);                            //寫小數點
         write_data(cdis1[TD]);                            //寫溫度值的個位
         write_data(0xdf);       
         write_data(cdis1[12]);                            //寫溫度單位
     delay(10);                      
}

//按鍵掃描程序
void key_scan(void)
{
      switch(month)
    {
         case 1:daytemp=31;break;
         case 2:if((year%4==0)&&(year%100!=0)||(year%400==0)) //閏年:年份能被4整除且不能被100整除,或者能被400整除
               {
                daytemp=29;
               }
                        else
                        daytemp=28;break;
         case 3:daytemp=31;break;
         case 4:daytemp=30;break;
         case 5:daytemp=31;break;
         case 6:daytemp=30;break;
         case 7:daytemp=31;break;
         case 8:daytemp=31;break;
         case 9:daytemp=30;break;
         case 10:daytemp=31;break;
         case 11:daytemp=30;break;
         case 12:daytemp=31;break;
         default:break;
    }
           P1=0xf0;                                       //將P1口高4位置高電平“1”
           if((P1&0xf0)!=0xf0)                            //有鍵按下
           {
                    delay(10);                               //延時消抖延時60ms再檢測
                        if((P1&0xf0)!=0xf0)                      //確實有鍵按下
                             {
                                      if(K5==0)                        //如果是K5鍵按下,切換到調節模式,按下一次是,年代數跳動
                                {
                                         K5flag++;
                                         if(K5flag>=7)
                                         K5flag=0;
                                         switch(K5flag)
                                         {
                                          case 1:write_address(0x03);write_control(0x0f);break;  //光標跳動命令于"year"調節模式
                                          case 2:write_address(0x06);write_control(0x0f);break;  //光標跳動命令于"month"調節模式
                                          case 3:write_address(0x09);write_control(0x0f);break;         //光標跳動命令"day"調節模式
                                          case 4:write_address(0x0e);write_control(0x0f);break;         //光標跳動命令"weekday"調節模式
                                          case 5:write_address(0x49);write_control(0x0f);break;         //光標跳動命令"H"調節模式
                                          case 6:write_address(0x4C);write_control(0x0f);break;         //光標跳動命令"M"調節模式
                                          default:break;
                                         }
                                         while(!K5);                      //等待K5釋放                                         
                                        }                                
                                        if(K6==0)                         //如果是k6鍵按下數值增加
                                        {                                         
                                         switch(K5flag)
                                         {
                                         case 1:year++;        break;
                                         case 2:month++;if((month-1)>=12)month=1;break;
                                         case 3:day++;if((day-1)>=daytemp)day=1;break;
                                         case 4:weekdayflag++;if((weekdayflag-1)==7)weekdayflag=1;break;
                                         case 5:H++;if(H>=24)H=0;break;
                                         case 6:M++;if(M>=60)M=0;break;               
                                         default:break;
                                         }
                                         while(!K6);                     //等待K6釋放
                                        }
                                        if(K7==0)                        
                                {                                         
                                         switch(K5flag)
                                         {
                                         case 1:year--;        break;
                                         case 2:month--;if((month+1)==1)month=12;break;
                                         case 3:day--;if((day+1)==1)day=daytemp;break;
                                         case 4:weekdayflag--;if((weekdayflag+1)==7)weekdayflag=1;break;
                                         case 5:H--;if(H<0)H=23;break;
                                         case 6:M--;if(M<0)M=59;break;                                       
                                         default:break;
                                         }
                                         while(!K7);                     //等待K7釋放
                                        }                                
                                    if(K8==0)                        //如果是k8鍵確認鍵按下,光標停止閃爍,結束設置
                                {                                         
                                        write_control(0x0c);
                                        K5flag=0;
                                        }                                            
                 }
           }
}
/*
//串口通信函數
unsigned char tmp;
void send_char(unsigned char txd)   // 傳送一個字符
{
        SBUF = txd;
        while(!TI);                                        // 等特數據傳送
        TI = 0;                                                // 清除數據傳送標志
}
void interrupt1_init()                                //串口初始化程序
{
        TMOD=0x20;                                            // 定時器1工作于8位自動重載模式, 用于產生波特率
        TH1=TL1=0XFD;                                    // 波特率9600,定時器裝初值
        SCON=0X50;                                            // 設定串行口工作方式1 ,REN置1允許數據接收
        PCON=0X00;                                            // 波特率不倍增
        TR1=1;                                                    // 啟動定時器1,不用開定時器中斷
}
main()
{
    interrupt1_init();
        while(1)
        {
                if(RI==1)                                    // 允許接收標志位,RI=1有數據到來,允許接收,接收完一個字節數據后,自動置1
                {
                   RI = 0;                                        //RI置0,暫停接收,等待數據處理
                   tmp = SBUF;                            // 暫存接收到的數據
                   P0 = tmp;                            // 數據傳送到P0口
                   send_char(tmp);                    // 回傳接收到的數據,在電腦里顯示
                }               
        }
}

*/
/**********************************************************/                
/*  主函數  */
void  main()
{
    lcd_init();                   //LCD1602初始化
        TMOD=0x01;                    //定時器T0設為16位定時器
        EA=1;
    ET0=1;
    TR0=1;
       
        while(1)
        {
         key_scan();
         date_display();    //顯示萬年歷部分
         weekday_display(); //顯示Weekday信息
         Tdisplay();            //顯示溫度部分                  
         TimeDisplay(S);    //顯示時鐘部分
       
         }
         
}

/*  中斷函數  */
void interserve(void) interrupt 1 using 1           //定時器T0的中斷編號為1,using 1寄存器組
  {
                uchar i;
        TR0=0;              //調用T0中斷程序時先要關閉定時器T0
        i++;               //每來一次中斷,中斷次數int_time自加1       
            if(i==20)          //夠20次中斷,即1秒鐘進行一次檢測結果采樣
            {
           i=0;            //中斷次數清0
               S++;             //秒加1
                   if(S==60)
                   {
                      S=0;
                      M++;
                      if(M==60)
                        {
                                  M=0;
                                  H++;
                                  if(H==24)
                                  {
                                          H=0;
                                        day++;
                                        if((day-1)==daytemp)
                        {
                                           day=1;
                               month++;
                               if((month-1)==12)                  
                               {
                                              month=1;
                                  year++;
                                           }
                    }
                                    weekdayflag++;                               
                                    if((weekdayflag-1)==7)
                                    {
                                           weekdayflag=1;
                                    }                               
                                   }
                                 }

                        }   
            }                     
            TH0=(65536-46080)/256;    //重新給計數器T0賦初值50MS
            TL0=(65536-46080)%256;
             TR0=1;                    //啟動定時器T0

}  


回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 一区二区三区国产精品 | 久久精品国产a三级三级三级 | 国产一区二区三区在线 | 日韩欧美国产精品一区二区三区 | 亚州激情| 欧美综合在线视频 | 久久久久久美女 | 精品美女久久久 | 欧洲国产精品视频 | 久久久久www | 中文字幕av在线播放 | 婷婷桃色网 | 伊人久久综合 | 久久久久久国模大尺度人体 | 日本精品视频 | 五月免费视频 | 亚洲国产精品99久久久久久久久 | 一级做a爰片久久毛片免费看 | 国产精品毛片 | 亚洲精品九九 | 视频一区在线 | 国产精品精品视频 | 四虎国产| 色婷婷综合久久久中文字幕 | 午夜影院在线观看 | 毛片一区二区三区 | 国产午夜精品理论片a大结局 | 久久久久亚洲av毛片大全 | 中日av| 国产一级特黄aaa大片评分 | 91视频导航 | 亚洲 中文 欧美 日韩 在线观看 | 欧美日韩精品一区 | 久久久久亚洲精品 | 青青草免费在线视频 | 欧美日韩91 | 色资源在线| 亚洲热在线视频 | 一区二区三区四区在线 | 国产农村妇女毛片精品久久麻豆 | 欧美日韩在线精品 |