1 设计目标
通过18b20芯片获取温度,利用动态数码管显示温度。
2 主要功能
实现温度测量并显示。
3 硬件设计
温度寄存器由两个字节组成,分为低8位和高8位。一共16位。
其中,第0位到第3位,存储的是温度值的小数部分。
第4位到第10位存储的是温度值的整数部分。
第11位到第15位为符号位。全0表示是正温度,全1表示是负温度。
表格中的数值,如果相应的位为1,表示存在。如果相应的位为0,表示不存在。
1.单总线通信初始化
初始化时序包括:主机发出的复位脉冲和从机发出的应答脉冲。主机通过拉低单总线480-960μs产生复位脉冲;然后由主机释放总线,并进入接收模式。主机释放总线时,会产生一由低电平跳变为高电平的上升沿,单总线器件检测到该上升沿后,延时15~60μs,接着单总线器件通过拉低总线60~240μs来产生应答脉冲。主机接收到从机的以应答脉冲后,说明有单总线器件在线,到此初始化完成。然后主机就可以开始对从机进行ROM命令和功能命令操作。
2.位写入时序
写时序:当主机把数据线从逻辑高电平拉到逻辑低电平的时候,写时间隙开始。有两种写时间隙:写1的时间隙和写0时间隙。所有写时间隙必须最少持续60us,包括两个写周期间至少1us的恢复时间。DQ引脚上的电平变低后,DS18B20在一个15us到60us的时间窗口内对DQ引脚采样。如果DQ引脚是高电平,就是写1,如果DQ引脚是低电平,就是写0。主机要生成一个写1时间隙,必须把数据线拉到低电平然后释放,在写时间隙开始后的15us内允许数据线拉到高电平。主机要生成一个写0时间隙,必须把数据线拉到低电平并保持60us。
3.位读取时序
当主机把总线从高电平拉低,并保持至少1us后释放总线;并在15us内读取从DS18B20输出的数据。
4 流程图
5 源程序
#include <REGX51.H>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P3^7; //定义端口
int i;
/**************************************延时***********************************/
void delay_us(uchar n) //延时约16微妙
{
while(n--);
}
void delay(unsigned int t)
{
while(t--);
}
/**************************************18b20初始化***********************************/
void DS18B20_init()
{
DQ=1;
delay_us(1); //稍作延时
DQ=0;
delay_us(80); //延时480到960us
DQ=1;
i = 0;
while(DQ) //等待DS18B20拉低总线
{
delay_us(100);
i++;
if(i>5)//约等待>5MS
{
break;
}
}
}
/**************************************写一个字节***********************************/
void write_byte(uchar dat) //写一个字节
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0; //每写入一位数据之前先把总线拉低1us
_nop_();
DQ=dat&0x01; //取最低位写入
delay_us(10); //延时68us,持续时间最少60us
DQ=1; //然后释放总线
dat=dat>>1; //从低位开始写
}
delay_us(10);
}
/**************************************读一个字节***********************************/
uchar read_byte() //读一个字节
{
uchar i,dat=0;
for(i=0;i<8;i++)
{
DQ=0; //先将总线拉低1us
_nop_();
DQ=1; //然后释放总线
_nop_();_nop_();
_nop_();_nop_();
if(DQ) dat=dat|0x80; //每次读一位
dat=dat>>1; //从最低位开始读
delay_us(10); //读取完之后等待48us再接着读取下一个数
}
return dat;
}
/**************************************读温度***********************************/
uint read_temper ()
{
uchar a,b;
uint t=0;
DS18B20_init();//初始化
delay_us(15);
write_byte(0xcc); //因只有一个18b20,所以直接跳过ROM操作命令
write_byte(0x44); //发送启动温度转换命令
DS18B20_init();
delay_us(15);
write_byte(0xcc); //跳过ROM操作命令
write_byte(0xbe); //发送读温度寄存器命令
a=read_byte(); //先读低八位
b=read_byte(); //再读高八位
t=b;
t<<=8; //左移八位
t=t|a; //t为16位的数,使高八位为b的值,低八位为a的值
return t; //返回温度值
}
/**************************************温度转换***********************************/
uint temper_change()
{
uint temper;
float tp;
temper=read_temper();
if(temper<0) //考虑负温度的情况
{
temper=temper-1;
temper=~temper;
tp=temper*0.0625; //16位温度转换成10进制的温度
temper=tp*100+0.5; //留两个小数点,并四舍五入
}
else
{
tp=temper*0.0625; //16位温度转换成10进制的温度
temper=tp*100+0.5; //留两个小数点,并四舍五入
}
return temper;
}
/******************************************数码管控制函数***************************************/
unsigned char shuzi[]={0x3f/*0*/,0x06/*1*/,0x5b/*2*/,0x4f/*3*/,0x66/*4*/,0x6d/*5*/,0x7d/*6*/,0x07/*7*/,0x7f/*8*/,0x6f/*9*/};//显示的数字(num)的数组
void shumaguan(unsigned char wei,num)//第几位(wei)显示
{
switch(wei)
{
case 1:P0_2=0;P0_1=0;P0_0=0;break;
case 2:P0_2=0;P0_1=0;P0_0=1;break;
case 3:P0_2=0;P0_1=1;P0_0=0;break;
case 4:P0_2=0;P0_1=1;P0_0=1;break;
case 5:P0_2=1;P0_1=0;P0_0=0;break;
case 6:P0_2=1;P0_1=0;P0_0=1;break;
case 7:P0_2=1;P0_1=1;P0_0=0;break;
case 8:P0_2=1;P0_1=1;P0_0=1;break;
}
P3=shuzi[num];
delay(1);
}
/**************************************动态数码管显示结果***********************************/
void xianshi(int d)
{
int k=8,m;
while(d!=0)
{
m=(d%10);//在数码管上显示个位,从后往前显示
shumaguan(k,m);
k--;//数码管向前移位
d=d/10;
}
}
/**************************************主函数***********************************/
int main()
{
int temper;
temper_change();
xianshi(temper);
}
6 结论
本次使用的18b20芯片属于单总线通信,较为简单,对比前期的学习,对于此类芯片,只需要了解其原理及协议,便可以掌握其用法。后期可以将其与其他芯片一起使用从而实现更多功能。