/*
用的是80C51单片机,DS18B20温度传感器,晶振是11.0592 具体的手册自行百度解决
我是初学者,仅供参考微笑
*/
#include <reg52.h>
#include <intrins.h>
#include <stdlib.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit DQ=P3^2;
sbit smg3=P1^3;sbit smg2=P1^2;
sbit smg1=P1^1;sbit smg0=P1^0;
sbit smg4=P1^4;
typedef char int8;
typedef int int16;
#define nops(); {_nop_(); _nop_(); _nop_(); _nop_();} //定义空指令
//宏定义一个nops(一个nops相当于4个机器周期(4个nop())
uint8 shuma[4]; uint8 fh=0;
code uint16 sum[]={0xC0,0xF9,0xA4,0xB0,0x99,
0x92,0x82,0xF8,0x80,0x90};
void refresh() //显示函数
{
static uint8 t=0;
switch(t)
{
case 0:smg3=0;smg2=1;smg1=1;smg0=1;P0=sum[shuma[0]];t++;break;//点亮led灯后,把对应 的数组元素赋值一对应的字形码数组中。
case 1:smg3=1;smg2=0;smg1=1;smg0=1;P0=sum[shuma[1]];t++;break;
case 2:smg3=1;smg2=1;smg1=0;smg0=1;P0=0x7F;t++;break; //显示点
case 3:smg3=1;smg2=1;smg1=0;smg0=1;P0=sum[shuma[2]];t++;break;
case 4:smg3=1;smg2=1;smg1=1;smg0=0;P0=sum[shuma[3]];t=0;break;
default:break;
}
}
void delay(uint16 n)
{
while (n--);
}
/*void delay_ms(uint16 n)
{
uint8 m=120;
while (n--)
while (m--);
} */
/*
* 18B20复位函数
单片机t0时刻发送一复位脉冲(最短为480us的低电平信号),
接着在tl时刻释放总线并进入接收状态,DS18B20 在检测到总线的上升沿之后,
等待15-60us,接着DS18B20在t2时刻发出存在脉冲(低电平持续60-240us),如图中虚线所示。
换句话说如果t2~t3之间信号电平如果为低,则说明DS18B20复位成功;否则失败。
*/
void t18b20_reset()
{
bit flag=1;
while(flag)
{
while(flag) //根据时序图进行写代码
{
DQ=1; //先稳定他是高电压
delay(1);
DQ=0; // t0 拉低后延时960us
delay(50);
DQ=1; // t1 拉高
delay(6); //60us
flag=DQ; //t2到t3之间如果是低电平就说名复位成功,会退出本次循环
}
delay(45);
flag=~DQ;
}
DQ=1;
}
/*
* 18B20写1个字节函数
* 向1-WIRE总线上写一个字节
当单片机将总线t0时刻从高拉至低电平时,就产生写时间隙。
见上图,从t0时刻开始 15us之内应将所需写的位送到总线上。
DS18B20在t0后15-60us间对总线采样,若低电平写入的位是0;若高电平,写入的位是1。
连续写2位间的间隙应大于1us。
*/
void write_byte(uint8 dat)
{
uint8 i;
for(i=0;i<8;i++)
{
DQ=1; _nop_(); //一个机器周期(12兆晶振一个机器周期大约是1us)
DQ=0; nops();//4us
DQ=dat&0x01; //在t0时刻开始 15us之内应将所需写的位送到总线上。
delay(6); //在t0后15-60us间对总线采样
dat=dat>>1;
}
DQ=1;
delay(1);
}
/*
* 18B20读1个字节函数
* 从1-WIRE总线上读取一个字节
当单片机将总线t0时刻从高拉至低电平时,总线只须保持低电平4us之后,
在t1时刻将总线拉高,产生读时间隙,读时间在t1时刻后t2时刻前有效,t2距t0为15us,
也就是说,t2时刻前主机必须完成读位 并在t0后的60us~120us内释放总线。
*/
uint8 read_byte()
{
uint8 j,value=0;
for(j=0;j<8;j++)
{
DQ=1;_nop_();
DQ=0;nops();
value>>=1;
DQ=1;nops();
if(DQ==1)
value=value|0x80;
delay(6);
}
DQ=1;
return(value);
}
/*
* 启动温度转换
三个步骤:1、复位DS18B20
2、发出Skip ROM命令(CCH)
3、发出Convert T命令(44H)
读取温度五个步骤 :1、复位DS18B20
2、发出Skip ROM命令(CCH)
3、发出Read命令(BEH)
4、读两字节的温度
5、温度格式转换
*/
void start_temp_sensor()
{
t18b20_reset();
write_byte(0xcc);
write_byte(0x44);
}
uint16 read_temp()
{
uint8 temp[2]; //这2个8位的数组元素存的是温度的二进制
uint16 temp_all;
t18b20_reset();
write_byte(0xcc); //skip ROM(跳过 ROM)
write_byte(0xBE); //read scratchpad(读暂存器)
temp[0]=read_byte();
temp[1]=read_byte();
temp_all=temp[1]; //定义一个16位的变量,把8位的数值存到右边八位
temp_all<<=8; //然后左移8位 such as: 0000000 00000000 <--0000 1000 == 00001000 00000000
temp_all|=temp[0];//再把另一组数值存进去
/*temp_all>>=4;*/
/*temp_all&=0x87FF;*/
return temp_all; //然后把得到的值返回
}
/**
*
* 数值转换
*/
void convert()
{
int16 x;double y;
x=read_temp();
fh=x&0x8000;
if(fh==1) x=~x+1;
y=0.0625*x;
shuma[3]=((int)y)/10;
shuma[2]=((int)y)%10;
shuma[1]=((int)(y*10))%10;
shuma[0]=((int)(y*100))%10;
}
void main()
{
uint16 i=0,j=0,counter=0;
TMOD =0x01; //TMOD工作方式1
TH0=0xFC; //赋初始值
TL0=0x67; //12*(65536-x)/11059200=0.001
TR0=1; //打开定时器
start_temp_sensor(); //
convert();
while(1)
{
if(1==TF0) //溢出后就刷新显示函数
{
TF0=0;
TH0=0xFC;
TL0=0x67;
counter++;
refresh();
if(1000==counter)
{
start_temp_sensor();
convert();
counter=0;
}
}