/*********************************************************************/
/* Knihovna pro teplotni cidlo DS18B20 */
/* Lukas Olivik */
/* l.olivik @ centrum.cz */
/* www.ollie.xf.cz */
/* */
/* v0.1 - 01.06.2011 */
/* bez floatu, minimalni blokovani procesoru, */
/* prikazy se odesilaji jen pokud je detekovano cidlo */
/* */
/* originalni zdroj: Jan Matuska, walda.starhill.org */
/*********************************************************************/
#include <avr/io.h>
#define F_CPU 4000000UL // 4 MHz - takt MCU
#include <util/delay.h>
#define DS_PIN PD5 // na PD5 je připojeno čidlo
#define TX DDRD |= (1<<DS_PIN); // vysilani, pin je pripojen k zemi
#define RX DDRD &=~(1<<DS_PIN); // prijem, uvolneni sbernice
#define RXPIN PIND & (1<<DS_PIN) // testovani log. urovne na sbernici
// look-up tabulka pro desetiny stupne, vyhneme se tim pouziti float cisel
static const unsigned char deci_lut[16]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};
// provede reset a test prezence DS18B20 na sbernici
unsigned char ow_detect_presence(void) {
unsigned char out=0;//1; // vychozi navratova hodnota
RX; // vychozi stav sbernice
_delay_us(1000); // pro ustaleni
//if (RXPIN == 0) return 2; // detekce zkratu na sbernici, nebo chybejici pull-up - nefunguje
cli(); // zakazat preruseni
TX; // bus low
_delay_us(480); // cas pro prikaz reset
RX; // uvolneni sbernice
_delay_us(70); // cekani na potvrzeni teplomerem
if(RXPIN) out = 1;//0 // pokud detekovana log.1, tak teplomer na sbernici neni
_delay_us(410); // pauza pred dalsi komunikaci
sei(); // povolit preruseni
return out; // vrati stav: 0=teplomer nalezen, 1=teplomer nenalezen, 2=zkrat sbernice
}
// posle na sbernici log.1
void ow_write_one(void) {
cli(); // zakazat preruseni
TX; // bus low
_delay_us(6); // pauza definujici log.1
RX; // uvolneni sbernice
_delay_us(64); // pauza pred dalsi komunikaci
sei(); // povolit preruseni
}
// posle na sbernici log.0
void ow_write_zero(void) {
cli(); // zakazat preruseni
TX; // bus low
_delay_us(60); // pauza definujici log.0
RX; // uvolneni sbernice
_delay_us(10); // pauza pred dalsi komunikaci
sei(); // povolit preruseni
}
// precte jeden bit ze sbernice
unsigned char ow_read_bit(void) {
unsigned char out=0; // vychozi navratova hodnota bitu
cli(); // zakazat preruseni
TX; // bus low
_delay_us(6); // pauza pro stav cteni
RX; // uvolneni sbernice
_delay_us(9); // pauza pro reakci teplomeru
if(RXPIN) out=1; // test stavu sbernice, vlastni cteni
_delay_us(55); // pauza pred dalsi komunikaci
sei(); // povolit preruseni
return out; // prectena hodnota, 1 nebo 0
}
// odesle na sbernici jeden byte. Odesila se prvni LSB
void ow_write_byte(unsigned char tosend) {
int n=8;
while(n--) {
if(tosend&1) ow_write_one(); else ow_write_zero();
tosend >>= 1;
}
}
// prijme ze sbernice jeden byte. Prijima jako prvni LSB.
unsigned char ow_read_byte(void) {
int n=8, out=0;
while(n--) {
out >>= 1; // bitovy posuv doprava
if(ow_read_bit()) out |= 0x80; // nastaveni nejvyssiho bitu na 1
}
return out;
}
// spusti mereni teploty
unsigned char ds_conv(void) {
unsigned char pres = 0;
pres = ow_detect_presence();
if (pres == 0){
ow_write_byte(0xCC); // SKIP ROM
ow_write_byte(0x44); // CONVERT T
}
return pres;
}
// po spusteni mereni je nutne pockat 750 ms
// nacte teplotu z teplomeru a vrati ji ve formatu (t*10)
// priklad: 23.5°C = 235
// tento format lze snadneji zpracovavat nez nejake floaty (zerou moc pameti)
int ds_read(void) {
unsigned char data_lo, data_hi, deci_ind;
int teplota = 0;
unsigned char pres = 0;
pres = ow_detect_presence();
if (pres == 0){
ow_write_byte(0xCC); // SKIP ROM
ow_write_byte(0xBE); // READ SCRATCHPAD
data_lo=ow_read_byte(); // 1. byte scratchpadu teplomeru = spodni byte teploty
data_hi=ow_read_byte(); // 2. byte scratchpadu teplomeru = horni byte teploty
teplota = (data_lo & 0xF0) >> 4 | (data_hi & 0x0F) << 4 ; // signed teplota
teplota = 10 * teplota;
deci_ind = (data_lo & 0x0F); // desetiny nacist z look-up tabulky
if (teplota > 0) teplota += deci_lut[deci_ind];
else teplota -= deci_lut[deci_ind];
}
return teplota;
}