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 // TODO SHT20 has only one fixed address so it is no necessary to pass it as parameter
13 
14 void bc_sht20_init(bc_sht20_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
15 {
16  memset(self, 0, sizeof(*self));
17 
18  self->_i2c_channel = i2c_channel;
19  self->_i2c_address = i2c_address;
20 
21  self->_task_id_interval = bc_scheduler_register(_bc_sht20_task_interval, self, BC_TICK_INFINITY);
22  self->_task_id_measure = bc_scheduler_register(_bc_sht20_task_measure, self, _BC_SHT20_DELAY_RUN);
23 
24  self->_tick_ready = _BC_SHT20_DELAY_RUN;
25 
26  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
27 }
28 
29 void bc_sht20_set_event_handler(bc_sht20_t *self, void (*event_handler)(bc_sht20_t *, bc_sht20_event_t, void *), void *event_param)
30 {
31  self->_event_handler = event_handler;
32  self->_event_param = event_param;
33 }
34 
36 {
37  self->_update_interval = interval;
38 
39  if (self->_update_interval == BC_TICK_INFINITY)
40  {
41  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
42  }
43  else
44  {
45  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
46 
47  bc_sht20_measure(self);
48  }
49 }
50 
52 {
53  if (self->_measurement_active)
54  {
55  return false;
56  }
57 
58  self->_measurement_active = true;
59 
60  bc_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
61 
62  return true;
63 }
64 
65 bool bc_sht20_get_humidity_raw(bc_sht20_t *self, uint16_t *raw)
66 {
67  if (!self->_humidity_valid)
68  {
69  return false;
70  }
71 
72  *raw = self->_reg_humidity;
73 
74  return true;
75 }
76 
77 bool bc_sht20_get_humidity_percentage(bc_sht20_t *self, float *percentage)
78 {
79  uint16_t raw;
80 
81  if (!bc_sht20_get_humidity_raw(self, &raw))
82  {
83  return false;
84  }
85 
86  *percentage = -6.f + 125.f * (float) raw / 65536.f;
87 
88  if (*percentage >= 100.f)
89  {
90  *percentage = 100.f;
91  }
92  else if (*percentage <= 0.f)
93  {
94  *percentage = 0.f;
95  }
96 
97  return true;
98 }
99 
100 bool bc_sht20_get_temperature_raw(bc_sht20_t *self, uint16_t *raw)
101 {
102  if (!self->_temperature_valid)
103  {
104  return false;
105  }
106 
107  *raw = self->_reg_temperature;
108 
109  return true;
110 }
111 
112 bool bc_sht20_get_temperature_celsius(bc_sht20_t *self, float *celsius)
113 {
114  uint16_t raw;
115 
116  if (!bc_sht20_get_temperature_raw(self, &raw))
117  {
118  return false;
119  }
120 
121  *celsius = -46.85f + 175.72f * (float) raw / 65536.f;
122 
123  return true;
124 }
125 
126 static void _bc_sht20_task_interval(void *param)
127 {
128  bc_sht20_t *self = param;
129 
130  bc_sht20_measure(self);
131 
132  bc_scheduler_plan_current_relative(self->_update_interval);
133 }
134 
135 static void _bc_sht20_task_measure(void *param)
136 {
137  bc_sht20_t *self = param;
138 
139 start:
140 
141  switch (self->_state)
142  {
143  case BC_SHT20_STATE_ERROR:
144  {
145  self->_humidity_valid = false;
146  self->_temperature_valid = false;
147 
148  self->_measurement_active = false;
149 
150  if (self->_event_handler != NULL)
151  {
152  self->_event_handler(self, BC_SHT20_EVENT_ERROR, self->_event_param);
153  }
154 
155  self->_state = BC_SHT20_STATE_INITIALIZE;
156 
157  return;
158  }
159  case BC_SHT20_STATE_INITIALIZE:
160  {
161  self->_state = BC_SHT20_STATE_ERROR;
162 
163  uint8_t buffer[1];
164 
165  buffer[0] = 0xfe;
166 
167  bc_i2c_transfer_t transfer;
168 
169  transfer.device_address = self->_i2c_address;
170  transfer.buffer = buffer;
171  transfer.length = sizeof(buffer);
172 
173  if (!bc_i2c_write(self->_i2c_channel, &transfer))
174  {
175  goto start;
176  }
177 
178  self->_state = BC_SHT20_STATE_MEASURE_RH;
179 
180  self->_tick_ready = bc_tick_get() + _BC_SHT20_DELAY_INITIALIZATION;
181 
182  if (self->_measurement_active)
183  {
184  bc_scheduler_plan_current_absolute(self->_tick_ready);
185  }
186 
187  return;
188  }
189  case BC_SHT20_STATE_MEASURE_RH:
190  {
191  self->_state = BC_SHT20_STATE_ERROR;
192 
193  uint8_t buffer[1];
194 
195  buffer[0] = 0xf5;
196 
197  bc_i2c_transfer_t transfer;
198 
199  transfer.device_address = self->_i2c_address;
200  transfer.buffer = buffer;
201  transfer.length = sizeof(buffer);
202 
203  if (!bc_i2c_write(self->_i2c_channel, &transfer))
204  {
205  goto start;
206  }
207 
208  self->_state = BC_SHT20_STATE_READ_RH;
209 
210  bc_scheduler_plan_current_from_now(_BC_SHT20_DELAY_MEASUREMENT_RH);
211 
212  return;
213  }
214  case BC_SHT20_STATE_READ_RH:
215  {
216  self->_state = BC_SHT20_STATE_ERROR;
217 
218  uint8_t buffer[2];
219 
220  bc_i2c_transfer_t transfer;
221 
222  transfer.device_address = self->_i2c_address;
223  transfer.buffer = buffer;
224  transfer.length = sizeof(buffer);
225 
226  if (!bc_i2c_read(self->_i2c_channel, &transfer))
227  {
228  goto start;
229  }
230 
231  self->_reg_humidity = buffer[0] << 8 | buffer[1];
232 
233  self->_humidity_valid = true;
234 
235  self->_state = BC_SHT20_STATE_MEASURE_T;
236 
237  goto start;
238  }
239  case BC_SHT20_STATE_MEASURE_T:
240  {
241  self->_state = BC_SHT20_STATE_ERROR;
242 
243  uint8_t buffer[1];
244 
245  buffer[0] = 0xf3;
246 
247  bc_i2c_transfer_t transfer;
248 
249  transfer.device_address = self->_i2c_address;
250  transfer.buffer = buffer;
251  transfer.length = sizeof(buffer);
252 
253  if (!bc_i2c_write(self->_i2c_channel, &transfer))
254  {
255  goto start;
256  }
257 
258  self->_state = BC_SHT20_STATE_READ_T;
259 
260  bc_scheduler_plan_current_from_now(_BC_SHT20_DELAY_MEASUREMENT_T);
261 
262  return;
263  }
264  case BC_SHT20_STATE_READ_T:
265  {
266  self->_state = BC_SHT20_STATE_ERROR;
267 
268  uint8_t buffer[2];
269 
270  bc_i2c_transfer_t transfer;
271 
272  transfer.device_address = self->_i2c_address;
273  transfer.buffer = buffer;
274  transfer.length = sizeof(buffer);
275 
276  if (!bc_i2c_read(self->_i2c_channel, &transfer))
277  {
278  goto start;
279  }
280 
281  self->_reg_temperature = buffer[0] << 8 | buffer[1];
282 
283  self->_temperature_valid = true;
284 
285  self->_state = BC_SHT20_STATE_UPDATE;
286 
287  goto start;
288  }
289  case BC_SHT20_STATE_UPDATE:
290  {
291  self->_measurement_active = false;
292 
293  if (self->_event_handler != NULL)
294  {
295  self->_event_handler(self, BC_SHT20_EVENT_UPDATE, self->_event_param);
296  }
297 
298  self->_state = BC_SHT20_STATE_MEASURE_RH;
299 
300  return;
301  }
302  default:
303  {
304  self->_state = BC_SHT20_STATE_ERROR;
305 
306  goto start;
307  }
308  }
309 }
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:51
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:45
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:14
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:77
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:65
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:35
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:100
bool bc_sht20_get_temperature_celsius(bc_sht20_t *self, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: bc_sht20.c:112
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:29