Firmware SDK
twr_sht20.c
1 #include <twr_sht20.h>
2 
3 #define _TWR_SHT20_DELAY_RUN 20
4 #define _TWR_SHT20_DELAY_INITIALIZATION 20
5 #define _TWR_SHT20_DELAY_MEASUREMENT_RH 50
6 #define _TWR_SHT20_DELAY_MEASUREMENT_T 100
7 
8 static void _twr_sht20_task_interval(void *param);
9 
10 static void _twr_sht20_task_measure(void *param);
11 
12 static bool _twr_sht20_write(twr_sht20_t *self, const uint8_t data);
13 
14 // TODO SHT20 has only one fixed address so it is no necessary to pass it as parameter
15 
16 void twr_sht20_init(twr_sht20_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
17 {
18  memset(self, 0, sizeof(*self));
19 
20  self->_i2c_channel = i2c_channel;
21  self->_i2c_address = i2c_address;
22 
23  self->_task_id_interval = twr_scheduler_register(_twr_sht20_task_interval, self, TWR_TICK_INFINITY);
24  self->_task_id_measure = twr_scheduler_register(_twr_sht20_task_measure, self, _TWR_SHT20_DELAY_RUN);
25 
26  self->_tick_ready = _TWR_SHT20_DELAY_RUN;
27 
28  twr_i2c_init(self->_i2c_channel, TWR_I2C_SPEED_400_KHZ);
29 }
30 
32 {
33  _twr_sht20_write(self, 0xfe);
34  twr_scheduler_unregister(self->_task_id_interval);
35  twr_scheduler_unregister(self->_task_id_measure);
36 }
37 
38 void twr_sht20_set_event_handler(twr_sht20_t *self, void (*event_handler)(twr_sht20_t *, twr_sht20_event_t, void *), void *event_param)
39 {
40  self->_event_handler = event_handler;
41  self->_event_param = event_param;
42 }
43 
45 {
46  self->_update_interval = interval;
47 
48  if (self->_update_interval == TWR_TICK_INFINITY)
49  {
50  twr_scheduler_plan_absolute(self->_task_id_interval, TWR_TICK_INFINITY);
51  }
52  else
53  {
54  twr_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
55 
56  twr_sht20_measure(self);
57  }
58 }
59 
61 {
62  if (self->_measurement_active)
63  {
64  return false;
65  }
66 
67  self->_measurement_active = true;
68 
69  twr_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
70 
71  return true;
72 }
73 
74 bool twr_sht20_get_humidity_raw(twr_sht20_t *self, uint16_t *raw)
75 {
76  if (!self->_humidity_valid)
77  {
78  return false;
79  }
80 
81  *raw = self->_reg_humidity;
82 
83  return true;
84 }
85 
86 bool twr_sht20_get_humidity_percentage(twr_sht20_t *self, float *percentage)
87 {
88  uint16_t raw;
89 
90  if (!twr_sht20_get_humidity_raw(self, &raw))
91  {
92  return false;
93  }
94 
95  *percentage = -6.f + 125.f * (float) raw / 65536.f;
96 
97  if (*percentage >= 100.f)
98  {
99  *percentage = 100.f;
100  }
101  else if (*percentage <= 0.f)
102  {
103  *percentage = 0.f;
104  }
105 
106  return true;
107 }
108 
109 bool twr_sht20_get_temperature_raw(twr_sht20_t *self, uint16_t *raw)
110 {
111  if (!self->_temperature_valid)
112  {
113  return false;
114  }
115 
116  *raw = self->_reg_temperature;
117 
118  return true;
119 }
120 
122 {
123  uint16_t raw;
124 
125  if (!twr_sht20_get_temperature_raw(self, &raw))
126  {
127  return false;
128  }
129 
130  *celsius = -46.85f + 175.72f * (float) raw / 65536.f;
131 
132  return true;
133 }
134 
135 bool twr_sht20_get_temperature_fahrenheit(twr_sht20_t *self, float *fahrenheit)
136 {
137  float celsius;
138 
139  if (!twr_sht20_get_temperature_celsius(self, &celsius))
140  {
141  return false;
142  }
143 
144  *fahrenheit = celsius * 1.8f + 32.f;
145 
146  return true;
147 }
148 
150 {
151  float celsius;
152 
153  if (!twr_sht20_get_temperature_celsius(self, &celsius))
154  {
155  return false;
156  }
157 
158  *kelvin = celsius + 273.15f;
159 
160  if (*kelvin < 0.f)
161  {
162  *kelvin = 0.f;
163  }
164 
165  return true;
166 }
167 
168 static void _twr_sht20_task_interval(void *param)
169 {
170  twr_sht20_t *self = param;
171 
172  twr_sht20_measure(self);
173 
174  twr_scheduler_plan_current_relative(self->_update_interval);
175 }
176 
177 static void _twr_sht20_task_measure(void *param)
178 {
179  twr_sht20_t *self = param;
180 
181 start:
182 
183  switch (self->_state)
184  {
185  case TWR_SHT20_STATE_ERROR:
186  {
187  self->_humidity_valid = false;
188  self->_temperature_valid = false;
189 
190  self->_measurement_active = false;
191 
192  if (self->_event_handler != NULL)
193  {
194  self->_event_handler(self, TWR_SHT20_EVENT_ERROR, self->_event_param);
195  }
196 
197  self->_state = TWR_SHT20_STATE_INITIALIZE;
198 
199  return;
200  }
201  case TWR_SHT20_STATE_INITIALIZE:
202  {
203  self->_state = TWR_SHT20_STATE_ERROR;
204 
205  if (!_twr_sht20_write(self, 0xfe))
206  {
207  goto start;
208  }
209 
210  self->_state = TWR_SHT20_STATE_MEASURE_RH;
211 
212  self->_tick_ready = twr_tick_get() + _TWR_SHT20_DELAY_INITIALIZATION;
213 
214  if (self->_measurement_active)
215  {
216  twr_scheduler_plan_current_absolute(self->_tick_ready);
217  }
218 
219  return;
220  }
221  case TWR_SHT20_STATE_MEASURE_RH:
222  {
223  self->_state = TWR_SHT20_STATE_ERROR;
224 
225  if (!_twr_sht20_write(self, 0xf5))
226  {
227  goto start;
228  }
229 
230  self->_state = TWR_SHT20_STATE_READ_RH;
231 
232  twr_scheduler_plan_current_from_now(_TWR_SHT20_DELAY_MEASUREMENT_RH);
233 
234  return;
235  }
236  case TWR_SHT20_STATE_READ_RH:
237  {
238  self->_state = TWR_SHT20_STATE_ERROR;
239 
240  uint8_t buffer[2];
241 
242  twr_i2c_transfer_t transfer;
243 
244  transfer.device_address = self->_i2c_address;
245  transfer.buffer = buffer;
246  transfer.length = sizeof(buffer);
247 
248  if (!twr_i2c_read(self->_i2c_channel, &transfer))
249  {
250  goto start;
251  }
252 
253  self->_reg_humidity = buffer[0] << 8 | buffer[1];
254  self->_reg_humidity &= ~0x3;
255 
256  self->_humidity_valid = true;
257 
258  self->_state = TWR_SHT20_STATE_MEASURE_T;
259 
260  goto start;
261  }
262  case TWR_SHT20_STATE_MEASURE_T:
263  {
264  self->_state = TWR_SHT20_STATE_ERROR;
265 
266  if (!_twr_sht20_write(self, 0xf3))
267  {
268  goto start;
269  }
270 
271  self->_state = TWR_SHT20_STATE_READ_T;
272 
273  twr_scheduler_plan_current_from_now(_TWR_SHT20_DELAY_MEASUREMENT_T);
274 
275  return;
276  }
277  case TWR_SHT20_STATE_READ_T:
278  {
279  self->_state = TWR_SHT20_STATE_ERROR;
280 
281  uint8_t buffer[2];
282 
283  twr_i2c_transfer_t transfer;
284 
285  transfer.device_address = self->_i2c_address;
286  transfer.buffer = buffer;
287  transfer.length = sizeof(buffer);
288 
289  if (!twr_i2c_read(self->_i2c_channel, &transfer))
290  {
291  goto start;
292  }
293 
294  self->_reg_temperature = buffer[0] << 8 | buffer[1];
295  self->_reg_temperature &= ~0x3;
296 
297  self->_temperature_valid = true;
298 
299  self->_state = TWR_SHT20_STATE_UPDATE;
300 
301  goto start;
302  }
303  case TWR_SHT20_STATE_UPDATE:
304  {
305  self->_measurement_active = false;
306 
307  if (self->_event_handler != NULL)
308  {
309  self->_event_handler(self, TWR_SHT20_EVENT_UPDATE, self->_event_param);
310  }
311 
312  self->_state = TWR_SHT20_STATE_MEASURE_RH;
313 
314  return;
315  }
316  default:
317  {
318  self->_state = TWR_SHT20_STATE_ERROR;
319 
320  goto start;
321  }
322  }
323 }
324 
325 static bool _twr_sht20_write(twr_sht20_t *self, const uint8_t data)
326 {
327  twr_i2c_transfer_t transfer;
328 
329  transfer.device_address = self->_i2c_address;
330  transfer.buffer = (void *) &data;
331  transfer.length = sizeof(data);
332 
333  return twr_i2c_write(self->_i2c_channel, &transfer);
334 }
bool twr_i2c_write(twr_i2c_channel_t channel, const twr_i2c_transfer_t *transfer)
Write to I2C channel.
Definition: twr_i2c.c:243
Error event.
Definition: twr_sht20.h:16
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
uint8_t device_address
7-bit I2C device address
Definition: twr_i2c.h:45
bool twr_sht20_get_humidity_percentage(twr_sht20_t *self, float *percentage)
Get measured humidity as percentage.
Definition: twr_sht20.c:86
bool twr_sht20_get_temperature_fahrenheit(twr_sht20_t *self, float *fahrenheit)
Get measured temperature in degrees of Fahrenheit.
Definition: twr_sht20.c:135
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
void twr_sht20_deinit(twr_sht20_t *self)
Deinitialize SHT20.
Definition: twr_sht20.c:31
I2C transfer parameters.
Definition: twr_i2c.h:42
void twr_sht20_set_event_handler(twr_sht20_t *self, void(*event_handler)(twr_sht20_t *, twr_sht20_event_t, void *), void *event_param)
Set callback function.
Definition: twr_sht20.c:38
twr_sht20_event_t
Callback events.
Definition: twr_sht20.h:13
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_i2c_init(twr_i2c_channel_t channel, twr_i2c_speed_t speed)
Initialize I2C channel.
Definition: twr_i2c.c:57
bool twr_sht20_get_temperature_raw(twr_sht20_t *self, uint16_t *raw)
Get measured temperature as raw value.
Definition: twr_sht20.c:109
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
bool twr_sht20_measure(twr_sht20_t *self)
Start measurement manually.
Definition: twr_sht20.c:60
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
size_t length
Length of buffer which is being written or read.
Definition: twr_i2c.h:51
twr_i2c_channel_t
I2C channels.
Definition: twr_i2c.h:15
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
struct twr_sht20_t twr_sht20_t
SHT20 instance.
Definition: twr_sht20.h:25
bool twr_i2c_read(twr_i2c_channel_t channel, const twr_i2c_transfer_t *transfer)
Read from I2C channel.
Definition: twr_i2c.c:289
void * buffer
Pointer to buffer which is being written or read.
Definition: twr_i2c.h:48
bool twr_sht20_get_temperature_kelvin(twr_sht20_t *self, float *kelvin)
Get measured temperature in kelvin.
Definition: twr_sht20.c:149
bool twr_sht20_get_temperature_celsius(twr_sht20_t *self, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: twr_sht20.c:121
Update event.
Definition: twr_sht20.h:19
void twr_sht20_set_update_interval(twr_sht20_t *self, twr_tick_t interval)
Set measurement interval.
Definition: twr_sht20.c:44
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_sht20_init(twr_sht20_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize SHT20.
Definition: twr_sht20.c:16
I2C communication speed is 400 kHz.
Definition: twr_i2c.h:36
bool twr_sht20_get_humidity_raw(twr_sht20_t *self, uint16_t *raw)
Get measured humidity as raw value.
Definition: twr_sht20.c:74