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秒
这是显示的2025年06月07日
这里就是显示的湿度79,温度24,星期6
开心不😊😁?
我很开心
总结教训
不同系列的单片机移植的时候。尤其是这种单总线的系统中。一定要考虑的问题是,系统的时钟关系。经常这次事件。相信以后这种单总线系统的移植时。就应该不会像这次这样了吧。搞了我进3天的时间,才弄好。等我这个项目全部弄完了。把我的全部代码共享出来。供大家相互学习。
致谢
感谢B站,优快云,立创EDA等各大开源平台,对资源的共享。帮助我们学习。