Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_sht20.c
1 #include <bc_sht20.h>
2 
3 #define _BC_SHT20_DELAY_RUN 20
4 #define _BC_SHT20_DELAY_INITIALIZATION 20
5 #define _BC_SHT20_DELAY_MEASUREMENT_RH 50
6 #define _BC_SHT20_DELAY_MEASUREMENT_T 100
7 
8 static void _bc_sht20_task_interval(void *param);
9 
10 static void _bc_sht20_task_measure(void *param);
11 
12 static bool _bc_sht20_write(bc_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 bc_sht20_init(bc_sht20_t *self, bc_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 = bc_scheduler_register(_bc_sht20_task_interval, self, BC_TICK_INFINITY);
24  self->_task_id_measure = bc_scheduler_register(_bc_sht20_task_measure, self, _BC_SHT20_DELAY_RUN);
25 
26  self->_tick_ready = _BC_SHT20_DELAY_RUN;
27 
28  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
29 }
30 
32 {
33  _bc_sht20_write(self, 0xfe);
34  bc_scheduler_unregister(self->_task_id_interval);
35  bc_scheduler_unregister(self->_task_id_measure);
36 }
37 
38 void bc_sht20_set_event_handler(bc_sht20_t *self, void (*event_handler)(bc_sht20_t *, bc_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 == BC_TICK_INFINITY)
49  {
50  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
51  }
52  else
53  {
54  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
55 
56  bc_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  bc_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
70 
71  return true;
72 }
73 
74 bool bc_sht20_get_humidity_raw(bc_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 bc_sht20_get_humidity_percentage(bc_sht20_t *self, float *percentage)
87 {
88  uint16_t raw;
89 
90  if (!bc_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 bc_sht20_get_temperature_raw(bc_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 
121 bool bc_sht20_get_temperature_celsius(bc_sht20_t *self, float *celsius)
122 {
123  uint16_t raw;
124 
125  if (!bc_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 bc_sht20_get_temperature_fahrenheit(bc_sht20_t *self, float *fahrenheit)
136 {
137  float celsius;
138 
139  if (!bc_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 
149 bool bc_sht20_get_temperature_kelvin(bc_sht20_t *self, float *kelvin)
150 {
151  float celsius;
152 
153  if (!bc_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 _bc_sht20_task_interval(void *param)
169 {
170  bc_sht20_t *self = param;
171 
172  bc_sht20_measure(self);
173 
174  bc_scheduler_plan_current_relative(self->_update_interval);
175 }
176 
177 static void _bc_sht20_task_measure(void *param)
178 {
179  bc_sht20_t *self = param;
180 
181 start:
182 
183  switch (self->_state)
184  {
185  case BC_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, BC_SHT20_EVENT_ERROR, self->_event_param);
195  }
196 
197  self->_state = BC_SHT20_STATE_INITIALIZE;
198 
199  return;
200  }
201  case BC_SHT20_STATE_INITIALIZE:
202  {
203  self->_state = BC_SHT20_STATE_ERROR;
204 
205  if (!_bc_sht20_write(self, 0xfe))
206  {
207  goto start;
208  }
209 
210  self->_state = BC_SHT20_STATE_MEASURE_RH;
211 
212  self->_tick_ready = bc_tick_get() + _BC_SHT20_DELAY_INITIALIZATION;
213 
214  if (self->_measurement_active)
215  {
216  bc_scheduler_plan_current_absolute(self->_tick_ready);
217  }
218 
219  return;
220  }
221  case BC_SHT20_STATE_MEASURE_RH:
222  {
223  self->_state = BC_SHT20_STATE_ERROR;
224 
225  if (!_bc_sht20_write(self, 0xf5))
226  {
227  goto start;
228  }
229 
230  self->_state = BC_SHT20_STATE_READ_RH;
231 
232  bc_scheduler_plan_current_from_now(_BC_SHT20_DELAY_MEASUREMENT_RH);
233 
234  return;
235  }
236  case BC_SHT20_STATE_READ_RH:
237  {
238  self->_state = BC_SHT20_STATE_ERROR;
239 
240  uint8_t buffer[2];
241 
242  bc_i2c_transfer_t transfer;
243 
244  transfer.device_address = self->_i2c_address;
245  transfer.buffer = buffer;
246  transfer.length = sizeof(buffer);
247 
248  if (!bc_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 = BC_SHT20_STATE_MEASURE_T;
259 
260  goto start;
261  }
262  case BC_SHT20_STATE_MEASURE_T:
263  {
264  self->_state = BC_SHT20_STATE_ERROR;
265 
266  if (!_bc_sht20_write(self, 0xf3))
267  {
268  goto start;
269  }
270 
271  self->_state = BC_SHT20_STATE_READ_T;
272 
273  bc_scheduler_plan_current_from_now(_BC_SHT20_DELAY_MEASUREMENT_T);
274 
275  return;
276  }
277  case BC_SHT20_STATE_READ_T:
278  {
279  self->_state = BC_SHT20_STATE_ERROR;
280 
281  uint8_t buffer[2];
282 
283  bc_i2c_transfer_t transfer;
284 
285  transfer.device_address = self->_i2c_address;
286  transfer.buffer = buffer;
287  transfer.length = sizeof(buffer);
288 
289  if (!bc_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 = BC_SHT20_STATE_UPDATE;
300 
301  goto start;
302  }
303  case BC_SHT20_STATE_UPDATE:
304  {
305  self->_measurement_active = false;
306 
307  if (self->_event_handler != NULL)
308  {
309  self->_event_handler(self, BC_SHT20_EVENT_UPDATE, self->_event_param);
310  }
311 
312  self->_state = BC_SHT20_STATE_MEASURE_RH;
313 
314  return;
315  }
316  default:
317  {
318  self->_state = BC_SHT20_STATE_ERROR;
319 
320  goto start;
321  }
322  }
323 }
324 
325 static bool _bc_sht20_write(bc_sht20_t *self, const uint8_t data)
326 {
327  bc_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 bc_i2c_write(self->_i2c_channel, &transfer);
334 }
I2C transfer parameters.
Definition: bc_i2c.h:42
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
Error event.
Definition: bc_sht20.h:16
I2C communication speed is 400 kHz.
Definition: bc_i2c.h:36
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
Update event.
Definition: bc_sht20.h:19
bool bc_sht20_measure(bc_sht20_t *self)
Start measurement manually.
Definition: bc_sht20.c:60
bool bc_sht20_get_temperature_fahrenheit(bc_sht20_t *self, float *fahrenheit)
Get measured temperature in degrees of Fahrenheit.
Definition: bc_sht20.c:135
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:45
bool bc_sht20_get_temperature_kelvin(bc_sht20_t *self, float *kelvin)
Get measured temperature in kelvin.
Definition: bc_sht20.c:149
bool bc_i2c_read(bc_i2c_channel_t channel, const bc_i2c_transfer_t *transfer)
Read from I2C channel.
Definition: bc_i2c.c:283
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_current_absolute(bc_tick_t tick)
Schedule current task to absolute tick.
Definition: bc_scheduler.c:144
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
bc_sht20_event_t
Callback events.
Definition: bc_sht20.h:13
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
void * buffer
Pointer to buffer which is being written or read.
Definition: bc_i2c.h:48
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
bool bc_i2c_write(bc_i2c_channel_t channel, const bc_i2c_transfer_t *transfer)
Write to I2C channel.
Definition: bc_i2c.c:237
void bc_sht20_init(bc_sht20_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize SHT20.
Definition: bc_sht20.c:16
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
bool bc_sht20_get_humidity_percentage(bc_sht20_t *self, float *percentage)
Get measured humidity as percentage.
Definition: bc_sht20.c:86
struct bc_sht20_t bc_sht20_t
SHT20 instance.
Definition: bc_sht20.h:25
bool bc_sht20_get_humidity_raw(bc_sht20_t *self, uint16_t *raw)
Get measured humidity as raw value.
Definition: bc_sht20.c:74
bc_i2c_channel_t
I2C channels.
Definition: bc_i2c.h:15
void bc_sht20_set_update_interval(bc_sht20_t *self, bc_tick_t interval)
Set measurement interval.
Definition: bc_sht20.c:44
size_t length
Length of buffer which is being written or read.
Definition: bc_i2c.h:51
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bool bc_sht20_get_temperature_raw(bc_sht20_t *self, uint16_t *raw)
Get measured temperature as raw value.
Definition: bc_sht20.c:109
bool bc_sht20_get_temperature_celsius(bc_sht20_t *self, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: bc_sht20.c:121
void bc_sht20_set_event_handler(bc_sht20_t *self, void(*event_handler)(bc_sht20_t *, bc_sht20_event_t, void *), void *event_param)
Set callback function.
Definition: bc_sht20.c:38
void bc_sht20_deinit(bc_sht20_t *self)
Deinitialize SHT20.
Definition: bc_sht20.c:31
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80