第九章:DS18B20

重点是协议的方式:单总线协议

重点是:协议中的时间间隔问题


外部线路

初始化步骤:

mintime-----maxtime(480-960)低电平时间

之后进入等待时间(15us-60us)将单总线拉高,看从设备是否将总线从新拉低

/*********************************************************************
* 函 数 名       : Ds18b20Init
* 函数功能		 : 按照DS18B20底层时序要求进行传感器初始化
* 参数列表       : 无
* 函数输出    	 : 若初始化成功则返回0,否则返回1
*********************************************************************/
static u8 Ds18b20Init(void)
{
	u8 i = 0;

	gIO = 0;			// 时序要求将总线拉低480us~960us
	delay750us();		// 实际延时750us,符合480-960之间的条件
	gIO = 1;			// 然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线被拉低

	i = 0;
	while (gIO)			// 等待DS18B20拉低总线
	{
		i++;
		if(i>5)			// 等待 15*5=75us,如果还没拉低则可以认为初始化失败了
		{
			return 1;	// 初始化失败
		}
		delay15us();	// 隔15us查看一下是否收到DS18B20的回应
	}
	return 0;			//初始化成功
}

我们先看写字节

先15us内将要写入的数据拉低或拉高

然后通过从设备的pin来采集。最后采集完之后要释放总线等待下一个bit的写操作(这里显示的一个写周期在60us)

/*********************************************************************
* 函 数 名       : Ds18b20WriteByte
* 函数功能		 : 按照DS18B20底层时序要求向DS18B20写入1字节数据
* 参数列表       : dat - 待写入的1字节数据
* 函数输出    	 : 无
*********************************************************************/
static void Ds18b20WriteByte(u8 dat)
{
	u16 i = 0, j = 0;

	for (j=0; j<8; j++)
	{
		gIO = 0;	     	  	// 每写入一位数据之前先把总线拉低1us
		i++;
		gIO = dat & 0x01;  		// 然后写入一个数据,从最低位开始
		delay70us();			// 时序要求最少60us
		gIO = 1;				// 然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
		dat >>= 1;
	}
}

/*********************************************************************
* 函 数 名       : Ds18b20ReadByte
* 函数功能		 : 按照DS18B20底层时序要求从DS18B20中读取1字节数据
* 参数列表       : 无
* 函数输出    	 : 返回读取到的1字节数据
*********************************************************************/
u8 Ds18b20ReadByte(void)
{
	u8 byte = 0, bi = 0;
	u16 i = 0, j = 0;
		
	for (j=8; j>0; j--)
	{
		gIO = 0;		// 先将总线拉低1us
		i++;
		gIO = 1;		// 然后释放总线
		i++;
		i++;			// 延时6us等待数据稳定
		bi = gIO;	 	// 读取数据,从最低位开始读取
		/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
		byte = (byte >> 1) | (bi << 7);	
		//byte |= (bi << (8-j));
		delay45us();
	}				
	return byte;
}

/*************** 高层时序 *************************************/

void Ds18b20TempConvertCmd(void)
{
	Ds18b20Init();
	delay1ms();
	Ds18b20WriteByte(0xcc);		// 跳过ROM操作命令		 
	Ds18b20WriteByte(0x44);	    // 温度转换命令
	delay750ms();			    // 等待转换成功,750ms肯定够了
}

 

 

void Ds18b20TempReadCmd(void)
{	
	Ds18b20Init();
	delay1ms();
	Ds18b20WriteByte(0xcc);	 	// 跳过ROM操作命令
	Ds18b20WriteByte(0xbe);	 	// 发送读取温度命令
}

 

//应用

void TempDisplayTest(void)
{
	u16 temp = 0;	 				// 用来暂存12位的AD值
	u8 tmh = 0, tml = 0;			// 用来暂存2个8位的AD值
	u16 tDisp = 0;					// 用来存储乘以100倍后的温度值
	double t = 0;					// 用来存储转换后以摄氏度为单位的温度值

	Ds18b20TempConvertCmd();		// 先写入转换命令
	Ds18b20TempReadCmd();			// 然后等待转换完后发送读取温度命令
	tml = Ds18b20ReadByte();		// 读取温度值共16位,先读低字节
	tmh = Ds18b20ReadByte();		// 再读高字节

	temp = tml | (tmh << 8);		// 默认是12位分辨率,前面4个S位是符号位
	
	// 正温度时符号位为0,下面代码计算没有考虑负温度情况,因为我们实验是在
	// 室温下做的,如果要考虑到负温度的情况,代码中要先判断S位,若S位为1则
	// 必须点去掉S的1再计算,计算后的值加负号即可。
	t = temp * 0.0625;
	tDisp = (u16)(t * 100);			// 为方便显示将温度值乘以100后强转为u16

	// 调用LCD1602的显示函数来显示乘以100倍后的温度值
	Lcd1602ShowTempU16(0, 0, tDisp);
}
/*********************************************************************
* 函 数 名       : Lcd1602ShowTempU16
* 函数功能		 : 从坐标(x,y)开始显示被乘以100倍之后的U16类型的温度值
				   注意中间加入了小数点的显示。
* 参数列表       : x - 横向坐标,范围是0-15
*				   y - 纵向坐标,0表示上面一行,1表示下面一行
*				   temp - 待显示的u16类型的温度值
* 函数输出    	 : 无
*********************************************************************/
void Lcd1602ShowTempU16(u8 x, u8 y, u16 temp)     
{
	u8 d = 0;

    Lcd1602SetCursor(x, y);		// 当前字符的坐标
    
	d = temp / 1000;			// temp开始为4位数,取出最高位
	temp %= 1000;				// temp中剩下后3位
	Lcd1602WriteData(d + '0');	// 显示最高位数字

	d = temp / 100;				// temp开始为3位数,取出最高位
	temp %= 100;				// temp中剩下后2位
	Lcd1602WriteData(d + '0');	// 显示最高位数字

	Lcd1602WriteData('.');		// 显示小数点

	d = temp / 10;				// temp开始为2位数,取出最高位
	temp %= 10;					// temp中剩下后1位
	Lcd1602WriteData(d + '0');	// 显示最高位数字

	d = temp;					// temp剩余1位数字,直接显示即可
	Lcd1602WriteData(d + '0');	// 显示最高位数字

	Lcd1602WriteData(0xdf);		// 显示摄氏度的小圆圈
	Lcd1602WriteData('C');		// 显示摄氏度的大写C
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值