1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
#include <pic16f84a.h>
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");
}
}
|