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传感器的EEPROM/高速缓存,MCU运行时即可设置:
DS18B20的64BROM在MCU尚未仿真时设置:
参考文档:Interfacing the DS18X20_DS1822 1-Wire® Temperature Sensor in a Microcontroller Environment - Application Note - Maxim.pdf