普中A2实验板上DS18B20温度传感器与DS1302时钟芯片冲突现象的解决方法探讨

在普中板上进行写较综合的项目时,是否会出现温度传感器经常出错的问题,明明是严格按照时序图所编写的程序就是无法读出正确的值(全为0),或许温度底层在其他工程里能正常运行,而到了某些工程中却总是出错。这些就是我经常遇到的问题。

那么问题的根源是什么?如果在排除了温度传感器底层编写上的问题,那就如标题所说,是ds18b20温度传感器与ds1302冲突的原因,严格意义上来说,是在普中A2实验板上,才是这两个芯片冲突的原因。或许有人会觉得不可思议,甚至觉得我在胡说八道,两个相互独立的芯片怎么可能互相冲突。那在这就直接上代码,此处代码来源 weixin_68427965所发的问题

 
#include "reg52.h"
#include<intrins.h>
typedef unsigned char u8;  // x<=255
typedef unsigned int u16;
 
sbit DQ=P3^7;
sbit k1=P3^1; sbit k2=P3^0;
sbit LSA=P2^2;sbit LSB=P2^3;sbit LSC=P2^4;
sbit CLK=P3^6;sbit CE=P3^5;sbit IO_ds1302=P3^4;
 
void delay(u16 t) {while(t--);}
 
u8 code smgd[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
    0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
 
unsigned char code read_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
unsigned char code write_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//秒分时日周年
unsigned char  TIME[7]={0x00,0x00,0x00,0x01,0x01,0x01,0x00};
//0000年1月1日星期一00点00分00秒
unsigned char a[22];
 
 
void dtsmg(int i,int key,int num)
{
    LSA=i%2;
    LSB=(i/2)%2;
    LSC=i/4;
    if(key==0) P0=smgd[num];
    else  P0=key;
    delay(100);
    P0=0x00;
}
 
//DS1302写单字节
void DS1302_Write_Byte(unsigned dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        IO_ds1302=dat&0x01;
        dat>>=1;
        CLK=1;
        _nop_();
        CLK=0;
        _nop_();
    }
}
//DS1302写入函数
void DS1302_Write(unsigned char addr,unsigned char dat)
{
    CE=0;
    _nop_();
    CLK=0;//拉低时钟,使CE(RST)能置高
    _nop_();
    CE=1;
    _nop_();
    DS1302_Write_Byte(addr);//写入地址
    DS1302_Write_Byte(dat);//操作地址数据
    CE=0;
    _nop_();
}
//DS1302读取单字节
unsigned char DS1302_Read_Byte()
{
    unsigned char i;
    unsigned char dat=0x00;
    for(i=0;i<8;i++)
    {
        dat>>=1;
        if(IO_ds1302) dat|=0x80;
        CLK=1;
        _nop_();
        CLK=0;
        _nop_();
    }
    return dat;
}
//DS1302读取函数 
unsigned char DS1302_Read(unsigned char addr)
{
    unsigned char data_a;
    CE=0;
    _nop_();
    CLK=0;
    _nop_();
    CE=1;
    _nop_();
    DS1302_Write_Byte(addr);
    _nop_();
    data_a=DS1302_Read_Byte();
    CE=0;
    _nop_();
    CLK=1;    //我也不知道这里为什么
    _nop_();
    IO_ds1302=0;
    _nop_();
    IO_ds1302=1;
    _nop_();
 
    return data_a;
}
 
void DS1302_Init()
{
    unsigned char i;
    DS1302_Write(0x8e,0x00);//关闭写保护
    for(i=0;i<7;i++)
    {
        DS1302_Write(write_addr[i],TIME[i]);//秒分时日月周年
    }DS1302_Write(0x8e,0x80);//打开写保护
}
 
void read_time()
{    char i;
    for(i=0;i<7;i++)
    {
        TIME[i]=DS1302_Read(read_addr[i]);
    }
}
 
 
//初始化 返回0位初始化成功
unsigned char Init_DS18B20()
{
    char x;
    DQ=0;
    delay(60);
    DQ=1;
    delay(2);
    x=DQ;
    delay(25);
    return x;
}
//写时序,写入一个字节
void Write_DS18B20(unsigned char dat)
{
    
    char i,x;
    DQ=1;//置位
    for(i=0;i<8;i++)
    {
        x=dat&0x01;
        DQ=0;
        DQ=x;
        dat>>=1;
        delay(10);
        DQ=1;//置位
        delay(1);
    }
 
    
}
 
//读时序,读取一个字节
unsigned char Read_DS18B20()
{
    
    unsigned char dat=0x00;
    char i,t;
    //DQ=1;
    for(i=0;i<8;i++)
    {    
        
        DQ=0;
        dat>>=1;
        DQ=1;
        t++;
        t++;
        if(DQ) dat|=0x80;
        delay(4);
        //DQ=1;     ???
    }return dat;
 
}
 
//读取温度
 int ReadTemperature()
{
    int temp=0;
    unsigned char tmh,tml;
    Init_DS18B20();
    delay(110);
    Write_DS18B20(0xcc);//跳过RAM
    Write_DS18B20(0x44);//温度转换
 
    Init_DS18B20();
    delay(110);
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);//读取温度
 
    tml=Read_DS18B20();
    tmh=Read_DS18B20();
 
    temp=tmh;
    temp<<=8;
    temp|=tml;
 
    return temp;
 
}
 
void Trainsport_DS18B20(int temp)
{
    float tp;
    int i;
    u8 a[8]={0,0,0,0,0,0,0,0};
    if(temp<0)
    {
        a[7]=0x40;
        tp=~(temp-1);
        temp=tp*0.0625*100+0.5;
 
    }else
    {
        a[7]=0x00;
        tp=temp;
        temp=tp*0.0625*100+0.5;
    }
    a[2]=smgd[temp%10];
    a[3]=smgd[temp%100/10];
    a[4]=smgd[temp%1000/100];
    a[5]=smgd[temp%10000/1000];
    for(i=0;i<8;i++) dtsmg(i,a[i],16);
}
    
void main()
{
    //DS1302_Init();//这里注释掉初始化,如果不注释这一开始温度显示也为0000
    while(1)
    {
 
        Trainsport_DS18B20(ReadTemperature());
        if(k1==0)
        {
            if(k1==0)
            {    
                while(k2)
                {
                    read_time();
                    dtsmg(0,0,TIME[0]%16);
                    dtsmg(1,0,TIME[0]/16);
                    dtsmg(3,0,TIME[1]%16);
                    dtsmg(4,0,TIME[1]/16);
                    dtsmg(6,0,TIME[2]%16);
                    dtsmg(7,0,TIME[2]/16);
                    dtsmg(2,0x40,0);
                    dtsmg(5,0x40,0);
                }
            }
        }
 
        
    }
}

如运行结果所表示,在调用ds18b20底层前若运行过ds1302的代码,ds18b20所读出来的数据全是0,甚至会出现一开始能正常读,按键按下启用ds1302后ds18b20就立即出错了的情况。直接说解决方案:在ds1302底层函数中,在完成写入或读取的操作后,不要把CE使能口置0,或者在置0后重新置1,确保ds18b20函数调用时ds1302的CE口为1.

那么就会产生一个疑问,为什么两个独立的芯片会互相影响呢?事实上,两个引脚不复用的的芯片确实不会相互影响,而真正出问题的是普中A2实验板上的P3^7和P3^5引脚,从而使ds18b20与ds1302相互冲突。我们来做一个简单的实验,先把P3^7引脚置1,然后看看P3^5引脚的电平高低对P3^7的影响,如果P3^7为1,就点亮所有led,为0就都熄灭,代码如下:

#include <reg51.h>
sbit P37=P3^7;
sbit P35=P3^5;
sbit K1=P3^1;//K1按键
void main()
{
    P37=1;
    while(1)
    {
        if(K1==0)//K1按键按下
            P35=0;
        else     //K1按键释放
            P35=1;
        
        if(P37==1)
            P2=0x00;//LED点亮
        else
            P2=0xff;//LED熄灭
    }
}

在这个程序里,独立按键K1按下时P3^5就置0,不按下就是1。按理来说无论我们按键按不按下LED都应该是点亮的。而事实却是在按键K1不按下时LED点亮,K1按下时LED灭了!

如果我们把P3^7一开始置0呢?改完后无论按键是否按下led均熄灭。也就是在P3^5为0时,P3^7只能是0,反过来P3^7对P3^5却没有这个影响。而板子上P3^5接的是ds1302的CE使能端口,我们根据时序在用完ds1302的底层后会将CE置0,导致了连接P3^7的ds18b20无法正常使用。

这是板子的品控问题线路之间出错了吗?当我把同样的代码发同学时,现象跟上面描述的一模一样。那这就很玄学了,不过单片机玄学的事还少吗(狗头)。当我一头扎进stc89c52的参考手册里时,发现P3口有特殊的功能接口,这一发现让我兴奋起来,会不会是这个外部数据存储器搞的鬼,

然后兴奋地打开千度一查,“现在的芯片已经不接外部存储器了”,给我浇一头冷水。然后继续回来翻手册,发现51的IO有开漏输出功能。

会不会是IO口工作类型弄错了?然后继续兴奋的一查,stc89c51P3口默认上电为准双向口工作模式。又是一头冷水。然后就只能翻翻板子的原理图了,这一翻却找到了问题所在。

在板子里,P3^5口和P3^7口也连接到ET2046AD转换芯片上,翻开芯片手册一查,

P3^7口是AD芯片的数据输出端口,而P3^5口是片选信号,翻开时序图

不出所料,在CS置0时,DOUT自动置0,而CS置1时DOUT口为高阻状态不对P3^7口的电平造成影响,也就造成了P3^5引脚置0时P3^7引脚置为0,那么就破案了。由于普中A2实验板的P3^5和P3^7引脚在各自连接ds1302和ds18b20的同时连接了ET2046,由于ET2046芯片的原因,当P3^5引脚置0时P3^7引脚自动置为0,进而使板子上的ds18b20和ds1302冲突。

物联沃分享整理
物联沃-IOTWORD物联网 » 普中A2实验板上DS18B20温度传感器与DS1302时钟芯片冲突现象的解决方法探讨

发表评论