找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1399|回复: 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 单片机教程网

快速回复 返回顶部 返回列表