LPC213x ARM板子的DS18B20温度传感器模块添加

老大临时给了一个任务,给了我一块LPC213x的板子,叫我加上DS18B20温度传感器。本人之前是写上层应用程序的,

对ARM是一窍不通的。没办法啊,硬着头皮上。调了好几天,终于调完了,先上一个热腾腾的截图:

到的“18 4B”的十六制数据就是从温度传感器的寄存器中读出来的数值。

有关DS18B20的一些中英资料,我会在文章的末尾贴出。好了,我们开始吧。

1、关于DS18B20的简单介绍

DS18B20 温度读取函数参考步骤:

(1)DS18B20 开始转换:

1.DS18B20 复位。

2.写入跳过ROM 的字节命令,0xCC。

3.写入开始转换的功能命令,0x44。

4.延迟大约750~900 毫秒

(2)DS18B20 读暂存数据:

1.DS18B20 复位。

2.写入跳过ROM 的字节命令,0xCC。

3.写入读暂存的功能命令,0xee。

4.读入第0 个字节LS Byte,转换结果的低八位。

5.读入第1 个字节MS Byte,转换结果的高八位。

6.DS18B20 复位,表示读取暂存结束。

(3)数据求出十进制:

1.整合LS Byte 和MS Byte 的数据

2.判断符号,得到整数部分

3.得到小数部分

另外,还有最重要的时序,比如复位、读、写时序。我夹着代码尽量说清楚吧,一个一个来。


2、DS18B20复位

DS18B20 的复位时序如下:

1.单片机拉低总线480us~950us, 然后释放总线(拉高电平)。

2.这时DS18B20 会拉低信号,大约60~240us 表示应答。

3.DS18B20 拉低电平的60~240us 之间,单片机读取总线的电平,如果是低电平,那么表示复位成功。

4.DS18B20 拉低电平60~240us 之后,会释放总线。

我的LPC213x的板子(这里我不得不多说几句,对于小白程序员像我一样,一定要注意不同板子,指令是不同,所以代码不能随意copy,这样是不行的)相应复位的代码如下:

//DS18B20复位函数
void  DS18B20_Reset()
{
	//IO0CLR   // out 0
	//IO0SET   // out 1
	//IO0DIR //方向
	//IO0PIN  //read IO status  0/1
	
	IO0DIR|=DQ; //DQ 为输出状态
	IO0CLR|=DQ; //输出低电平
	Delay_1us(600); //延迟600 微秒
	IO0SET|=DQ; //释放总线,拉高电平
	Delay_1us(30); //延迟30 微秒
	IO0DIR|=DQ; //DQ 位输出状态
	Delay_1us(240); //延迟240 微秒
	if((IO0PIN&DQ) != 0){ //等待从机DS18B20 应答(低电平有效)
		IO0SET|=DQ;//释放总线
	}
}

代码注释很详细了,我这里就不多说了。


3、写时序

DS18B20写逻辑 0 的步骤如下:

(1)单片机拉低电平大约10~15us

(2)单片机持续拉低电平大约20~45us的时间

(3)释放总线

DS18B20写逻辑 1 的步骤如下:

(1)单片机拉低电平大约10~15us

(2)单片机持续拉高电平大约20~45us的时间

(3)释放总线


相应的代码:

//DS18B20 写字节函数
void DS18B20_Write(unsigned char Data)
{
	unsigned char i;
	IO0DIR|=DQ; //DQ 为输出
	for(i=0;i<8;i++)
	{
		IO0CLR|=DQ; //拉低总线
		Delay_1us(10); //延迟10微秒(最大15 微秒)
		if(Data&0x01)
			IO0SET|=DQ;
		else 
			IO0CLR|=DQ;
		Delay_1us(40); //延迟40 微秒
		IO0SET|=DQ; //释放总线
		Delay_1us(1); //稍微延迟
		Data>>=1;
	}
}


4、读时序

DS18B20 读逻辑0 的步骤如下:
1.在读取的时候单片机拉低电平大约1us
2.单片机释放总线,然后读取总线电平。
3.这时候DS18B20 会拉低电平。
4.读取电平过后,延迟大约40~45 微秒

DS18B20 读逻辑1 的步骤如下:
1.在读取的时候单片机拉低电平大约1us
2.单片机释放总线,然后读取总线电平。
3.这时候DS18B20 会拉高电平。
4.读取电平过后,延迟大约40~45 微秒


相应的代码如下:

//DS18B20 读字节函数
unsigned char DS18B20_Read()
{
	unsigned char i,Data;
	for(i=0;i<8;i++)
	{
		Data>>=1; //数据右移
		IO0DIR|=DQ; //DQ 为输出状态
		IO0CLR|=DQ; //拉低总线,启动输入
		Delay_1us(1);
		IO0SET|=DQ; //释放总线
		IO0DIR&=(~DQ); //DQ 为输入状态
		if(IO0PIN&DQ) 
			Data|=0x80;
		Delay_1us(45); //延迟45 微秒
	}
	return Data;
}


5、真正的读取温度的总函数

/***************  读温度函数*******************

数据例子:

	Tem[0]=0x1a,Tem[1]=0x32,则为正26.50摄氏度

	Tem[0]=0xb7,Tem[1]=0x4b,则为负55.75摄氏度
	
*****************************************************/
void  Read_Temperature(unsigned char *Tem)
{
	unsigned int Temp1,Temp2;
	
	DS18B20_Reset(); //DS18B20 复位
	DS18B20_Write(0xCC); //跳过ROM
	DS18B20_Write(0x44); //温度转换
	
	DS18B20_Reset(); //DS18B20 复位
	DS18B20_Write(0xCC); //跳过ROM
	DS18B20_Write(0xBE); //读取RAM
	
	Temp1=DS18B20_Read(); //读低八位,LS Byte, RAM0
	Temp2=DS18B20_Read(); //读高八位,MS Byte, RAM1
	DS18B20_Reset(); //DS18B20 复位,表示读取结束

	Convert_Data(Tem,Temp1,Temp2);//例如:Tem[0]=0x19,Tem[1]=0x00, 温度值为25.00度
	
}

到这差不多就做完了,Temp1和Temp2就是读出寄存器中的数值。可能你也注意了 Convert_Data函数,这个跟我们项目没有多大关系,主要功能就是把读到的两个字节转化成我们可读的十六进制,原因你看了资料手册就很清楚这个的重要性了。直接上代码吧,这里仅仅做为一个转换的参考。

/******************************************************************************
 把从温度传感器寄存器中16bit的数据转化为char[]保存;

  temp_str 为保存目的数组, temp1为低位寄存器数据,temp2为高位数据;
  
  将读到的整数部分(包括符号位,最高位为1是负,为0是正)  存于temp_str[0] 中;

  将读到的(2 位)小数部分(不包括小数点)存于temp_str[1] 中;
  
  转换误差0.25 摄氏度左右;

*******************************************************************************/
void Convert_Data(unsigned char *temp_str,unsigned int temp1,unsigned int temp2)
{

	unsigned int   Temp;
	unsigned int Integer_tem;//保存整数部分
	unsigned int Decimal_tem;//保存小数部分
	
	/*判断符号位*/
	if(temp2 & 0xF8){ //为负数
		Temp = ((temp2<<8)|temp1); //高8位和低8位合并
		Temp = ((~Temp)+1);//取反加1
		Temp = (Temp & 0x0000ffff);//将32位的前16位复原

		/* 得到整数部分*/
		Integer_tem = Temp;
		Integer_tem = (Integer_tem & 0x000007F0);//得到7位整数
		Integer_tem = (Integer_tem | 0x00000800);//将最高位置1(为负)
		Integer_tem = (Integer_tem>>4);              //得到8位数

		/* 得到小数部分*/
		Decimal_tem = Temp;
		Decimal_tem = (Decimal_tem & 0x0000000c);// 得到两位小数
		if(Decimal_tem == 0x00000000){//小数为 0.00
			Decimal_tem = 0x00;
		}else if (Decimal_tem == 0x00000004 ){//小数为 0.25
			Decimal_tem = 0x19;
		}else if (Decimal_tem == 0x00000008 ){//小数为0 .50
			Decimal_tem = 0x32;
		}if (Decimal_tem == 0x0000000c ){//小数0 .75
			Decimal_tem = 0x4B;
		}
	}else{              //为正数
	
		Temp = ((temp2<<8)|temp1); //高8位和低8位合并
		/* 得到整数部分*/
		Integer_tem = Temp;
		Integer_tem = (Integer_tem & 0x000007F0);//得到7位整数
		Integer_tem = (Integer_tem & 0xFFFFF7FF);//将最高位置0(为正)
		Integer_tem = (Integer_tem>>4);              //得到8位数

		/* 得到小数部分*/
		Decimal_tem = Temp;
		Decimal_tem = (Decimal_tem & 0x0000000c);// 得到两位小数
		if(Decimal_tem == 0x00000000){//小数为 0.00
			Decimal_tem = 0x00;
		}else if (Decimal_tem == 0x00000004 ){//小数为 0.25
			Decimal_tem = 0x19;
		}else if (Decimal_tem == 0x00000008 ){//小数为0 .50
			Decimal_tem = 0x32;
		}if (Decimal_tem == 0x0000000c ){//小数0 .75
			Decimal_tem = 0x4B;
		}
		
	}

	temp_str[0] = Integer_tem;//将整数部分存于第1个元素中
	temp_str[1] = Decimal_tem;//将小数部分存于第2个元素中
	
}

另外再加上一些头文件,这是自己定义的,对你们一点作用都没有。要把引脚宏定义好,因为你只能联接DS18B20的引脚操作。

//DS18B20 DQ 引脚对应的链接,为P0.23
#define   DQ    ANT4_LED    //(1<<23)


/*延迟1微秒时间函数*/
void Delay_1us(unsigned int  iTime)
{
	    unsigned int i,j ;
	    for(i=0;i<iTime;i++)
	    {
	        for(j=0;j<10;j++);
	    }
}

再多说很重要的两句,这个Delay_1us函数得自己用示波器把这个时间调在误差范围之内,因为ARM 嵌入式机器对时序要求很高

有关DS18B20的中英文资料http://download.csdn.net/detail/yanyuanfen2011/6558677

有什么问题欢迎大家留言交流!



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值