Rev Author Line No. Line
2843 kaklik 1 #include "config.h"
2 #include "sht11.h"
3  
4 #define SHT11_CMD_TEMP 0x03
5 #define SHT11_CMD_HUMID 0x05
6 #define SHT11_CMD_WSTAT 0x06
7 #define SHT11_CMD_RSTAT 0x07
8 #define SHT11_CMD_RESET 0x1E
9  
10 /////////////////////////////////////////////////////////////////////////////
11 // This version needs external pullups on SDA!
12 /////////////////////////////////////////////////////////////////////////////
13  
14 static void delay(void) { _delay_us(2); }
15  
16 static void scl_hi(void) { setBits(PORT(SHT11_PORT), SHT11_SCL); }
17 static void scl_lo(void) { clrBits(PORT(SHT11_PORT), SHT11_SCL); }
18 static void sda_hi(void) { clrBits(DDR(SHT11_PORT), SHT11_SDA); }
19 static void sda_lo(void) { setBits(DDR(SHT11_PORT), SHT11_SDA); }
20 static void scl_pulse(void) { scl_hi(); delay(); scl_lo(); }
21 static uint8_t sda_val(void) { return (PIN(SHT11_PORT) & SHT11_SDA) != 0; }
22  
23 /////////////////////////////////////////////////////////////////////////////
24  
25 static uint8_t crc_value;
26  
27 static void
28 crc8(uint8_t b)
29 {
30 for (uint8_t i = 0; i < 8; ++i) {
31 if ((crc_value ^ b) & 0x80) {
32 crc_value <<= 1;
33 crc_value ^= 0x31;
34 } else
35 crc_value <<= 1;
36 b <<= 1;
37 }
38 }
39  
40 /////////////////////////////////////////////////////////////////////////////
41  
42 static uint8_t
43 send(uint16_t b)
44 {
45 crc8(b);
46  
47 // data
48 for (uint8_t i = 0; i < 8; ++i) {
49 if (b & 0x80)
50 sda_hi();
51 else
52 sda_lo();
53 b <<= 1;
54 delay();
55 scl_pulse();
56 }
57  
58 // acknowledge
59 sda_hi();
60 delay();
61 uint8_t ack = sda_val();
62 scl_pulse();
63 return ack;
64 }
65  
66 static uint8_t
67 recv_data(void)
68 {
69 // data
70 uint8_t b = 0;
71 for (uint8_t i = 0; i < 8; ++i) {
72 // data is transmitted MSB first
73 b <<= 1;
74 if (sda_val())
75 b |= 1;
76 scl_pulse();
77 delay();
78 }
79  
80 // lo acknowledge
81 sda_lo();
82 delay();
83 scl_pulse();
84 sda_hi();
85 delay();
86  
87 crc8(b);
88 return b;
89 }
90  
91 static uint8_t
92 recv_crc(void)
93 {
94 // data
95 uint8_t b = 0;
96 for (uint8_t i = 0; i < 8; ++i) {
97 // CRC is transmitted LSB first
98 b >>= 1;
99 if (sda_val())
100 b |= 0x80;
101 scl_pulse();
102 delay();
103 }
104  
105 // hi acknowledge
106 sda_hi();
107 delay();
108 scl_pulse();
109 delay();
110  
111 return b;
112 }
113  
114 static void
115 start(void)
116 {
117 clrBits(PORT(SHT11_PORT), SHT11_SCL | SHT11_SDA); // SCK output low, SDA input/high
118 setBits(DDR(SHT11_PORT), SHT11_SCL);
119 clrBits(DDR(SHT11_PORT), SHT11_SDA);
120 delay();
121  
122 // reset communication
123 for (uint8_t i = 0; i < 10; ++i) {
124 scl_pulse();
125 delay();
126 }
127  
128 // "start" sequence
129 scl_hi(); delay();
130 sda_lo(); delay();
131 scl_lo(); delay();
132 scl_hi(); delay();
133 sda_hi(); delay();
134 scl_lo(); delay();
135 }
136  
137 /////////////////////////////////////////////////////////////////////////////
138 // Measurement sequence.
139  
140 uint8_t
141 sht11_start_temp(void)
142 {
143 crc_value = SHT11_LOWRES << 7; // bit-reversed
144 start();
145 return send(SHT11_CMD_TEMP) == 0;
146 }
147  
148 uint8_t
149 sht11_start_humid(void)
150 {
151 crc_value = SHT11_LOWRES << 7; // bit-reversed
152 start();
153 return send(SHT11_CMD_HUMID) == 0;
154 }
155  
156 uint8_t
157 sht11_ready(void)
158 {
159 return sda_val() == 0;
160 }
161  
162 static int16_t
163 result(void)
164 {
165 if (!sht11_ready())
166 return SHT11_UNAVAIL;
167 int16_t v = recv_data() << 8; v |= recv_data();
168 uint8_t crc = recv_crc();
169 if (crc != crc_value)
170 return SHT11_CRC_FAIL;
171 return v;
172 }
173  
174 int16_t
175 sht11_result_temp(void)
176 {
177 int16_t v = result();
178 if (sht11_valid(v)) {
179 #if SHT11_LOWRES
180 v = v * 4 - 4000;
181 #else
182 v -= 4000;
183 #endif
184 }
185 return v;
186 }
187  
188 int16_t
189 sht11_result_humid(void)
190 {
191 int16_t v = result();
192 if (sht11_valid(v)) {
193 #if SHT11_LOWRES
194 // inspired by Werner Hoch, modified for low resolution mode
195 const int32_t C1 = (int32_t)(-4.0 * 100);
196 const int32_t C2 = (int32_t)(0.648 * 100 * (1L<<24));
197 const int32_t C3 = (int32_t)(-7.2e-4 * 100 * (1L<<24));
198 v = (int16_t)((((C3 * v + C2) >> 7) * v + (1L<<16)) >> 17) + C1;
199 #else
200 // inspired by Werner Hoch
201 const int32_t C1 = (int32_t)(-4.0 * 100);
202 const int32_t C2 = (int32_t)(0.0405 * 100 * (1L<<28));
203 const int32_t C3 = (int32_t)(-2.8e-6 * 100 * (1L<<30));
204 v = (int16_t)((((((C3 * v) >> 2) + C2) >> 11) * v + (1L<<16)) >> 17) + C1;
205 #endif
206 }
207 return v;
208 }
209  
210 /////////////////////////////////////////////////////////////////////////////
211 // Initialize.
212  
213 void
214 sht11_init(void)
215 {
216 start();
217 send(SHT11_CMD_RESET);
218 _delay_ms(11);
219  
220 start();
221 send(SHT11_CMD_WSTAT);
222 send(SHT11_LOWRES);
223 }
224