DS18B20 驱动示例 STC_51单片机 温度传感器

目录

前言

         上次学习了EC11开关编码器的使用,这次来学习DS18B20基础的使用方法,虽然过程有点波折,但是成功显示温度的那一刻,那种感受却是无比喜悦的。

一、DS18B20简介

        这东西用来干嘛的就不用多说了吧,反正不是三极管。说下器件本身的几个特点:

1、两种供电模式:

        A寄生电源供电。

        B外部电源供电。

2、两种连接模式:

        A单个独立工作。

        B多个并联在一条总线上工作。

3、通讯协议:1wire总线。

        1、复位(检测存在脉冲)

        2、写间隙(生成下降沿后写)

        3、读间隙(生成上升沿后读)

        4、读写顺序:低位在前

4  、本次学:外部电源、单个独立工作。

        原理图就不讲了:数据脚给个2-10k的上拉电阻,正负脚不接反就行。

二、工作过程:

简单来说分三步(发命令前均需初始化):

        1、采集温度(自动)。

        2、转换温度(发命令)。

        3、输出温度(发命令读取数据)。

详细点说分十步:

        1、初始化(检测通讯是否正常)。

        2、发送跳过编码命令(0xCC)。

        3、发送温度转换命令(0x44)。

        4、等待时间95ms-750ms,转换完成。

        5、初始化(检测通讯),每次都必须做。

        6、发送跳过编码命令(0xCC)。

        7、发送温度读取命令(0xBE)。

        8、读取温度寄存器低字节(低位先读)。

        9、读取温度寄存器高字节(低位先读)。

        10、将两字节数据合成16位整型数据。

本次只用到了三个命令:

        Skip ROM: 0xCCH(跳过编码)

        Convert_T: 0x44H(温度转换)

        Read Scratchpad: 0xBEH(读暂存器即存温度数据的地方)

三、更详细的操作流程一张图解释:

四、 怎么初始化(复位/检测脉冲):

操作流程:

        MCU将数据线拉低-

        等待500us(480-960)-

        MCU拉高-等待50us(15-60) -

        读取数据线的值给ACK(低电平正常) -

        等待高电平来到结束检测-

        返回 ACK的值判断初始化(复位)结果。

        下面是初始化函数:

/************************************************************************
功能描述:18B20初始化
入口参数:
返回数据:ACK 即复位结果
备注:		TEMP 为总线IO口
************************************************************************/

bit Init_18b20()	    //初始化
{
	bit ACK;			//初始化结果变量声明

	EA = 0;			   	//关中断
	TEMP = 0;		   	//总线拉低
	Delay500us();	    //延时500
	TEMP = 1;		   	//拉高
	Delay100us();	    //延时100
	ACK = TEMP;		    //检测存在脉冲
	while(!TEMP);	    //等待存在脉冲结束
	EA = 1;		 	   	//关中断
	return ACK;		    //返回存在脉冲结果
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

上面是初始化部分处理 

五、怎么发命令?怎么读数据?看手册:

        这个就真不好用文字表达了,毕竟图片的信息量更大更清楚。配合代码可能会更好理解。不过有一点特别值得注意,就是在读取前的那一刻,必须保证你没有从MCU输出低电平,我可是被这个读时序图给坑惨了,按我的理解这个读取的时序图是不那么恰当的,新手(就是我)容易被误导,准备读取前数据前数据总线必须是高电平才能正常工作。这个读时序图展示的显然不是这样的。有其他意见的欢迎指正哈。

        下面是写一个字节的函数:

/************************************************************************
功能描述:向18B20写一个字节
入口参数:cmd 即要输入的命令
返回数据:
备注:    TEMP 为总线IO口
************************************************************************/
void Write_18b20(uint8 cmd)
{
	unsigned char mask;

	EA = 0;			   		//关中断
	for(mask=0x01;mask!=0;mask<<=1)
	{
		TEMP = 0;	   		//拉低总线
		Delay10us();	    //延时10
		if((mask&cmd)==0)	
			TEMP = 0;  		//写低电平
		else
			TEMP = 1;  		//写高电平
		Delay50us();   	    //延时50
		TEMP = 1;	   		//释放总线
	}
	EA = 1;			   		//关中断
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

        下来是读取一个字节函数:

/************************************************************************
功能描述:向18B20读一个字节
入口参数:
返回数据:
备注:    TEMP 为总线IO口
************************************************************************/
unsigned char Read_18b20()
{
	uint8 i = 8;
	uint8 dat;

	EA = 0;					//关中断
	while(i--)
	{
		TEMP = 0;			//拉低总线
		_nop_();			//延时2
		TEMP = 1;			//释放总线
		Delay10us();	    //延时10us
		if(TEMP)			//接收1
		{			
			dat >>= 1;
			dat |= 0x80; 		
		}
		else			    //接收0
		{
			dat >>= 1;	
		}	
		Delay50us();	    //延时60
	}
	EA = 1;					//关中断

	return dat;			    //返回数据
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

        再下来是启动温度转换部分代码:

/************************************************************************
功能描述:启动温度转换并返回存在结果
入口参数:
返回数据:
备注:
************************************************************************/
bit Start_18b20()
{
	bit ACK;
	
	ACK = Init_18b20();		//初始化读存在脉冲
	if(ACK == 0)					//收到存在脉冲进行下一步
	{				
		Write_18b20(0xCC);  //Skin_ROM//只能但从机使用该指令
		Write_18b20(0x44);  //Convert_T启动温度转换命令
	}
	return ~ACK;		
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

        接着获取温度寄存器中的数据:

/************************************************************************
功能描述:获取温度寄存器中的值
入口参数:
返回数据:
备注:
************************************************************************/
bit Get18b20temp(uint16 *temp)	//获取温度
{
	bit ACK;
	
	uint8 LSB;						//温度接收缓存低字节
	uint8 MSB;						//温度接收缓存高字节

	ACK = Init_18b20();
	if(ACK == 0)
	{		   
		Write_18b20(0xCC); 	//Skin_ROM
		Write_18b20(0xBE); 	//写读暂存寄存器命令
		LSB = Read_18b20();	//读暂存LSB中的温度数据
		MSB = Read_18b20();	//读暂存MSB中的温度数据
	}
	*temp = ((int)MSB <<8 ) + LSB;	//合成温度数据
	return ACK;	
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

 六、怎么转换温度?先看数据手册

 数据手册真的超级重要,第一时间看数据手册

        看上图就可以知道,数据的长读一共是16位,其中最高的5位(我思维导图说4位其实无所谓哈不影响最终结果最主要是懒得改了)任意一位都可以用来判断温度的正负,最低四位是表示温度的小数的转换过程上面说过了哈,或者可以参考下后面的转换代码。

        举个负数的例子吧:例如 -10.125度,负温度要先将数据转换成补码再计算

FF5EH 的补码 = FF5EH 的反码 +1 = 00A2H     

        所以:

温度整数 = 00A0H *精度 = 160*0.0625 = 10

        或者直接右移四位的值就是温度整数

温度整数 = (00A2H>>4) = 00AH = 10

温度小数 = 0002H *精度 = 2*0.0625 = 0.125

        下面是转换代码:

/************************************************************************
功能描述:获取温度并将温度转换成十进制送到数码管缓冲区或转换成字符串
入口参数:
返回数据:
备注:
************************************************************************/
void Temp_translate()
{
    uint8 temp_buf;				    //整数温度缓存
	uint8 symbol;					//符号缓存
	uint8 th = 0;					//数据高四位
	uint8 tm = 0;					//整数部分源码
	uint16 tl = 0;				    //小数温度缓存
	uint16 temp;					//温度源码缓存
	
	Get18b20temp(&temp);				//获取温度
	th = (uint8)(temp>>12);				//取数据高四位
	tm = (uint8)((temp&0x0FF0)>>4);		//取温度整数值
	tl = temp&0x000F;					//取温度小数值
	tl = tl*625/1000; 					//只留一位并放大十倍
	if(th)	//高四位大于0说明是负数
	{
		symbol = '-';					//标记符号字符
		temp_buf = 256-tm;				//取整数温度
	}
	else
	{
		symbol = ' ';					//正数不显示
		temp_buf = tm;					//取整数温度
	}
	//共阳数码管显示部分
	smg_buf[0] = Smg_Char[12];			//温度符号
	smg_buf[1] = Smg_Char[tl];					//温度小数
	smg_buf[2] = Smg_Char[temp_buf%10];			//温度个位
	smg_buf[2] &= 0x7F;	//小数点
	smg_buf[3] = Smg_Char[temp_buf/10%10];	    //温度十位
	//LCD1602显示部分
	lcd_buf[0] = symbol;
	lcd_buf[1] = (temp_buf/10%10) + '0';		//
	lcd_buf[2] = (temp_buf%10) + '0';			//
	lcd_buf[3] = '.';							//
	lcd_buf[4] = tl + '0';						//
	lcd_buf[5] = 'c';							//
	lcd_buf[6] = '\0';							//
}
/************************************************************************
 ----------------------------秋末的蒲公英-------------------------------
************************************************************************/

以上仅是DS18B20驱动代码

七、结尾来看实验结果

四位数码管显示

LCD1602液晶显示 

秋末的蒲公英_-CSDN博客

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,这是一个关于STC15F2K60S2单片机使用ds18b20在1602显示屏显示温度的问题。下面是一个简单的程序示例,供参考: ```c #include <reg51.h> #include <intrins.h> #define DS18B20_PORT P2 #define DS18B20_DQ P2_0 #define LCD_RS P0_0 #define LCD_RW P0_1 #define LCD_E P0_2 #define LCD_DAT P0 unsigned char code LCD_INIT_TBL[] = {0x38, 0x0c, 0x06, 0x01, 0x80}; unsigned char code DS18B20_SKIP_ROM[] = {0xcc, 0x44}; unsigned char code DS18B20_READ_SCRATCHPAD[] = {0xcc, 0xbe}; void lcd_init(); void lcd_clear(); void lcd_write_cmd(unsigned char cmd); void lcd_write_data(unsigned char dat); void lcd_write_str(unsigned char *str); void delay_ms(unsigned int t); void ds18b20_reset(); void ds18b20_write_byte(unsigned char dat); unsigned char ds18b20_read_byte(); int ds18b20_read_temp(); void main() { unsigned int temp; lcd_init(); lcd_write_str("Temperature:"); while (1) { temp = ds18b20_read_temp(); lcd_write_cmd(0x80 + 0x0c); lcd_write_data(temp / 10 + '0'); lcd_write_data(temp % 10 + '0'); lcd_write_data('C'); delay_ms(1000); } } void lcd_init() { unsigned char i; LCD_DAT = 0x00; LCD_RW = 0; LCD_RS = 0; LCD_E = 0; delay_ms(15); for (i = 0; i < sizeof(LCD_INIT_TBL); i++) { lcd_write_cmd(LCD_INIT_TBL[i]); } } void lcd_clear() { lcd_write_cmd(0x01); delay_ms(2); } void lcd_write_cmd(unsigned char cmd) { LCD_DAT = cmd; LCD_RW = 0; LCD_RS = 0; LCD_E = 1; _nop_(); _nop_(); LCD_E = 0; delay_ms(2); } void lcd_write_data(unsigned char dat) { LCD_DAT = dat; LCD_RW = 0; LCD_RS = 1; LCD_E = 1; _nop_(); _nop_(); LCD_E = 0; delay_ms(2); } void lcd_write_str(unsigned char *str) { while (*str) { lcd_write_data(*str++); } } void delay_ms(unsigned int t) { unsigned int i, j; for (i = 0; i < t; i++) { for (j = 0; j < 110; j++); } } void ds18b20_reset() { DS18B20_DQ = 1; _nop_(); DS18B20_DQ = 0; delay_ms(20); DS18B20_DQ = 1; delay_ms(20); } void ds18b20_write_byte(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { DS18B20_DQ = 0; _nop_(); DS18B20_DQ = dat & 0x01; delay_ms(2); DS18B20_DQ = 1; dat >>= 1; } } unsigned char ds18b20_read_byte() { unsigned char i, dat = 0; for (i = 0; i < 8; i++) { DS18B20_DQ = 0; _nop_(); DS18B20_DQ = 1; _nop_(); dat |= DS18B20_DQ << i; delay_ms(2); } return dat; } int ds18b20_read_temp() { unsigned char high, low; int temp; ds18b20_reset(); ds18b20_write_byte(DS18B20_SKIP_ROM[0]); ds18b20_write_byte(DS18B20_SKIP_ROM[1]); ds18b20_write_byte(DS18B20_READ_SCRATCHPAD[0]); ds18b20_write_byte(DS18B20_READ_SCRATCHPAD[1]); low = ds18b20_read_byte(); high = ds18b20_read_byte(); temp = high; temp <<= 8; temp |= low; temp *= 625; temp /= 100; return temp; } ``` 这个程序使用的是STC15F2K60S2单片机,通过DS18B20温度传感器读取温度值,并在1602液晶显示屏上显示出来。程序中涉及到了LCD1602显示屏和DS18B20温度传感器的读写操作,需要根据具体的硬件连接进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值