#include typedef unsigned char uint8_t; __sfr __at(0x70) UART_TX; __sfr __at(0x72) UART_STATUS; __sfr __at(0x73) OW_DATA; __sfr __at(0x74) OW_CMD; __sfr __at(0x75) OW_STATUS; #define OW_RESET 0x00 #define OW_WRITE 0x01 #define OW_READ 0x02 #define OW_BUSY 0x01 #define OW_PRESENCE 0x02 #define CMD_SKIP_ROM 0xCC #define CMD_CONVERT_T 0x44 #define CMD_READ_SCRATCH 0xBE /* * Fractional nibble lookup: each step is 0.0625 deg C. * Tables give the two decimal digits (tenths, hundredths) truncated. * e.g. frac=1 -> 0.0625 -> prints ".06" * frac=8 -> 0.5000 -> prints ".50" */ static const uint8_t frac_tens[16] = {0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9}; static const uint8_t frac_hund[16] = {0,6,2,8,5,1,7,4,0,6,2,8,5,1,7,3}; /* * Timer0 delay. OPTION_REG 0x07: T0CS=0 (Fosc/4), PSA=0, PS=111 (1:256). * At 50 MHz: overflow every 256*256 / (50M/4) = 5.24 ms. * 143 overflows ≈ 750 ms. */ #define STATUS_RP0 0x20 #define T0IF 0x04 static void wait_overflows(uint8_t n) { INTCON &= ~T0IF; while (n--) { while (!(INTCON & T0IF)); INTCON &= ~T0IF; } } static void delay_750ms(void) { wait_overflows(143); } static void uart_send(uint8_t b) { while (UART_STATUS & 0x01); UART_TX = b; } static void uart_puts(const char *s) { while (*s) uart_send((uint8_t)*s++); } static void ow_wait(void) { while (OW_STATUS & OW_BUSY); } static void ow_write_byte(uint8_t b) { OW_DATA = b; OW_CMD = OW_WRITE; ow_wait(); } static uint8_t ow_read_byte(void) { OW_CMD = OW_READ; ow_wait(); return OW_DATA; } static void print_uint8(uint8_t v) { uint8_t started = 0; if (v >= 200) { uart_send('2'); v -= 200; started = 1; } else if (v >= 100) { uart_send('1'); v -= 100; started = 1; } { uint8_t t = '0'; while (v >= 10) { v -= 10; t++; } if (started || t != '0') uart_send(t); } uart_send(v + '0'); } void main(void) { uint8_t lo, hi, sign, temp_int, frac; uint8_t i; /* Configure Timer0: bank 1, OPTION_REG = 0x07 (Fosc/4, prescaler 1:256) */ STATUS |= STATUS_RP0; TMR0 = 0x07; STATUS &= ~STATUS_RP0; uart_puts("\x1B[2J\x1B[H"); uart_puts("DS18B20 Temperature\r\n"); uart_puts("-------------------\r\n"); while (1) { /* Reset */ OW_CMD = OW_RESET; ow_wait(); if (!(OW_STATUS & OW_PRESENCE)) { uart_puts("No sensor\r\n"); delay_750ms(); continue; } /* Start temperature conversion */ ow_write_byte(CMD_SKIP_ROM); ow_write_byte(CMD_CONVERT_T); delay_750ms(); /* Reset and read scratchpad */ OW_CMD = OW_RESET; ow_wait(); if (!(OW_STATUS & OW_PRESENCE)) { uart_puts("Lost sensor\r\n"); continue; } ow_write_byte(CMD_SKIP_ROM); ow_write_byte(CMD_READ_SCRATCH); lo = ow_read_byte(); /* scratchpad byte 0: temp LSB */ hi = ow_read_byte(); /* scratchpad byte 1: temp MSB */ for (i = 0; i < 7; i++) ow_read_byte(); /* discard remaining bytes */ /* * DS18B20 12-bit format: * sign = hi bit 7 (and sign-extended through hi[7:4]) * integer part = hi[3:0]:lo[7:4] * fractional nibble = lo[3:0] (each bit = 0.0625 deg C) * * Negative values are two's complement of the 16-bit word. */ sign = hi & 0x80; if (sign) { lo = ~lo; hi = ~hi; if (lo == 0xFF) { lo = 0; hi++; } else { lo++; } } temp_int = ((hi & 0x0F) << 4) | (lo >> 4); frac = lo & 0x0F; uart_puts("\rTemp: "); if (sign) uart_send('-'); print_uint8(temp_int); uart_send('.'); uart_send('0' + frac_tens[frac]); uart_send('0' + frac_hund[frac]); uart_puts(" C\r\n"); } }