在普中板上进行写较综合的项目时,是否会出现温度传感器经常出错的问题,明明是严格按照时序图所编写的程序就是无法读出正确的值(全为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口是片选信号,翻开时序图文章来源:https://www.toymoban.com/news/detail-510418.html
不出所料,在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冲突。文章来源地址https://www.toymoban.com/news/detail-510418.html
到了这里,关于基于普中A2实验板,ds18b20温度传感器与ds1302时钟芯片的冲突现象的探讨的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!