多路DS18B20读取

        DS18B20作为一个单总线温度传感器估计大家都比较熟悉,但通常情况下都只是总线上挂一个18B20。实际应用中难免会用到多点测温,我在工作中就遇到了这样的情况。

对于多次安测温,可能大家首先想到的是把18B20都挂在单总线上,毕竟单总线也是总线啊,理论上可以和总线上的任意一个元器件通信。但当我读取了官方的文档之后就放弃了这种方式。例如我的项目需要测量不同环境下的6个点的温度,如果通过读取rom序列码来确定具体某个点(例如2点)的温度,那么事先就必须知道控制器读取的rom序列码是否就是2点的器件,在实际生产中也不可能会每个18B20的序列码都写进程序或者写一段对应序列码与器件的程序,那样就太复杂了。我所选的控制器管脚比较多,所以完全没有必要用一根总线读取的方式。

   既然不用单总线挂多个器件的方式,那就只能用多个IO口,每个IO口挂一个器件的方式。因为手头有一个18B20的例程,所以首先想到的是把IO口作为变量,然后一个一个的读出多个IO上的18B20数据。可是结果却是让人头疼,因为总会有一个或者218B20会出现CRC校验错误或者不能识别器件(控制器下拉480us后没有收到18B20的回复)的情况。这就比较头大了,都是同一个程序,只是改变了管脚而已,读数出错,还是偶尔出错,根本无从查起,无从下手啊。只可能是控制器的中断影响了18B20的时序了。

   多方查找资料解决这个问题,结果还真被我找到一篇比较有用的文章http://blog.csdn.net/dldw8816/article/details/45170283;他里面介绍了一种并口同时读取的方式让我眼前一亮。这样就方便多了啊,可以在读取数据的时候禁用中断,不就解决问题了吗(之前的逐一读取时禁用中断会影响其他测功能,因为我的项目6个点温度可能导致禁用中断次数太多)?这里面涉及到的最后数据处理的问题那篇文章里面也有介绍。但是我并不只是读取温度数据,我还读取了温度的CRC校验数据,所以数据的处理上跟他文章中的方法有点出入。下面是关键函数代码:

 

u8 DS18B20_Read2Byte(void)    // read one byte
{        
    u8 i,j,k=0,Mask,m=0,n=0,dat=0;
    u8 temp_buff[72] = {0};

#if SYSTEM_SUPPORT_OS
	OS_ERR err;
	//CPU_SR_ALLOC();
	OSSchedLock(&err);							//UCOSIII的方式,禁止调度,防止打断
	//OS_CRITICAL_ENTER();	//进入临界区
#endif
//    dat=0;
//	for (i=1;i<=8;i++)
//	{
//        j=DS18B20_Read_Bit();
//        dat=(j<<7)|(dat>>1);
//    }

	for(i=0; i<=71; i++)
	{
		temp_buff[i] = DS18B20_Read_Bit();
	}

#if SYSTEM_SUPPORT_OS
	OSSchedUnlock(&err);						//UCOSIII的方式,恢复调度
	//OS_CRITICAL_EXIT();	//退出临界区
#endif

	for(j=0; j<9; j++)
	{
		for(i=0;i<8;i++)
		{
			m = j*8+i;		//m表示bit位
			Mask = 0x01;
			for(k=0; k<8; k++)
			{				
				if(temp_buff[m]&Mask) n=1;
				else	n=0;
				
				read_buff[k][j] = (n<<7)|(read_buff[k][j]>>1);
				
				Mask <<= 1;
			}
		}
	}

    return dat;
}

   因为我的工程用了ucosiii,所以读取18B20那段加了禁止调度函数。如果大家没有用系统,可以直接换成禁用中断的函数。这里是8路温度数据,每路9byte的寄存器数据,所以用了u8 read_buff[8][9]的全局变量。9byte8*9=72bit,所以用了u8 temp_buff[72]来存放读取的8路温度数据,然后再转换成一般格式数据u8 read_buff[8][9],最后再每路通道校验CRC,看是否存在错误数据。

   以上为我在使用18B20时的心得,如有错误,欢迎指正。


你可能感兴趣的:(元件驱动)