单总线器件DS18B20温度传感器

DS18B20的代码有很多,这篇的代码主要参考自美信公司的应用笔记。proteus仿真时对时不对的,实在搞不懂为嘛。程序中除了基本的读取温度外还有搜索1-wire器件算法,读取1-wire器件EEPROM/高速缓存的算法。这些算法中有一点需要注意,由于温度转换需要较长时间至少750MS,因此启动温度转换到实际读取温度值需要延时,否则将无法正确读到温度值。这是我痛苦的经历,因为美信公司的应用手册上没有调用延时函数,因此一直获取不到温度值。此处加以记录希望下次不要重蹈覆辙。

#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit DS=P2^2;           //define interface

void delay(int us)
{
	int i;
	for(i=0;i<us;i++);
}

void delayMs(int Ms)
{
	int i,j;
	for(i=0;i<Ms;i++)
		for(j=0;j<100;j++);
}

unsigned char resetSingleBus()
{
	unsigned char presence;
	DS = 0; //pull DQ line low
	delay(29); // leave it low for 480us
	DS = 1; // allow line to return high
	delay(3); // wait for presence
	presence = DS; // get presence signal
	delay(25); // wait for end of timeslot
	return presence; // presence signal returned
}

unsigned char readBit()
{
	int i;
	unsigned char dat;
	DS = 0;
	DS = 1;
	for(i=0;i<3;i++);
	dat = DS;

	return dat;
}

unsigned char readByte()
{
	int i,j,dat;
	dat = 0;
	for(i=0;i<8;i++)
	{
		if(readBit())
		{
			dat |= 0x01<<i;
		}
		delay(6);
	}
	return dat;
}

void writeBit(unsigned char val)
{
	DS = 0;
	if(val == 1)
	{
		DS = 1;
	}
	delay(5);
	DS = 1;
}

void writeByte(unsigned char val)
{
	int i, tmp;
	for(i=0;i<8;i++)
	{
		tmp = val>>i;
		tmp &= 0x01;
		writeBit(tmp);
	}
	delay(5);
}

//读高速缓存
unsigned int temp_c;
void Read_Temperature(void)
{
	char get[10];
	char temp_lsb,temp_msb;
	int k;
	char temp_f;
	resetSingleBus();
	writeByte(0xCC); //Skip ROM
	writeByte(0x44); // Start Conversion
	delayMs(800);		 //750ms 转换时间
	resetSingleBus();
	writeByte(0xCC); // Skip ROM
	writeByte(0xBE); // Read Scratch Pad
	delayMs(800);		 //750ms 转换时间
	for (k=0;k<9;k++)
	{
		get[k]=readByte();
	}
	//printf("\n ScratchPAD DATA = %X%X%X%X%X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
	temp_msb = get[1]; // Sign byte + lsbit
	temp_lsb = get[0]; // Temp data plus lsb
	if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree
	temp_msb = temp_msb & 0x80; // mask all but the sign bit
	if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement
	if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree
	if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit
	//printf( "\nTempC= %d degrees C\n", (int)temp_lsb ); // print temp. C
	temp_c = temp_lsb; // ready for conversion to Fahrenheit
	temp_f = (((int)temp_c)* 9)/5 + 32;
//	printf( "\nTempF= %d degrees F\n", (int)temp_f );
}

//rom
void ReadROMCode(void)
{
	int n;
	char romCode[9]={0};
	resetSingleBus() ;
	writeByte(0x33) ;
	for (n=0; n<8; n++)
	{
		romCode[n] = (char)readByte(); 
	}

	romCode[8]=0x00;
}

void ReadScratchPad(void)
{
	int j ;
	char padCode[10]={0};
	writeByte(0xBE);
	delayMs(800);
	for(j =0; j <8; j ++)
	{
		padCode[j] = readByte(); 
	}
}

unsigned char ROM[8];
unsigned char FoundROM[5][8];
unsigned char lastDiscrep=0;
unsigned char doneFlag=0;
unsigned char numROMs;
unsigned char dowcrc;
unsigned char code dscrc_table[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};

unsigned char ow_crc( unsigned char x)
{
	dowcrc = dscrc_table[ dowcrc^x] ;
	return dowcrc;
}

// NEXT
// The Next function searches for the next device on the 1-Wire bus. If
// there are no more devices on the 1-Wire then 0 is returned.
//
unsigned char Next(void)
{
	unsigned char m = 1; // ROM Bit index
	unsigned char n = 0; // ROM Byte index
	unsigned char k = 1; // bit mask
	unsigned char x = 0;
	unsigned char discrepMarker = 0; // discrepancy marker
	unsigned char g; // Output bit
	unsigned char nxt; // return value
	int flag;
	char dowcrc = 0; // reset the dowcrc
	nxt = 0; // set the next flag to 0
	flag = resetSingleBus() ; // reset the 1-Wire
	if(flag||doneFlag) // no parts -> return 0
	{
		lastDiscrep = 0; // reset the search
		return 0;
	}
	writeByte(0xF0) ; // send SearchROM command
	delayMs(10);
	do
	// for all eight bytes
	{
		x= 0;
		if(readBit() ==1)
			x = 2;
		
		if(readBit() ==1) 
			x |= 1; // and its complement
		if(x ==3) // there are no devices on the 1-Wire
			break;
		else
		{
			if(x>0) // all devices coupled have 0 or 1
				g = x>>1; // bit write value for search
			else
			{
				// if this discrepancy is before the last
				// discrepancy on a previous Next then pick
				// the same as last time
				if(m<lastDiscrep)
					g = ((ROM[n]&k) >0) ;
				else // if equal to last pick 1
					g = (m==lastDiscrep) ; // if not then pick 0
				// if 0 was picked then record
				// position with mask k
				if (g==0)
					discrepMarker = m;
			}
			if(g==1) // isolate bit in ROM[ n] with mask k
				ROM[n] |= k;
			else
				ROM[ n] &= ~k;
			writeBit(g) ; // ROM search write
			m++; // increment bit counter m
			k = k<<1; // and shift the bit mask k
			if(k==0) // if the mask is 0 then go to new ROM
			{ // byte n and reset mask
				ow_crc(ROM[n] ) ; // accumulate the CRC
				n++; k++;
			}
		}
	}while(n<8) ; //loop until through all ROM bytes 0-7
	if(m<65||dowcrc) // if search was unsuccessful then
		lastDiscrep=0; // reset the last discrepancy to 0
	else
	{// search was successful, so set lastDiscrep,
	// lastOne, nxt
	lastDiscrep = discrepMarker;
	doneFlag = (lastDiscrep==0) ;
	nxt = 1; // indicates search is not complete yet, more
	// parts remain
	}
	return nxt;
}

unsigned char First(void)
{
	lastDiscrep = 0; // reset the rom search last discrepancy global
	doneFlag = 0;
	return Next() ; // call Next and return its return value
}

void FindDevices(void)
{
	unsigned char m;
	if(!resetSingleBus() ) //Begins when a presence is detected
	{
		if(First() ) //Begins when at least one part is found
		{
			numROMs=0;
			do
			{
				numROMs++;
				for(m=0; m<8; m++)
				{
					FoundROM[ numROMs] [ m] =ROM[ m] ; //Identifies ROM
					//number on found device
				}
			}while(Next()&&(numROMs<2)); //Continues until no additional devices are found
		}
	}
}

unsigned char Send_MatchRom(void)
{
	unsigned char i;
	if(resetSingleBus())
		return 0;
	writeByte(0x55) ; // match ROM
	for(i=0; i<8; i++)
	{
		writeByte(FoundROM[0][i] ) ; //send ROM code
	}
	return 1;
}

void main()
{

	do
	{
		resetSingleBus();
		First();
		FindDevices();
		ReadROMCode();
		Read_Temperature();
		ReadScratchPad();
	}while(1);
}


resetSingleBus/First/FindDevices/ReadRomCode/ReadScratchPad依次是复位/搜索第一个1wire器件/搜索EEPROM/搜索告诉缓存

下图为我的仿真图

单总线器件DS18B20温度传感器_第1张图片

下图为设置DS18B20传感器的EEPROM/高速缓存,MCU运行时即可设置:

单总线器件DS18B20温度传感器_第2张图片

DS18B20的64BROM在MCU尚未仿真时设置:

单总线器件DS18B20温度传感器_第3张图片

参考文档:Interfacing the DS18X20_DS1822 1-Wire® Temperature Sensor in a Microcontroller Environment - Application Note - Maxim.pdf

你可能感兴趣的:(传感器,单片机)