天天看點

單總線器件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溫度傳感器

下圖為設定DS18B20傳感器的EEPROM/高速緩存,MCU運作時即可設定:

單總線器件DS18B20溫度傳感器