DHT11不同单片机的移植问题解决

DHT11不同单片机的移植问题解决

事件缘来

最近闲来无事,想制作一个由STC单片机控制的桌面电子笔筒,设想功能,可以实现年月日,时分秒,温湿度的显示功能。时间功能,采用专用芯片PCF8563芯片完成,温湿度采用DHT11模块采集。显示部分通过2个74HC595芯片驱动8位数码管来进行显示。笔筒的四壁焊接WS2812数字LED显示各种花色。​
我利用嘉立创的免费打样机会,制作好了电路图,打样好PCB,把PCB焊接完成。进行逐个功能模块的调试。其他功能都很快的调试出来了。当遇到调试DHT11的时候出现了从来没有遇到过的问题,搞得我头痛好几天,也搞了好几天。今天一个巧合的机遇下。终于找到问题的根源并得以解决。特记录于此。望同行遇到问题,可以予以借鉴参考。

在这里插入图片描述
上图就是我用的DHT11。

问题发现

​ 我在制作之前是有在B站学习DHT11的控制的,网站博主也有分享51单片机的驱动代码的。我拿驱动代码回来,在Protues系统进行了仿真。从仿真中可以看出,驱动代码正常,可以正常使用。
在这里插入图片描述
于是我就把实物焊接好。写代码进去,数码管一直显示00,无法获取模块传出来的信息。偶尔还会出现显示卡死的情况。我反复查看了我的IO口驱动,我的代码移植是否有误。都没有解决问题。我就怀疑是不是我买的模块有问题。于是我联系某宝卖家。问他们的模块是否是测试后确认好的才发货。得到的回复是“都是厂家测试好后,才会发给他们”。我找商家要了他们的测试代码。我原封不动的把他的代码下载进我的51系统开发板。就是下图的板子,按照程序的引脚安全不动的安装好,他的测试代码是将温湿度的值通过串口发回电脑端。我这边安装好后,连接电脑,打开了我的串口调试助手,发现串口能接收数据,我对DHT11进行吹气,发现数据会发生变换,说明这个DHT11模块就是好的。
在这里插入图片描述
又担心是我的硬件电路有问题,我在网上查询了很大资料,芯片手册这些我都看了很多。用万用表测量电压这些都正常,说明硬件就没有问题。后来我就把商家给的驱动代码,进行了修改(DHT11的读取部分没有动一个字符),下载到我的板子上。显示还是00。不能读取温湿度信息。用仿真软件调试,两段代码都是没有问题,都能正常的读出信息。

第一段,商家提供的

	void RH(void)
	{      
	 P2_0=0;//主机拉低18ms 	       
	 Delay(180);		   
	P2_0=1;			   
	   Delay_10us(); //总线由上拉电阻拉高 主机延时20us	   
	   Delay_10us();	   
	   Delay_10us();	   
	   Delay_10us();		   
	   P2_0=1; //主机设为输入 判断从机响应信号 	 
	   if(!P2_0)		 //T !	  //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行	  
	   {
	   U8FLAG=2; //判断从机是否发出 80us 的低电平响应信号是否结束	 	
	   while((!P2_0)&&U8FLAG++);
	   U8FLAG=2;	 //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
	   while((P2_0)&&U8FLAG++);	 //数据接收状态		 
	   COM();
	   U8RH_data_H_temp=U8comdata;
	   COM();
	   U8RH_data_L_temp=U8comdata;
	   COM();
	   U8T_data_H_temp=U8comdata;
	   COM();
	   U8T_data_L_temp=U8comdata;
	   COM();
	   U8checkdata_temp=U8comdata;
	   P2_0=1;	 
	   U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp); //数据校验 
	   if(U8temp==U8checkdata_temp)
	   {
	   	  U8RH_data_H=U8RH_data_H_temp;
	   	  U8RH_data_L=U8RH_data_L_temp;
		  U8T_data_H=U8T_data_H_temp;
	   	  U8T_data_L=U8T_data_L_temp;
	   	  U8checkdata=U8checkdata_temp;
	   }//fi
	   }//fi

	}

第二段,是B站博主分享的

void DHT11_receive(void) //接收40位的数据
{
    uchar R_H,R_L,T_H,T_L,revise; 
    DHT11_start();
 
    if(DHT11_PIO==0)
    {   while(DHT11_PIO==0);     //等待拉高     
		DHT11_delay_us(40);      //拉高后延时80us
        R_H=DHT11_rec_byte();    //接收湿度高八位  
        R_L=DHT11_rec_byte();    //接收湿度低八位  
        T_H=DHT11_rec_byte();    //接收温度高八位  
        T_L=DHT11_rec_byte();    //接收温度低八位
        revise=DHT11_rec_byte(); //接收校正位
		DHT11_delay_us(25);    //结束
    if((R_H+R_L+T_H+T_L)==revise)      //校正
        {
            RH=R_H;
            RL=R_L;
            TH=T_H;
            TL=T_L;
        } 
    }
}

2段代码我都在仿真系统里进行了仿真,都能正常运行,就是我的实物不行。纠结的不行。

问题解决过程

后来实在没有办法了,我就想是不是显示电路出问题了,我开始逐步进行验证解决
第1步我就在主程序中逐级加入显示值的功能。
		DHT11_Receive(&hum,&temp);
		Show_Week(Time.week,hum,temp);
		hum = 25;

这样一来就应该在屏幕上显示25这个值,运行后,也确实能够显示。说明我的显示部分没有问题。
第2步我把hum = 25;这句代码放到DHT11_Receive(&hum,&temp);这个程序内部,看看能不能让数据显示出来。

void DHT11_Receive(u8 *hum,u8 *temp){   //接收40位的数据
    u8 i,DHT11[5]; 
    DHT11_start();
	*hum = 25;
    if(DHT11_PIO==0)
    {   while(DHT11_PIO==0);        //等待拉高     
		DHT11_delay_us(80); 
		for(i = 0;i < 5;i++)
		{
		DHT11[i] = DHT11_rec_byte();
		}
        DHT11_delay_us(25);         //结束		
    if(DHT11[4] = DHT11[0] + DHT11[1] + DHT11[2] + DHT11[3])       //校正
        {   
			 *hum = DHT11[0];
			*temp = DHT11[2];
        } 
    }
}

hum = 25;这个就是我加的,做后也在屏幕上显示出来了。说明程序的参数传递没有问题。
第3步我把
hum = 25;这条指令逐级向下移动。

void DHT11_Receive(u8 *hum,u8 *temp){   //接收40位的数据
    u8 i,DHT11[5]; 
    DHT11_start();	
    if(DHT11_PIO==0)
    {   while(DHT11_PIO==0);        //等待拉高    
		*hum = 25;	
		DHT11_delay_us(80); 
		for(i = 0;i < 5;i++)
		{
		DHT11[i] = DHT11_rec_byte();
		}
        DHT11_delay_us(25);         //结束		
    if(DHT11[4] = DHT11[0] + DHT11[1] + DHT11[2] + DHT11[3])       //校正
        {   
			 *hum = DHT11[0];
			*temp = DHT11[2];
        } 
    }
}

发现屏幕就不显示了。认真理解程序,发现应该是主机没有收到到ACK的信号。我倒过来检测,用示波器检测DHT11的数据引脚的信号。发现了,起始信号应该有低电平的18ms没有。
第4步,我单独把开始步骤拿出来调试,

static void DHT11_start(void){			//读准备
   DHT11_PIO=1;
   DHT11_delay_us(2);
   DHT11_PIO=0;
   DHT11_delay_ms(20);   //延时18ms以上
   DHT11_PIO=1;
   DHT11_delay_us(30);
}

我在主程序中单独执行,这个文件,测IO口的电平变化。用示波器,检测周期。最后发现,周期和需求的时序不一致,快很多。
我想起普通的89S51系列的单片机的机器周期为振荡周期的12倍。而我用的单片机是STC15W系列的。这个周期是1T模式。就是1个机器周期是1个振荡周期。要快12倍。于是我借助示波器。对延时程序进行修改。

static void DHT11_delay_us(u8 n){ while(--n){_nop_();_nop_();_nop_();};}
static void DHT11_delay_ms(u16 z){
	for(z;z>0;z--){
		DHT11_delay_us(200);
		DHT11_delay_us(200);
		DHT11_delay_us(200);
		DHT11_delay_us(200);
		DHT11_delay_us(200);
	}
}

让这段程序的延时时间基本吻合。
第5步我把程序还原,读取数据。竟然发现能够正常读值了,而且用手触摸DHT11,数据能够变化,这个时间很兴奋。还原了所有的程序,在实物上看效果,感觉很好。很满意。看看效果吧。这是显示的时间,16时24分19秒
这是显示的时间,16时24分19秒

这是显示的2025年06月07日

这里就是显示的湿度79,温度24,星期6

开心不😊😁?
我很开心

总结教训

不同系列的单片机移植的时候。尤其是这种单总线的系统中。一定要考虑的问题是,系统的时钟关系。经常这次事件。相信以后这种单总线系统的移植时。就应该不会像这次这样了吧。搞了我进3天的时间,才弄好。等我这个项目全部弄完了。把我的全部代码共享出来。供大家相互学习。

致谢

感谢B站,优快云,立创EDA等各大开源平台,对资源的共享。帮助我们学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值