51单片机DS18B20温度传感器

    xiaoxiao2021-12-14  16

    /* 用的是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); shuma[1]=((int)(y*10)); shuma[0]=((int)(y*100)); } 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; } }

     

    转载请注明原文地址: https://ju.6miu.com/read-961469.html

    最新回复(0)