依旧是接着蓝桥杯的机会来学习一下DS18B20和单总线技术,平台依旧是IAP15F2K61S2单片机
DS18B20单线数字温度计以9位数字量的形式反映器件的温度值,DS18B20通过一个单线接口发送或者接受信息,因此在中央微处理器和DS18B20之间只需要一根连线。下图为其引脚功能说明:
器件框图如下所示:
从图中可以看出,DS18B20主要由三个数字部件构成,分别是64位激光ROM,温度传感器,非易失性温度报警触发器TH和TL。
DS18B20所使用的总线技术为单总线技术,目前单片机与外设之间进行数据传输的串行总线主要由SCI,I2C和SPI总线,其中SCI总线总是以异步方式进行通信(一条数据输入线,一条数据输出线),而I2C总线以同步串行二线方式进行通信(一条时钟线,一条数据线),SPI总线则以同步串行三线方式进行通信(一条数据输入线,一条数据输出线)。这些总线都需要至少两条或两条以上的信号线,而DS18B20使用的单总线技术与上述总线不同,它采用单条信号线,既可传输时钟,有可传输数据,而且数据传输是双向的,因而这种单总线技术具有线路简单,硬件开销少,成本低廉,便于总线扩展和维护等优点。单总线适用于单主机系统,能够控制一个或多个从机设备。
还是老方法,先对DS18B20进行初始化,然后对DS18B20进行读写操作。
首先我们来看看控制DS18B20的指令。
33H-----读ROM:读DS18B20温度传感器ROM中的编码。
55H-----匹配ROM。发出此命令之后,接着发出64位ROM的编码,访问单总线上与该编码相对应的DS18B20并使之做出响应,为下一步对该DS18B20的读/写做准备。
F0H-----搜索ROM。用于确定挂接在同一总线上DS18B20的个数,识别64位ROM地址,为操作各器件做好准备。
CCH-----跳过ROM。忽略64位ROM地址,直接向DS18B20发温度变换命令,适用于一个从机工作。
ECH-----告警搜索命令。执行后只有温度超过设定值上限或下限芯片才会做出反应。
以上指令是针对总线上挂接多个DS18B20的情况,但如果总线上只挂接了一个DS18B20,就不需要以上ROM指令,直接进行如下的温度转换和读取操作。
44H----温度转换。启动DS18B20进行温度转换,12位转换时长最长为750ms,9位为93.75ms,结果存入内部9字节的RAM中。
BEH----读暂存器。读内部ROM中9字节的温度数据。
4EH----写暂存器。发出向内部RAM的第二三字节写上下线温度数据的命令,紧跟该命令之后,是传送两字节的数据。
48H----复制暂存器。将RAM中第2,3字节的内容复制到EEPROM中。
B8H----重调EEPROM。将EEPROM中内容恢复到RAM中的第三四字节。
B4H----读供电方式。读DS18B20的供电模式。寄生供电时,DS18B20发送0;外接电源供电时,DS18B20发送1。
和DS18B20的任何通信都需要以初始化序列开始,初始化序列见下图:
上图含义如下:
1.先将数据线置高电平1
2.延时(时间要求不严格,但尽可能短些)
3.数据线拉到低电平0
4.延时750us(该时间范围可以在480~960us)
5.数据线拉到高电平1
6.延时等待。如果初始化成功,则在15~60us内产生一个由DS18B20返回的低电平0,据该状态可以确定它的存在,但是应注意,不能无限地等待,不然会使程序进入死循环,所以要进行超时判断。
7.若CPU读到数据线上的低电平0后,还有进行延时,其延时的时间从发出高电平算起至少要480us。
8.将数据线再次拉到高电平1后结束。
DS18B20写数据,时序如下图所示:
其含义如下:
1.数据线先置低电平0
2.延时确定的时间为15us
3.按从低位到高位的顺序发送数据(一次只发送一位)
4.延时时间为45us
5.将数据线拉到高电平1
6.重复1~5步骤,直到发送完整个字节
7.最后将数据线拉高到1
DS18B20读数据,时序图如下:
含义如下:
1.将数据线拉高到1
2.延时2us
3.将数据线拉低到0
4.延时6us
5.将数据线拉高到1
6.延时4us
7.读数据线的状态得到一个状态位,并进行数据处理
8.延时30us
9.重复1~7步骤,直到读取完一个字节
下面我们一起分析一下蓝桥杯官方给出的代码,如果鄙生有理解错的地方,还望各位大牛指点。
首先是初始化函数
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1; //首先将数据线置高
Delay_OneWire(12); //短暂延时
DQ = 0; //将数据线拉到低电平
Delay_OneWire(80); //延时在480~960US之间
DQ = 1; //数据线拉回高电平
Delay_OneWire(10); // 延时等待
initflag = DQ; // initflag等于1初始化失败
Delay_OneWire(5); //最后一个延时
return initflag;
}
其中的Delay_OneWire()函数如下所示:注意这是一段延时,但是延时t值需要根据你单片机的一个机器周期时长来确定,否则时序会出错,即无法读出温度值!!!
void Delay_OneWire(unsigned int t)
{
int i;
while(t--)
{
for(i=0;i<12;i++);
}
}
//向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++) //重复直到发送完整个字节
{
DQ = 0; //数据线首先拉低
DQ = dat&0x01;
Delay_OneWire(5); //延时45us
DQ = 1; //将数据线拉回高电平1
dat >>= 1;
}
Delay_OneWire(5);
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++) //重复接收直到读完整个字节
{
DQ = 0; //数据线拉低
dat >>= 1;
DQ = 1; //数据线拉高
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
以上就是蓝桥杯官方给出的代码,下面我给出我根据单总线库写出的温度读取函数:
void Read_tem(void)
{
unsigned char low,high;
char temp;
Init_DS18B20();
Write_DS18B20(0xCC); //忽略64位ROM地址,直接向DS18B20发送温度变换命令,适用于一个从机工作
Write_DS18B20(0x44); //温度转换
Delay_OneWire(200);
Init_DS18B20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE); //读取温度数据
low = Read_DS18B20(); //低八位
high = Read_DS18B20(); //高八位
temp = high<<4; //整合成一个字节
temp |= (low>>4);
return temp;
}
至此,DS18B20部分就全部介绍完了,如果有错误,希望各位大牛指正。