Jednoduchá OneWire komunikace s DS18B20

Dobrý den ve spolek, rád bych rozchodil 1Wire komunikaci s DS18B20. Koukal jsem už po netu ale všude jsou jenom složité příklady s víc jak jednim čidlem a identifikací cenzorů a bohužel nejsem an takvé úrovni abych těm kódum porozumněl. Takže by se mi hodilo něco jednoduchého alespoň pro navázání komunikace a přečtení hodnoty, data si budu posílat UARTem do PC. Popřípadě nějaká knihovnička by byla fajn :slight_smile:
PS: Koukal jsem i do zdrojáku v sekci Download a stejně moc HardCore na mě :smiley:

Také nejsem expert, proto používam překladačmikroC PRO for AVR
mikroe.com/eng/products/view/228/mikroc-pro-for-avr/

a tam to jde uplně jednoduše, dokonce tam je i help přímo k tomuto tep. čidlu s připojeným LCD

// LCD module connections
sbit LCD_RS at PORTD2_bit;
sbit LCD_EN at PORTD3_bit;
sbit LCD_D4 at PORTD4_bit;
sbit LCD_D5 at PORTD5_bit;
sbit LCD_D6 at PORTD6_bit;
sbit LCD_D7 at PORTD7_bit;

sbit LCD_RS_Direction at DDD2_bit;
sbit LCD_EN_Direction at DDD3_bit;
sbit LCD_D4_Direction at DDD4_bit;
sbit LCD_D5_Direction at DDD5_bit;
sbit LCD_D6_Direction at DDD6_bit;
sbit LCD_D7_Direction at DDD7_bit;
// End LCD module connections

// Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20 sensor:
// 18S20: 9 (default setting; can be 9,10,11,or 12)
// 18B20: 12

const unsigned short TEMP_RESOLUTION = 9;

char *text = “000.0000”;
unsigned temp;

void Display_Temperature(unsigned int temp2write) {
const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
char temp_whole;
unsigned int temp_fraction;

// check if temperature is negative
if (temp2write & 0x8000) {
text[0] = ‘-’;
temp2write = ~temp2write + 1;
}

// extract temp_whole
temp_whole = temp2write >> RES_SHIFT ;

// convert temp_whole to characters
if (temp_whole/100)
text[0] = temp_whole/100 + 48;
else
text[0] = ‘0’;

text[1] = (temp_whole/10)%10 + 48; // Extract tens digit
text[2] = temp_whole%10 + 48; // Extract ones digit

// extract temp_fraction and convert it to unsigned int
temp_fraction = temp2write << (4-RES_SHIFT);
temp_fraction &= 0x000F;
temp_fraction *= 625;

// convert temp_fraction to characters
text[4] = temp_fraction/1000 + 48; // Extract thousands digit
text[5] = (temp_fraction/100)%10 + 48; // Extract hundreds digit
text[6] = (temp_fraction/10)%10 + 48; // Extract tens digit
text[7] = temp_fraction%10 + 48; // Extract ones digit

// print temperature on LCD
Lcd_Out(2, 5, text);
}

void main() {

Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear LCD
Lcd_Cmd(_LCD_CURSOR_OFF); // Turn cursor off
Lcd_Out(1, 1, " Temperature: ");
// Print degree character, ‘C’ for Centigrades
Lcd_Chr(2,13,223); // Different LCD displays have different char code for degree
// If you see greek alpha letter try typing 178 instead of 223

Lcd_Chr(2,14,‘C’);

//— main loop
do {
//— perform temperature reading
Ow_Reset(&PORTB, 2); // Onewire reset signal
Ow_Write(&PORTB, 2, 0xCC); // Issue command SKIP_ROM
Ow_Write(&PORTB, 2, 0x44); // Issue command CONVERT_T
Delay_us(120);

Ow_Reset(&PORTB, 2);
Ow_Write(&PORTB, 2, 0xCC);                  // Issue command SKIP_ROM
Ow_Write(&PORTB, 2, 0xBE);                  // Issue command READ_SCRATCHPAD
Delay_ms(400);

temp =  Ow_Read(&PORTB, 2);
temp = (Ow_Read(&PORTB, 2) << <img src="/uploads/default/original/1X/ae031e9834d19166598edd060b063d44f1829139.gif" width="15" height="15" alt="8)" title="Cool"/> + temp;

//--- Format and display result on Lcd
Display_Temperature(temp);

Delay_ms(500);

} while (1);
}

Jo to je přesně to co jsem teď dodělal, ale jelikoiž mám nedostatek LCD displayu tak sem tomu dal posílat data na UART a malinko sem to potunil pro čtení až z 8 čidel na 8 drátech :slight_smile: teoreticky by šlo využít všech IO pinů pro připojení čidel. Ale věřim že 8 mi bude stačit. I přesnost sem ořezal na 1 desetinné místo. Ale chtěl bych na to přijít i v obyčejným nenaboostovaným C :smiley:
Tady je upravený Kód pro MikroC:

char uart_rd;
const unsigned short TEMP_RESOLUTION = 12;

char *text = "000.0";
unsigned temp;


void Display_Temperature(unsigned int temp2write) {
  const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
  char temp_whole;
  unsigned int temp_fraction;

  // check if temperature is negative
  if (temp2write & 0x8000) {
    text[0] = '-';
    temp2write = ~temp2write + 1;
  }

  // extract temp_whole
  temp_whole = temp2write >> RES_SHIFT ;

  // convert temp_whole to characters
  if (temp_whole/100)
    text[0] = temp_whole/100  + 48;
  else
    text[0] = '0';

  text[1] = (temp_whole/10)%10 + 48;            // Extract tens digit
  text[2] =  temp_whole%10     + 48;            // Extract ones digit

  // extract temp_fraction and convert it to unsigned int
  temp_fraction  = temp2write << (4-RES_SHIFT);
  temp_fraction &= 0x000F;
  temp_fraction *= 625;

  // convert temp_fraction to characters
  text[4] =  temp_fraction/1000    + 48;        // Extract thousands digit
  //text[5] = (temp_fraction/100)%10 + 48;        // Extract hundreds digit
  //text[6] = (temp_fraction/10)%10  + 48;        // Extract tens digit
  //text[7] =  temp_fraction%10      + 48;        // Extract ones digit

  // print temperature on LCD
  UART1_Write_text(text);
  UART1_Write_text("\n\r");
}

void mereni(int cislo){
 Ow_Reset(&PORTB, cislo);                        // Onewire reset signal
    Ow_Write(&PORTB, cislo, 0xCC);                  // Issue command SKIP_ROM
    Ow_Write(&PORTB, cislo, 0x44);                  // Issue command CONVERT_T
    Delay_us(120);

    Ow_Reset(&PORTB, cislo);
    Ow_Write(&PORTB, cislo, 0xCC);                  // Issue command SKIP_ROM
    Ow_Write(&PORTB, cislo, 0xBE);                  // Issue command READ_SCRATCHPAD
    Delay_ms(400);

    temp =  Ow_Read(&PORTB, cislo);
    temp = (Ow_Read(&PORTB, cislo) << 8) + temp;

    //--- Format and display result on Lcd

    Display_Temperature(temp);


}
void main() {

  UART1_Init(9600);               // Initialize UART module at 9600 bps
  Delay_ms(100);                  // Wait for UART module to stabilize
  UART1_Write_Text("Init");
  UART1_Write(13);UART1_Write(10);
  while (1) {                                       // Endless loop
  mereni(0);
  Delay_ms(500);
  mereni(1);
  Delay_ms(500);
  mereni(2);
  Delay_ms(500);
  }
}

V downloads je příklad pro vícsenzorů bez jejich detekce (každý na svém pinu). Teplota je vracena v základu jako int (desetinásobek teploty). Počet čidel a umístění se nastavuje v hlavičkovém souboru.

V tom příkladu z microC pro AVR je chyba, nikdy se nemůže zobrazit znaménko mínus, protože i když je v této části nastaveno

// check if temperature is negative 
  if (temp2write & 0x8000) { 
    text[0] = '-'; 
    temp2write = ~temp2write + 1; 
  }

Zde dojde vždy k přepsání na 1 nebo 0

// convert temp_whole to characters 
  if (temp_whole/100) 
    text[0] = temp_whole/100  + 48; 
  else 
    text[0] = '0';

Po této úpravě to už funguje správně

// check if temperature is negative 
  if (temp2write & 0x8000) { 
    text[0] = '-'; 
    temp2write = ~temp2write + 1; 
  }
  else
 {
   text[0] = ' ';
 }

// convert temp_whole to characters 
  if (temp_whole/100) 
    text[0] = temp_whole/100  + 48; 
  else 
 {
     if(text[0]!=45)
      {
         text[0] = ' ';
      }
 } 

Nakonec sem se s tim programem v downloads popral a rozchodil na atmega8 s UARTem … sem nakej linej k tomu ted pripojovat LCD :slight_smile:

ahoj, kde najdu tuhle sekci download??

na hlavni strance v kategoriich,mam ale pocit ze musis splnovat nejake pozadavky… asi minimum prispevku …?

díky

tak pouze

které je viditelné jen registrovaným a přihlášeným uživatelům

a nevis jak zobrazím to o čem se tu bavili ty čidla, že je to v té sekci download nemůžu to najít.

No, ono je to tak, že tenkrát tu bylo jiné fórum (myšleno ten diskusní systém, na kterém to tu běží), a teď je tu používán k provozu systém jiný a původní databáze s diskusními příspěvky do něj byla převedena. Takže pokud to není v Downloads sekci, je to proto, že to bylo v Downloads sekci toho původního systému, takže jedině kdyby ti to poslal nějaký člen, který to ještě má, a nebo jestli někdo ví kde byl zdroj, tak na to dal odkaz…

Jestli se chceš něco naučit, tak co takhle vzít datasheet od DS18B20 a začít podle něj ? Je tam napsáno, jak má být čidlo zapojeno, je tam přesně popsáno, jak vypadá časování zápisu log. 1 a log. 0 do čidla i časování čtení dat z čidla. Jsou tam popsány i další časy a koneckonců je tam i popsáno, co čidlu poslat a co z něj přečíst.

Kromě toho by ses i dozvěděl, jak dlouho po odeslání příkazu 0x44 - CONVERT_T musís počkat, než má smysl poslat příkaz 0xBE - READ_SCRATCHPAD. A 120us to opravdu není.

O zběsilostech typu Delay_ms(400); raději vůbec nemluvím, ty do programu vůbec nepatří.

Programování cca na 1-2 hodiny. Teda když nepočítám ten algoritmus pro vyhledání adres všech připojených čidel.