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 
255  self->_humidity_valid = true;
256 
257  self->_state = BC_SHT20_STATE_MEASURE_T;
258 
259  goto start;
260  }
261  case BC_SHT20_STATE_MEASURE_T:
262  {
263  self->_state = BC_SHT20_STATE_ERROR;
264 
265  if (!_bc_sht20_write(self, 0xf3))
266  {
267  goto start;
268  }
269 
270  self->_state = BC_SHT20_STATE_READ_T;
271 
272  bc_scheduler_plan_current_from_now(_BC_SHT20_DELAY_MEASUREMENT_T);
273 
274  return;
275  }
276  case BC_SHT20_STATE_READ_T:
277  {
278  self->_state = BC_SHT20_STATE_ERROR;
279 
280  uint8_t buffer[2];
281 
282  bc_i2c_transfer_t transfer;
283 
284  transfer.device_address = self->_i2c_address;
285  transfer.buffer = buffer;
286  transfer.length = sizeof(buffer);
287 
288  if (!bc_i2c_read(self->_i2c_channel, &transfer))
289  {
290  goto start;
291  }
292 
293  self->_reg_temperature = buffer[0] << 8 | buffer[1];
294 
295  self->_temperature_valid = true;
296 
297  self->_state = BC_SHT20_STATE_UPDATE;
298 
299  goto start;
300  }
301  case BC_SHT20_STATE_UPDATE:
302  {
303  self->_measurement_active = false;
304 
305  if (self->_event_handler != NULL)
306  {
307  self->_event_handler(self, BC_SHT20_EVENT_UPDATE, self->_event_param);
308  }
309 
310  self->_state = BC_SHT20_STATE_MEASURE_RH;
311 
312  return;
313  }
314  default:
315  {
316  self->_state = BC_SHT20_STATE_ERROR;
317 
318  goto start;
319  }
320  }
321 }
322 
323 static bool _bc_sht20_write(bc_sht20_t *self, const uint8_t data)
324 {
325  bc_i2c_transfer_t transfer;
326 
327  transfer.device_address = self->_i2c_address;
328  transfer.buffer = (void *) &data;
329  transfer.length = sizeof(data);
330 
331  return bc_i2c_write(self->_i2c_channel, &transfer);
332 }
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