微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > STC52单片机实现DHT11温湿度显示+ds1302可调时钟程序 出现问题

STC52单片机实现DHT11温湿度显示+ds1302可调时钟程序 出现问题

时间:10-02 整理:3721RD 点击:
本人尝试将DHT11温湿度程序和ds1302时钟程序合并,实现两种功能 (程序分别运行是可行的,如后面图片)
合并后就出现图片的问题,什么都不显示。
请大神不吝赐教,谢谢。
这是我的代码:
//DHT11.C文件
#include<reg52.h>
#include<INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
/*                时钟                */

sbit key0 = P3^4;//功能键
sbit key1 = P3^6;//增大键
sbit key2 = P3^7;//减小键
sbit RST = P1^7;
sbit SCLK = P1^5;
sbit SDA = P1^6;
sbit LCD_RS = P2^5;
sbit RW = P2^6;
sbit LCD_E = P2^7;
#define DS1302_SECOND_WRITE     0x80
#define DS1302_MINUTE_WRITE     0x82
#define DS1302_HOUR_WRITE            0x84
#define DS1302_DAY_WRITE                 0x86
#define DS1302_MON_WRITE                0x88
#define DS1302_YEAR_WRITE                0x8c
#define DS1302_WEEK_WRITE                0x8a
#define DS1302_CURRENT_WRITE    0x90
#define DS1302_SECOND_READ      0x81
#define DS1302_MINUTE_READ      0x83
#define DS1302_HOUR_READ        0x85
#define DS1302_DAY_READ             0x87
#define DS1302_MON_READ             0x89
#define DS1302_YEAR_READ             0x8d
#define DS1302_WEEK_READ                0x8B
#define WRITE_PROTECT           0x8e
uchar sec,min,hour,day,mon,year,week,num,flag;
unsigned char table[]="20  -  -      ";
unsigned char table1[]="      :  :  ";
/*****************************/
void Delay_us(unsigned char n);
void write_cmd(uchar com)                  //写指令
{
        LCD_RS=0;
        RW=0;
        P0=com;
        Delay_us(5);
        LCD_E=1;
        Delay_us(5);
        LCD_E=0;
}
/********************/
void write_data(uchar dat)                           //写数据
{
        LCD_RS=1;
        RW=0;
        P0=dat;
        Delay_us(5);
        LCD_E=1;
        Delay_us(5);
        LCD_E=0;
}
/****************/
void write_sf(uchar add,uchar date)                   //时分秒函数,前一个是定义位置,后一个则是分离数据
{
        uchar ge,shi;
        shi=date/10;
        ge=date%10;
        write_cmd(0x80+add);                //设置显示的位置
//        Delay_us(10);
        write_data(0x30+shi);                         //给十位送数据
//        Delay_us(10);
        write_data(0x30+ge);                   //给个位送数据
}
/**********************************/
void lcd_write_week(uchar week)//写液晶星期显示函数
{
   write_cmd(0x80+11);//设置显示位置
   switch(week)
   {
             case 1:  write_data('M');Delay_us(5);
               write_data('O');Delay_us(5);
                           write_data('N');break;
          case 2:  write_data('T');Delay_us(5);
               write_data('U');Delay_us(5);
                           write_data('E');break;
          case 3:  write_data('W');Delay_us(5);
               write_data('E');Delay_us(5);
                           write_data('D');break;
          case 4:  write_data('T');Delay_us(5);
               write_data('H');Delay_us(5);
                           write_data('U');break;
          case 5:  write_data('F');Delay_us(5);
               write_data('R');Delay_us(5);
                           write_data('I');break;
          case 6:  write_data('S');Delay_us(5);
               write_data('A');Delay_us(5);
                           write_data('T');break;
          case 7:  write_data('S');Delay_us(5);
               write_data('U');Delay_us(5);
                           write_data('N');break;
   }
}
/*************************/
void init()                                                           //1602初始化
{
        uchar i;
        LCD_E=0;
        write_cmd(0x38);                                        //显示模式设置
        write_cmd(0x0c);                                  //开显示,光标不闪烁
        write_cmd(0x06);                                  
//        write_cmd(0x01);
        write_cmd(0x80);
        for(i=0;i<14;i++)                                          
        {
                write_data(table);
                Delay_us(10);
        }
        write_cmd(0xc0);
        for(i=0;i<12;i++)
        {
                write_data(table1);
                Delay_us(10);                                                 //1602位置的初始化
        }
//        while(1);
}                                         //以上便是液晶1602的初始化
/***********************************/
uchar DS1302ReadByte()                                                //读一个字节
{
        uchar i,dat;
        Delay_us(2);
        for(i=0;i<8;i++)
        {
                dat>>=1;//要返回的数据左移一位
                if(SDA==1)//当数据线为高时,证明该位数据为1
                dat|=0x80;//要传输数据的当前值置为1,若不是,则为0
                SCLK=1;//拉高时钟线
                Delay_us(2);
                SCLK=0;//制造下降沿
                Delay_us(2);
        }
        return dat;//返回读取出的数据
}
/************************************************/
void DS1302WriteByte(uchar dat)                           //写一个字节
{
        uchar i;
        SCLK=0;//初始时钟线置为0
        Delay_us(2);
        for(i=0;i<8;i++)//开始传输8个字节的数据
        {
                SDA=dat&0x01;//取最低位,注意DS1302的数据和地址都是从最低位开始传输的
                Delay_us(2);
                SCLK=1;//时钟线拉高,制造上升沿,SDA的数据被传输
                Delay_us(2);
                SCLK=0;//时钟线拉低,为下一个上升沿做准备
                dat>>=1;//数据右移一位,准备传输下一位数据
        }
}
/********************************/
uchar DS1302Read(uchar cmd)                                   //读命令
{
        uchar dat;
        RST=0;//初始CE线置为0
        SCLK=0;//初始时钟线置为0
        RST=1;//初始CE置为1,传输开始
        DS1302WriteByte(cmd);//传输命令字,要读取的时间/日历地址
        dat=DS1302ReadByte();//读取要得到的时间/日期
        Delay_us(4);
        SCLK=1;//时钟线拉高
        RST=0;//读取结束,CE置为0,结束数据的传输
        dat = dat/16*10+dat%16;         //分离十位和个位,将十六进制数转化为十进制数
        return dat;//返回得到的时间/日期
}
/*********** */
void DS1302Write(uchar cmd, uchar dat)                //往1302中写数据
{
        RST=0; //初始CE线置为0
        SCLK=0; //初始时钟线置为0
        RST=1; //初始CE置为1,传输开始
        DS1302WriteByte(cmd); //传输命令字,要写入的时间/日历地址
        DS1302WriteByte(dat); //写入要修改的时间/日期
        SCLK=1; //时钟线拉高
        RST=0; //读取结束,CE置为0,结束数据的传输
}
/***********************************/
void Init_DS1302()                 //1302初始化
{
        DS1302Write(0x8e,0x00);//写保护关
        DS1302Write(0x8e,0x80);
}
/***************************/
void display()                                                                        //主要是显示程序,从DS1302中读取数值
{
        day=DS1302Read(DS1302_DAY_READ);
        mon=DS1302Read(DS1302_MON_READ);
        year=DS1302Read(DS1302_YEAR_READ);
        week=DS1302Read(DS1302_WEEK_READ);
        sec=DS1302Read(DS1302_SECOND_READ);
        min=DS1302Read(DS1302_MINUTE_READ);
        hour=DS1302Read(DS1302_HOUR_READ);
        write_sf(8,day);
        write_sf(5,mon);
        write_sf(2,year);
        lcd_write_week(week);
        write_sf(0x40+4,hour);
        write_sf(0x40+7,min);
        write_sf(0x40+10,sec);                
}
/***********************************/
void keyscan()                  //键盘扫描
{
   if(key0==0)//确认功能键按下
   {
             Delay_us(20);
          if(key0==0)//功能键确实按下
           {
             while(!key0);//释放
                   num++;//按下次数记录
                   switch(num)
             {
                   case 1:  flag=1;//修改时间,液晶禁止从DS1302读数据
                     write_cmd(0x0f);//光标开始闪烁
                             write_cmd(0x80+2);//第一次按下,光标定位到年位置
                                  break;
                   case 2:  write_cmd(0x80+5);//第二次按下,光标定位到月位置
                                     break;
                   case 3:  write_cmd(0x80+8);//第三次按下,光标定位到日位置
                                   break;
                   case 4:  write_cmd(0x80+11);//第四次按下,光标定位到星期位置
                                   break;
                   case 5:  write_cmd(0x80+0x40+4);//第五次按下,光标定位到时位置
                                    break;
                                                 
                   case 6:  write_cmd(0x80+0x40+7);//第六次按下,光标定位到分位置
                                     break;
                   case 7:         write_cmd(0x80+0x40+10);//第七次按下,光标定位到秒位置
                                         break;
           case 8:         num=0;//第八次按下,记录清零
                             write_cmd(0x0c);//不显示光标                                                                              
                                       DS1302Write(WRITE_PROTECT,0x00);//禁止写保护
                                     DS1302Write(0x80,(sec/10*16)+sec%10);//将调节后的秒写入DS1302
                         DS1302Write(0x82,(min/10*16)+min%10);//将调节后的分写入DS1302
                         DS1302Write(0x84,(hour/10*16)+hour%10);//将调节后的时写入DS1302
                                     DS1302Write(0x8a,(week/10*16)+week%10);//将调节后的星期写入DS1302
                         DS1302Write(0x86,(day/10*16)+day%10);//将调节后的日写入DS1302
                         DS1302Write(0x88,(mon/10*16)+mon%10);//将调节后的月写入DS1302
                                     DS1302Write(0x8c,(year/10*16)+year%10);//将调节后的年写入DS1302
                                     DS1302Write(WRITE_PROTECT,0x80);//开写保护
                                     flag=0;//时间修改完毕,允许液晶从DS1302读数据
                                         break;                 
               }  
          }
   }
   if(num!=0)
   {
             if(key1==0)//确认增大键按下
          {
                    Delay_us(20);
                  if(key1==0)//增大键确实按下
                  {
                          while(!key1);
                        switch(num)
                        {
                           case 1:        year++;//调节年
                                    if(year==100)year=0;
                                    write_sf(2,year);//将调节后的年送入液晶显示
                                    write_cmd(0x80+2);//光标回到指定处
                                                break;
                           case 2:  mon++;//调节月
                                    if(mon==13)mon=1;
                                    write_sf(5,mon);//将调节后的月送入液晶显示
                                    write_cmd(0x80+5);//光标回到指定处
                                                break;
                          
                           case 3:  day++;//调节日
                                if(day==32)day=1;
                                    write_sf(8,day);//将调节后的日送入液晶显示
                                    write_cmd(0x80+8);//光标回到指定处
                                            break;
                           case 4:  week++;
                                    if(week==8)week=1;
                                    lcd_write_week(week);//将调节后的星期送入液晶显示
                                    write_cmd(0x80+11);//光标回到指定处
                                    break;
                           case 5:  hour++;
                                    if(hour==24)hour=0;
                                    write_sf(0x40+4,hour);//将调节后的小时送入液晶显示
                                    write_cmd(0x80+0x40+4);//光标回到指定处
                                            break;
                          
                           case 6:  min++;
                                    if(min==60)min=0;
                                         write_sf(0x40+7,min);//将调节后的分送入液晶显示
                                    write_cmd(0x80+0x40+7);//光标回到指定处
                                               break;
                           case 7:  sec++;
                                    if(sec==60)sec=0;
                                    write_sf(0x40+10,sec);//将调节后的秒送入液晶显示
                                    write_cmd(0x80+0x40+10);//光标回到指定处
                                                      break;
                           default: break;                                         
                        }                                 
                  }
          }
          if(key2==0)//确认减小键按下
          {
                    Delay_us(10);
                  if(key2==0)//减小键确实按下
                  {
                          while(!key2);
                        switch(num)
                        {
                          case 1:  year--;//调节年
                                    if(year==-1)year=99;
                                            write_sf(2,year);
                                            write_cmd(0x80+2);
                                            break;
                          case 2:  mon--;//调节月
                                            if(mon==0)mon=12;
                                            write_sf(5,mon);
                                            write_cmd(0x80+5);
                                            break;
                          case 3:  day--;//调节日
                                            if(day==0)day=31;
                                            write_sf(8,day);
                                            write_cmd(0x80+8);
                                            break;
                          case 4:   week--;//调节星期
                                             if(week==0)week=7;
                                             lcd_write_week(week);
                                             write_cmd(0x80+11);
                                             break;
                          case 5:   hour--;//调节时
                                                  if(hour==-1)hour=23;
                                                  write_sf(0x40+4,hour);
                                                  write_cmd(0x80+0x40+4);
                                                  break;
                          case 6:   min--;//调节分
                                             if(min==-1)min=59;
                                             write_sf(0x40+7,min);
                                             write_cmd(0x80+0x40+7);
                                             break;
                          case 7:   sec--;//调节秒
                                             if(sec==-1)sec=59;
                                             write_sf(0x40+10,sec);
                                             write_cmd(0x80+0x40+10);
                                             break;
                          default:break;
                                          
                        }
                  }
          }
   }
}
//#include<Timee_Delay.h>
//The main only needs to call getDHT11()
//then the temperature and huminity was geted in F16T,F16RH as float
sbit bit11=P2^0;
unsigned char U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
float F16T,F16RH;
//read 8 bits onice
void Delay_us(unsigned char n);
char COM(void)
{
        char i,U8temp,U8comdata;
        for(i=0;i<8;i++)
        {
                while(!bit11);//表示读取的高电位延时大于20多us,则读取的是1,否则读取的是0
                Delay_us(35);
                U8temp=0;
                if(bit11)
                        U8temp=1;
                while(bit11);
                        U8comdata<<=1;
                        U8comdata|=U8temp;                //0
        }//rof
        return        U8comdata;
}
//------------------------
//----温湿度读取子程序----
//------------------------
//----以下变量均为全局变量----
//----温度高8位==U8T_data_H----
//----温度低8位==U8T_data_L----
//----湿度高8位==U8RH_data_H----
//----湿度低8位==U8RH_data_L----
//----校验8位==U8checkdata----
//----调用相关子程序如下----
//----Delay();,Delay_10us();,COM();
//------------------------
void Delay_ms(unsigned int n);
void getDHT11(void)
{
        //主机拉低18ms
GO1: bit11=0;
         Delay_ms(20);
         bit11=1;
         //总线由上拉电阻拉高 主机延时20us
         Delay_us(60);
         //主机设为输入 判断从机响应信号
         // bit11=1
         //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
         if(!bit11)                //T!
         {
                 while(!bit11);                //wait DHT goto high
                 
                 while(bit11);
                 //数据接受状态
                 U8RH_data_H=COM();
                 U8RH_data_L=COM();
                 U8T_data_H=COM();
                 U8T_data_L=COM();
                 U8checkdata=COM();
                 bit11=1;
                 //数据校验
                 if((U8T_data_H+U8T_data_L+U8RH_data_H+U8RH_data_L)!=U8checkdata)
                 //if check wrong,read again
                 goto GO1;
         }//fi
         F16T=U8T_data_H+(float)U8T_data_L/256;  //change integer to float
         F16RH=U8RH_data_H+(float)U8RH_data_L/256;
}

//----LCD1602----
#include<reg52.h>
#include<stdio.h>
#include<INTRINS.H>
//#include<Lcd_1602.h>
//#include<Time_Delay.h>
#define LCD_DATA P0  //LCD1602 data transfer define
#define uint unsigned int
#define uchar unsigned char
/****
只由主函数调用的有
Init_Lcd()
LCD_write_str(uchar X,uchar Y,uchar *s)
LCD_value(unsigned char x,unsigned char y,float f)
****/
//sbit LCD_RS=P2^5;        //1602 control define
//sbit RW=P2^6;
//sbit LCD_E=P2^7;

/*****************************************
#define LCD_SCREEN_ON 0x0C    //显示开
#define LCD_SCREEN_OFF 0x08    //显示关
#define LCD_CURSOR_ON 0X0A    //显示光标
#define LCD_CURSOR_OFF 0x0c    //无光标
#define LCD_C_FLASH_ON 0x0f    //有光标,光标闪动
#define LCD_C_FLASH_OFF 0x0c    //有光标,光标不闪动
//进入模式设置指令
#define LCD_AC_UP 0x06    //新数据后光标右移
#define LCD_AC_DOWN 0x04    //新数据后光标左移
#define LCD_S_MOVE_ON 0X05    //画面可平移
#define LCD_S_MOVE_OFF 0x04    //画面不可平移
//设定显示屏或光标移动方向指令
#define LCD_C_LEFT 0x10    //光标左移1格,且AC值减1
#define LCD_C_RIGHT 0x11    //光标右移1格,且AC值加1
#define LCD_CHAR_LEFT 0x18    //显示器上字符全部左移1格,但光标不动
#define LCD_CHAR_RIGHT 0x1C    //显示器上字符全部右移1格,但光标不动
*******************************************/
//注        有主函数调用的函数都已作说明 其他函数一般不由主函数调用

/*********************************************
* 名 称:Init_Lcd() 主函数调用
* 功 能:Lcd 初始化
* 入口参数:无
* 出口参数:无
*范 例:在主函数中直接调用
**********************************************/
void LCD_write_char(uchar cd,uchar ab);
void Init_Lcd()                        //LCD初始化
{
        LCD_write_char(0x38,0);
        Delay_ms(1);
        LCD_write_char(0x38,0);
        Delay_ms(1);
        LCD_write_char(0x38,0);
        Delay_ms(1);
        LCD_write_char(0x0c,0);
        Delay_ms(1);
        LCD_write_char(0x06,0);
        Delay_ms(1);
        LCD_write_char(0x0c,0);
        Delay_ms(1);
       
}
/******************************************************
*名 称:LCD_write_str(uchar X,uchar Y,uchar *s)主函数调用
*功 能:在指定地址写一个字符串        eg:Y=0,1,2,3,4,5,6,7,8,9,10...15。        X=0,1。
*入口参数:X:横坐标 Y:纵坐标 *s:字符串首地址
*出口参数:无
*范 例:LCD_write_str(1,1,uchar *s)
  *****************************************************/
void LCD_set_xy(uchar x,uchar y);
void LCD_write_str(unsigned char X,unsigned char Y,unsigned char *s)
{
        LCD_write_char(0,' ');
        LCD_set_xy(X,Y);                //写地址
        while(*s)                                //写显示字符
        {
                LCD_write_char(0,*s);
                s++;
        }
}

/******************************************************
*名 称:LCD_set_xy(uchar x,uchar y)                the optic sign   flash?
*功 能:指定一个地址       
*入口参数:X:横坐标 Y:纵坐标
*出口参数:无
*范 例:LCD_set_xy(5,1)
  *****************************************************/
void LCD_set_xy(uchar x,uchar y)        //写地址函数
{
        unsigned char address;
        if(y==0)
                address=0x80+x;
        else
                address=0xc0+x;
        LCD_write_char(address,0);
}

/*******************************************************
*名 称:LCD_en_write(void)
*功 能:液晶使能
*入口参数:无
*出口参数:无
*范 例:直接调用
  ******************************************************/
void LCD_en_write(void)                //液晶使能
{
        //_nop_();
        LCD_E=1;        //EN=1
        //_nop_();
        LCD_E=0;        //EN=0
}
//------------------------------------------------------

/************************************************
*名 称:LCD_write_char(uchar cd,uchar ab)
*功 能:写指令或数据  当写ab时 应使cd=0  当cd不为0 且ab的赋值无效
*入口参数:cd:指令内容 ab:数据内容  指令常量已在上面定义 但一般不用
*出口参数:无
*范 例:LCD_write_char(0,'f')
  ***********************************************/
void LCD_byte(unsigned char abc);
void LCD_write_char(uchar cd,uchar ab)        //写数据
{
        Delay_us(20);
        if(cd==0)
        {
                LCD_RS=1;                        //RS=1,写显示内容
                LCD_byte(ab);
        }
        else
        {
                LCD_RS=0;                        //RS=0,写命令
                LCD_byte(cd);
        }
}

/*************************************************
  *名 称:LCD_byte(abc);
  *功 能:写一个字符到 or called one byte to LCD 中
  *入口参数:
  *出口参数:无
  *************************************************/
void LCD_byte(unsigned char abc)
{
        RW=0;
        LCD_E=0;
        LCD_DATA=abc;
        LCD_en_write();
}
//在液晶中显示浮点数函数
LCD_value(unsigned char x,unsigned char y,float f)
{
        unsigned char str[15];                //不能定义为char *str,数组长度一定要大于浮点
        //数的总位数
        sprintf(str,"%.1f",f);                //1表示小数位数 小数太多 自动四舍五入
        LCD_write_str(x,y,str);
        return 0;
}

//主函数文件
#include<reg52.h>
#include<intrins.h>
//#include<Lcd_1602.h>
//#include<Time_Delay.h>
//#include"DHT11.H"
extern float F16T,F16RH;        //全局变量声明
/*                */
/**** 主 函 数 ****/
/*                */
void main()
{
        if(P3^3)
        {
        Init_Lcd();
        LCD_write_str(0,1,"Bless You!");        //液晶预显示测试
        LCD_value(0,0,2015.520);
        Delay_ms(2000);
        Init_Lcd();
        while(1)
        {
                getDHT11();
                LCD_write_str(0,0,"Tem=");
                LCD_value(5,0,F16T);
                LCD_write_str(8,0,"\"C");        //字符 " 应用转义格式
                LCD_write_str(0,1,"Hum=");
                LCD_value(5,1,F16RH);
                LCD_write_str(9,1,"%");
                Delay_ms(500);
        }
        }
        else
        {
                init();
        Init_DS1302();
        while(1)
        {
                keyscan();
                if(flag==0)
                 display();       
        }
        }
}

//延时函数文件
//以下为延时函数        this is fit to old C51 12MHz,12 devide frequency
void Delay_ms(unsigned int n)        //n毫秒延时
{
        unsigned char j;
        while(n--)
        {
                for(j=0;j<125;j++);
        }
}
void Delay_us(unsigned char n)        //N us 延时函数
{
        n=n/2;
        while(--n);
}


时钟


温湿度


ADDRESS SPACE OVERFLOW啊
你的Keil和谐了没有?
你的全局变量或许太多了。,

这两个都是i2c的吧,你这里是怎么处理的

程序出现问题,什么都不显示,求解
是否与程序在keil中出现ADDRESS SPACE OVERFLOW有关?

我现在在学习万年历的程序,还没有你这么难的,你懂了教教我哈

小编弄完了展示展示呗

问题解决了,还想问问 I2C 这我不大懂求解释?

I2C怎么了,你按它的协议走就没有问题啊,有好多协议的文章你可以找找

怎么展示给你看啊?

谢谢耐心解答,分给你吧

问题已解决

把完整的图截屏出来就看到了。

小编能把完整的文件发给我吗,我也在做类似的,拜托了

楼楼有单独的DHT11和1602的代码吗,求分享啊

有原程序吗?求分享

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top