ds18b20,是一款强大的测温传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,所以是开发中必不可少的一个芯片,为了方便大家上手
ds18b20温度传感器是dallas公司生产的1-wire式单总线器件,具有线路简单,体积小的特点,用它组成的温度测量系统线路非常简单,只要求一个端口即可实现通信。温度测量范围在-55℃~+125℃之间,分辨率可以从9~12位选择,内部还有温度上、下限报警设置。每个ds18b20芯片都有唯一的序列号,所以可以利用多个ds18b20同时连接在同一条总线上,组成多点测温系统。但最多只能连接8个,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
ds18b20 的初始化:
根据 ds18b20 的通讯协议,主机(单片机)控制 ds18b20 完成温度转换必须经过三个步骤:每一次读写之前都要对 ds18b20 进行复位操作,复位成功后发送一条 rom 指令,最后发送 ram 指令,这样才能对 ds18b20 进行预定的操作。复位要求主 cpu 将数据线下拉 500 微秒,然后释放,当 ds18b20 收到信号后等待 16~60 微秒左右,后发出 60~240 微秒的存在低脉冲,主 cpu 收到此信号表示复位成功。
(1) 先将数据线 dq 置高电平“1”。
(2) 延时(该时间要求的不是很严格,但是尽可能的短一点)
(3) 数据线拉到低电平“0”。
(4) 延时 750 微秒(该时间的时间范围可以从 480 到 960 微秒)。
(5) 数据线拉到高电平“1”。
(6) 延时等待(如果初始化成功则在 15 到 60 微妙时间之内产生一个由 ds18b20 所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。
(7) 若 cpu 读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要 480 微秒。
(8) 将数据线再次拉高到高电平“1”后结束。
初始化程序如下:
uchar init_ds18b20()
{
uchar status; //status 为 ds18b20 返回的状态
dq = 1;
delay(8);
dq = 0;
delay(90);
dq = 1;
delay(8);
status=dq;
delay(100);
dq = 1;
return status;
}
ds18b20 应用举例(一)
如下图所示:dq 通过 4.7k 上拉电阻外接正电源(由于单总线为开漏所以需要外接一个 4.7k 的上拉电阻),并连接单片机 p3.3 口。
本例中,1602lcd 显示 ds18b20 所测量的外部温度,调节 ds18b20 模拟改变外界温度时,新的温度将刷新显示在 lcd 上
c 程序如下:
由于本例仅保存一位小数,温度小数位对照表 df_table[]将 0000~1111 对应的 16 个不同的小数进行四舍五入,例如,当读取的温度低字节低 4 位为 0101 时,对应的温度应为 2 -2 +2-4 =0.3125≈0.3,因此数组第 5 个元素(对应 0101)的值为 3;又如,如果低 4 位为 0110,对应的温度为 2 -2 +2-3 =0.375≈0.4,因此,数组第 6 个元素(对应 0110)取值为 4。
#include #include
#define uint unsigned int
#define uchar unsigned char
#define delay4us() {_nop_();_nop_();_nop_();_nop_();} //12mhz 系统频率下,延时 4us
sbit dq = p3^3;
sbit lcd_rs = p2^0;
sbit lcd_rw = p2^1;
sbit lcd_en = p2^2;
uchar code temp_disp_title[]={“current temp : ”}; //1602 液晶第一行显示内容
uchar current_temp_display_buffer[]={“ temp: ”}; //1602 液晶第二行显示内容
uchar code df_table[]={ 0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9 }; //温度小数位对照表
uchar currentt = 0; //当前读取的温度整数部分
uchar temp_value[]={0x00,0x00}; //从 ds18b20 读取的温度值
uchar display_digit[]={0,0,0,0}; //待显示的各温度数位
bit ds18b20_is_ok = 1; //ds18b20 正常标志
void delayxus(uint x) //延时 1
{
uchar i;
while(x--)
{
for(i=0;i《200;i++);
}
}
bit lcd_busy_check() //lcd 忙标志,返回值为 1602lcd 的忙标志位,为 1 表示忙
{
bit result;
lcd_rs = 0;
lcd_rw = 1;
lcd_en = 1;
delay4us();
result = (bit)(p0&0x80);
lcd_en=0;
return result;
}
void write_lcd_command(uchar cmd) //1602lcd 写指令函数
{
while(lcd_busy_check());
lcd_rs = 0;
lcd_rw = 0;
lcd_en = 0; _
nop_();
_nop_();
p0 = cmd;
delay4us();
lcd_en = 1;
delay4us();
lcd_en = 0;
}
void write_lcd_data(uchar dat) //1602lcd 写数据函数
{
while(lcd_busy_check());
lcd_rs = 1;
lcd_rw = 0;
.lcd_en = 0;
p0 = dat; delay4us();
lcd_en = 1;
delay4us();
lcd_en = 0;
}
void lcd_initialise() //1602lcd 初始化
{
write_lcd_command(0x01);
delayxus(5);
write_lcd_command(0x38);
delayxus(5);
write_lcd_command(0x0c);
delayxus(5);
write_lcd_command(0x06);
delayxus(5);
{
void set_lcd_pos(uchar pos) //1602lcd 设置显示位置
}
write_lcd_command(pos|0x80);
}
void delay(uint x) //延时 2
{
while(x--);
}
uchar init_ds18b20() //初始化(或者说复位)ds18b20
{
uchar status;
dq = 1;
delay(8);
dq = 0;
delay(90);
dq = 1;
delay(8);
status=dq;
delay(100);
dq = 1;
return status;
}
uchar readonebyte() //从 ds18b20 读一字节数据
{
uchar i,dat=0;
dq = 1;
_nop_();
for(i=0;i《8;i++)
{
dq = 0;
dat 》》= 1;
dq = 1;
_nop_();
_nop_();
if(dq)
dat |= 0x80;
delay(30);
dq = 1;
}
return dat;
void writeonebyte(uchar dat) //从 ds18b20 写一字节数据
{
uchar i;
for(i=0;i《8;i++)
{
dq = 0;
dq = dat& 0x01;
delay(5);
dq = 1; dat 》》= 1;
}
}
void read_temperature() //从 ds18b20 读取温度值
{
if(init_ds18b20()==1) //ds18b20 故障
ds18b20_is_ok=0;
else
{
writeonebyte(0xcc); //跳过序列号命令
writeonebyte(0x44); //启动温度转换命令
init_ds18b20(); //复位 ds18b20(每一次读写之前都要对 ds18b20 进行复位操作)
writeonebyte(0xcc); //跳过序列号命令
writeonebyte(0xbe); //读取温度寄存器
temp_value[0] = readonebyte(); //读取温度低 8 位(先读低字节,再读高字节,)
temp_value[1] = readonebyte();//读取温度高 8 位 (每次只能读一个字节) ds18b20_is_ok=1; //ds18b20 正常
}
}
void display_temperature() //在 1602lcd 上显示当前温度
{
uchar i;
uchar t = 150, ng = 0; //延时值与负数标志
if((temp_value[1]&0xf8)==0xf8) //高字节高 5 位如果全为 1,则为负数,为负数时取反
{ //加 1,并设置负数标志为 1
temp_value[1] = ~temp_value[1];
temp_value[0] = ~temp_value[0]+1;
if(temp_value[0]==0x00) //若低字节进位,则高字节加 1
temp_value[1]++;
ng = 1; //设置负数标志为 1
}
display_digit[0] = df_table[temp_value[0]&0x0f]; //查表得到温度小数部分
}
}
//获取温度整数部分(低字节低 4 位清零,高 4 位右移 4 位)+(高字节高 5 位清零, //低三位左移 4 位)
currentt = ((temp_value[0]&0xf0)》》4) | ((temp_value[1]&0x07)《《4);
/ //将温度整数部分分解为 3 位待显示数字
display_digit[3] = currentt/100;
display_digit[2] = currentt%100/10;
display_digit[1] = currentt%10;
//刷新 lcd 缓冲 //加字符 0 是为了将待数字转化为字符显示
current_temp_display_buffer[11] = display_digit[0] + ‘0’;
current_temp_display_buffer[10] = ‘。’;
current_temp_display_buffer[9] = display_digit[1] + ‘0’;
current_temp_display_buffer[8] = display_digit[2] + ‘0’;
current_temp_display_buffer[7] = display_digit[3] + ‘0’;
if(display_digit[3] == 0) //高位为 0 时不显示
current_temp_display_buffer[7] = ‘ ’;
if(display_digit[2] == 0&&display_digit[3]==0) //高位为 0,且次高位为 0,则次高位不显示
current_temp_display_buffer[8] = ‘ ’;
//负号显示在恰当位置
if(ng)
{
if(current_temp_display_buffer[8] == ‘ ’)
current_temp_display_buffer[8] = ‘-’;
else
if(current_temp_display_buffer[7] == ‘ ’)
current_temp_display_buffer[7] = ‘-’;
else
current_temp_display_buffer[6] = ‘-’;
}
set_lcd_pos(0x00); //第一行显示标题
for(i=0;i《16;i++)
{
write_lcd_data(temp_disp_title[i]);
}
set_lcd_pos(0x40); //第二行显示当前温度
for(i=0;i《16;i++)
{
write_lcd_data(current_temp_display_buffer[i]);
}
//显示温度符号
set_lcd_pos(0x4d);
write_lcd_data(0x00);
set_lcd_pos(0x4e);
write_lcd_data(‘c’);
}
void main() //主函数
{
lcd_initialise();
read_temperature();
delay(50000);
delay(50000);
while(1)
{
read_temperature();
if(ds18b20_is_ok)
display_temperature();
delayxus(100);
}
}
proteus 仿真运行结果如下:
ds18b20的应用实例二
#include《reg51.h》
sbit dq=p3^0;
sbit d1=p2^0;
sbit d2=p2^1;
#define uchar unsigned char
#define uint unsigned int
uchar temp_value;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void delay_18b20(uint i)
{
while(i--);
}
void init_ds18b20(void)
{
uchar x=0;
dq = 1; //dq复位
delay_18b20(8); //稍做延时
dq = 0; //单片机将dq拉低
delay_18b20(80); //精确延时 大于 480us
dq = 1; //拉高总线
delay_18b20(14);
x=dq; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay_18b20(20);
}
uchar readonechar(void)
{
uchar i=0;
uchar dat = 0;
for (i=8;i》0;i--)
{
dq = 0; // 给脉冲信号
dat》》=1;
dq = 1; // 给脉冲信号
if(dq)
dat|=0x80;
delay_18b20(4);
}
return(dat);
}
void writeonechar(uchar dat)
{
uchar i=0;
for (i=8; i》0; i--)
{
dq = 0;
dq = dat&0x01;
delay_18b20(5);
dq = 1;
dat》》=1;
}
}
void readtemp(void)
{
uchar a=0;
uchar b=0;
uchar t=0;
init_ds18b20();
writeonechar(0xcc); // 跳过读序号列号的操作
writeonechar(0x44); // 启动温度转换
delay_18b20(100); // this message is wery important
init_ds18b20();
writeonechar(0xcc); //跳过读序号列号的操作
writeonechar(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
delay_18b20(100);
a=readonechar(); //读取温度值低位
b=readonechar(); //读取温度值高位
temp_value=b《《4;
temp_value+=(a&0xf0)》》4;
}
void display (uchar num0,uchar num1)
{ p2=0xfd;
p0=table[num1];
delay_18b20(20);
p2=0xfe;
p0=table[num0];
delay_18b20(20);
}
main()
{
uchar a ,b ;
while(1)
{
readtemp();
b=temp_value/10; //十位
a=temp_value%10; //个位
display(b,a);
}
}
亚马逊致力于打造家庭机器人,可能于2019年会向消费者出售机器人
TE Connectivity推出全新ChipConnect电缆组件
光学防抖技术解析
红米5、红米5Plus即将发布,全面屏进入千元时代你最期待谁?
沁恒股份以太网协议栈芯片CH395概述
ds18b20应用程序实例分析
这几款可穿戴设备将可以治疗过敏
精密监视负电源电流的电路
我国成功研发出全球首个液态全柔性机器人
如何解读IGBT和模块的标准体系?
京东探索研究院首提产业元宇宙构想 助力未来更高效的数智供应链
红米note9 5G版手机怎么样?
鸿海正式量产苹果新款iPhone8 OLED版iPhone8延后到十月
揭秘虚拟现实眼镜的发明Oculus Rift的幕后故事
MES系统简介及重要环节
锤子科技绝处逢生 或将有新品发布会
曝三星新一代折叠智能手机将被命名为Galaxy Z Flip
RFID仓库管理的选择办法
红魔Mars电竞手机搭载了骁龙845处理器最高配备10GB内存
NASA猎户座飞船极端温度测试是重要里程碑