参考源码如下:
#include
#define uint unsigned int
#define uchar unsigned char
sbit temp = P2^2;
// delayus(1);//7us
// delay(1);//24us
// delayms(1);//826ms
// delayus(10);//25us
// delay(10);//123us
// delayms(10);//8141ms
//delayus(15);//35us
//delayus(25);//55us
//delayus(3); //13us
//delayus(17);//39us
//delayus(18);//41us
void delayus(uchar i)
{
while(--i);
}
void delayms(uint i)
{
uint j;
for(;i>0;i--)
for(j=100;j>0;j--);
}
void delay(uint i)
{
uint j;
for(j;j
}
void ds18_reset()
{
temp = 0;
delayms(1);
temp = 1;
delayus(25);//55us
}
void ds18_ack()
{
while(temp);
while(!temp);
}
void ds18_writebit(char bitval)
{
temp = 0;
delayus(2);
if(bitval)temp =1;
delayus(15);
temp =1;
}
void ds18_writechar(uchar uc)
{
uint i = 0;
uchar tempdata;
for(i;i8;i++)
{
tempdata = uc >> i;
tempdata = 0x01;
ds18_writebit(tempdata);
}
// delayus(25);
}//从8位数据的低位开始写
uchar ds18_readbit()
{
temp =0;
temp = 1;
delayus(1);
return temp;
}
uchar ds18_readchar()
{
uchar returntemp = 0x00;
uint i = 0;
for(i;i8;i++)
{
if(ds18_readbit())
{
returntemp |= 0x01
}else{
returntemp |= 0x00
}
delayus(18);//每读一个位,要延时40-40us//获取应该更小一点,因为前面一句貌似已经占用了一些时间了
}
return returntemp;
}//首先读到的也是低位字节
void main()
{
uint mi = 0;
uchar ds18data[9]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
ds18_reset();
ds18_ack();
ds18_writechar(0xcc);
ds18_writechar(0x44);
while(ds18_readchar()!=0xff);//单片机开始温度转换后,单总线会被其一直拉低直到总线上在八us时间内持续保持高电平说明转换完成
//测试ds18b20的供电模式(返回值是1)
/* ds18_writechar(0xB4);
temp= 0;
temp = 1;
delayus(1);
if(temp)
{P1 = 0x00;}else{P1 = 0xf0;}
while(1);*/
ds18_reset();
ds18_ack();
ds18_writechar(0xcc);
ds18_writechar(0xBE);
delayus(1);
// P1 = 0xf0;
for(mi = 0;mi 9;mi++)
{
ds18data[mi] = ds18_readchar();
}
for(mi = 0;mi 9;mi++)
{
P1=0xaa;
delayms(1500);
P1 = ~ds18data[mi];
delayms(15000);//
}
P1 = 0x00;
ds18_reset();
while(1);
}
其中应注意一下几点:
1.延时函数应该通过仿真确定实际延时时间,由于keil将c语言编译后会进行一些优化,所以某些写法的延时函数不会是与传入参数呈线性关系的
2.串行向ds18b20写入数据时候,高地位的写入顺序是要注意的(之前因为读出来是从高位开始,写的时候也从高位开始,产生了问题,实际上写给18b20的时候是从低位开始传输的)
3.给ds18b20 “Convert T(0x44) 命令后,应该重新开始一次reset周期之后读取ds18b20的暂存器,若是在0x44后直接读取,则没成功,并且每次开机都应该先给ds18b20发送一个“Convert T命令,否则会读出内部暂存器默认值的。
4.参考一些资料重写后,发现数据读出来都是1,于是怀疑是读出数据的问题,检查并且debug了许久未得其原因,后来考虑到可能是芯片没有响应,所以每次读到都是总线的高电平。于是检查了写函数,发现ds18_writechar()中调用的是ds18_writebit(temp),那么写入的一直是1,ds18b20还会思考呢,给我都是1的命令,我命令表中没有啊
5.单片机用于debug的方法不怎么多,在没有逻辑分析仪的情况下,实时通过led输出八位数据也是不错的选择
6.单总线协议对时序和延时的要求确实比较高。
附上读出rom和ram的数据
rom:
0010 1000 //从数据手册中得知此八位为0x28 , 为系列码
1110 1010
1100 0000
1011 1011
0000 0100
0000 0000
0000 0000
0100 0001
ram:
1100 1001
0000 0001//1 1100 1001 = 1B9 * 0.0625 = 28.5625 // 完美!!!!!
0100 1011
0100 0110
0111 1111//第五六位为11,温度转换精度为12位
1111 1111
0000 0111
0001 0000
0110 0100
经过两天,各种读文档,各种参考程序,终于能正确的写出了这么一个单总线协议的函数了