Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_sht30.c
1 #include <bc_sht30.h>
2 
3 #define _BC_SHT30_DELAY_RUN 20
4 #define _BC_SHT30_DELAY_INITIALIZATION 20
5 #define _BC_SHT30_DELAY_MEASUREMENT 20
6 
7 static void _bc_sht30_task_interval(void *param);
8 
9 static void _bc_sht30_task_measure(void *param);
10 
11 static bool _bc_sht30_write(bc_sht30_t *self, const uint16_t data);
12 
13 void bc_sht30_init(bc_sht30_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
14 {
15  memset(self, 0, sizeof(*self));
16 
17  self->_i2c_channel = i2c_channel;
18  self->_i2c_address = i2c_address;
19 
20  self->_task_id_interval = bc_scheduler_register(_bc_sht30_task_interval, self, BC_TICK_INFINITY);
21  self->_task_id_measure = bc_scheduler_register(_bc_sht30_task_measure, self, _BC_SHT30_DELAY_RUN);
22 
23  self->_tick_ready = _BC_SHT30_DELAY_RUN;
24 
25  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
26 }
27 
29 {
30  _bc_sht30_write(self, 0xa230);
31  bc_scheduler_unregister(self->_task_id_interval);
32  bc_scheduler_unregister(self->_task_id_measure);
33 }
34 
35 void bc_sht30_set_event_handler(bc_sht30_t *self, void (*event_handler)(bc_sht30_t *, bc_sht30_event_t, void *), void *event_param)
36 {
37  self->_event_handler = event_handler;
38  self->_event_param = event_param;
39 }
40 
42 {
43  self->_update_interval = interval;
44 
45  if (self->_update_interval == BC_TICK_INFINITY)
46  {
47  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
48  }
49  else
50  {
51  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
52 
53  bc_sht30_measure(self);
54  }
55 }
56 
58 {
59  if (self->_measurement_active)
60  {
61  return false;
62  }
63 
64  self->_measurement_active = true;
65 
66  bc_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
67 
68  return true;
69 }
70 
71 bool bc_sht30_get_humidity_raw(bc_sht30_t *self, uint16_t *raw)
72 {
73  if (!self->_humidity_valid)
74  {
75  return false;
76  }
77 
78  *raw = self->_reg_humidity;
79 
80  return true;
81 }
82 
83 bool bc_sht30_get_humidity_percentage(bc_sht30_t *self, float *percentage)
84 {
85  uint16_t raw;
86 
87  if (!bc_sht30_get_humidity_raw(self, &raw))
88  {
89  return false;
90  }
91 
92  *percentage = 100.f * (float) raw / (65536.f - 1.f);
93 
94  if (*percentage >= 100.f)
95  {
96  *percentage = 100.f;
97  }
98  else if (*percentage <= 0.f)
99  {
100  *percentage = 0.f;
101  }
102 
103  return true;
104 }
105 
106 bool bc_sht30_get_temperature_raw(bc_sht30_t *self, uint16_t *raw)
107 {
108  if (!self->_temperature_valid)
109  {
110  return false;
111  }
112 
113  *raw = self->_reg_temperature;
114 
115  return true;
116 }
117 
118 bool bc_sht30_get_temperature_celsius(bc_sht30_t *self, float *celsius)
119 {
120  uint16_t raw;
121 
122  if (!bc_sht30_get_temperature_raw(self, &raw))
123  {
124  return false;
125  }
126 
127  *celsius = -45.f + (175.f * (float) raw / (65535.f));
128 
129  return true;
130 }
131 
132 bool bc_sht30_get_temperature_fahrenheit(bc_sht30_t *self, float *fahrenheit)
133 {
134  float celsius;
135 
136  if (!bc_sht30_get_temperature_celsius(self, &celsius))
137  {
138  return false;
139  }
140 
141  *fahrenheit = celsius * 1.8f + 32.f;
142 
143  return true;
144 }
145 
146 bool bc_sht30_get_temperature_kelvin(bc_sht30_t *self, float *kelvin)
147 {
148  float celsius;
149 
150  if (!bc_sht30_get_temperature_celsius(self, &celsius))
151  {
152  return false;
153  }
154 
155  *kelvin = celsius + 273.15f;
156 
157  if (*kelvin < 0.f)
158  {
159  *kelvin = 0.f;
160  }
161 
162  return true;
163 }
164 
165 static void _bc_sht30_task_interval(void *param)
166 {
167  bc_sht30_t *self = param;
168 
169  bc_sht30_measure(self);
170 
171  bc_scheduler_plan_current_relative(self->_update_interval);
172 }
173 
174 static void _bc_sht30_task_measure(void *param)
175 {
176  bc_sht30_t *self = param;
177 
178 start:
179 
180  switch (self->_state)
181  {
182  case BC_SHT30_STATE_ERROR:
183  {
184  self->_humidity_valid = false;
185  self->_temperature_valid = false;
186 
187  self->_measurement_active = false;
188 
189  if (self->_event_handler != NULL)
190  {
191  self->_event_handler(self, BC_SHT30_EVENT_ERROR, self->_event_param);
192  }
193 
194  self->_state = BC_SHT30_STATE_INITIALIZE;
195 
196  return;
197  }
198  case BC_SHT30_STATE_INITIALIZE:
199  {
200  self->_state = BC_SHT30_STATE_ERROR;
201 
202  if (!_bc_sht30_write(self, 0xa230))
203  {
204  goto start;
205  }
206 
207  self->_state = BC_SHT30_STATE_MEASURE;
208 
209  self->_tick_ready = bc_tick_get() + _BC_SHT30_DELAY_INITIALIZATION;
210 
211  if (self->_measurement_active)
212  {
213  bc_scheduler_plan_current_absolute(self->_tick_ready);
214  }
215 
216  return;
217  }
218  case BC_SHT30_STATE_MEASURE:
219  {
220  self->_state = BC_SHT30_STATE_ERROR;
221 
222  if (!_bc_sht30_write(self, 0x0d2c))
223  {
224  goto start;
225  }
226 
227  self->_state = BC_SHT30_STATE_READ;
228 
229  bc_scheduler_plan_current_from_now(_BC_SHT30_DELAY_MEASUREMENT);
230 
231  return;
232  }
233  case BC_SHT30_STATE_READ:
234  {
235  self->_state = BC_SHT30_STATE_ERROR;
236 
237  uint8_t buffer[6];
238 
239  bc_i2c_transfer_t transfer;
240 
241  transfer.device_address = self->_i2c_address;
242  transfer.buffer = buffer;
243  transfer.length = sizeof(buffer);
244 
245  if (!bc_i2c_read(self->_i2c_channel, &transfer))
246  {
247  goto start;
248  }
249 
250  self->_reg_humidity = buffer[3] << 8 | buffer[4];
251  self->_reg_temperature = buffer[0] << 8 | buffer[1];
252 
253  self->_humidity_valid = true;
254  self->_temperature_valid = true;
255 
256  self->_state = BC_SHT30_STATE_UPDATE;
257 
258  goto start;
259  }
260  case BC_SHT30_STATE_UPDATE:
261  {
262  self->_measurement_active = false;
263 
264  if (self->_event_handler != NULL)
265  {
266  self->_event_handler(self, BC_SHT30_EVENT_UPDATE, self->_event_param);
267  }
268 
269  self->_state = BC_SHT30_STATE_MEASURE;
270 
271  return;
272  }
273  default:
274  {
275  self->_state = BC_SHT30_STATE_ERROR;
276 
277  goto start;
278  }
279  }
280 }
281 
282 static bool _bc_sht30_write(bc_sht30_t *self, const uint16_t data)
283 {
284  bc_i2c_transfer_t transfer;
285 
286  transfer.device_address = self->_i2c_address;
287  transfer.buffer = (void *) &data;
288  transfer.length = sizeof(data);
289 
290  return bc_i2c_write(self->_i2c_channel, &transfer);
291 }
I2C transfer parameters.
Definition: bc_i2c.h:42
bool bc_sht30_get_humidity_percentage(bc_sht30_t *self, float *percentage)
Get measured humidity as percentage.
Definition: bc_sht30.c:83
Error event.
Definition: bc_sht30.h:19
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
void bc_sht30_deinit(bc_sht30_t *self)
Deinitialize SHT30.
Definition: bc_sht30.c:28
I2C communication speed is 400 kHz.
Definition: bc_i2c.h:36
struct bc_sht30_t bc_sht30_t
SHT30 instance.
Definition: bc_sht30.h:28
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
bool bc_sht30_get_temperature_raw(bc_sht30_t *self, uint16_t *raw)
Get measured temperature as raw value.
Definition: bc_sht30.c:106
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:45
Update event.
Definition: bc_sht30.h:22
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_sht30_event_t
Callback events.
Definition: bc_sht30.h:16
void bc_sht30_init(bc_sht30_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize SHT30.
Definition: bc_sht30.c: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
bool bc_sht30_get_temperature_fahrenheit(bc_sht30_t *self, float *fahrenheit)
Get measured temperature in degrees of Fahrenheit.
Definition: bc_sht30.c:132
void bc_sht30_set_update_interval(bc_sht30_t *self, bc_tick_t interval)
Set measurement interval.
Definition: bc_sht30.c:41
void bc_sht30_set_event_handler(bc_sht30_t *self, void(*event_handler)(bc_sht30_t *, bc_sht30_event_t, void *), void *event_param)
Set callback function.
Definition: bc_sht30.c:35
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
bc_i2c_channel_t
I2C channels.
Definition: bc_i2c.h:15
size_t length
Length of buffer which is being written or read.
Definition: bc_i2c.h:51
bool bc_sht30_get_humidity_raw(bc_sht30_t *self, uint16_t *raw)
Get measured humidity as raw value.
Definition: bc_sht30.c:71
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_sht30_measure(bc_sht30_t *self)
Start measurement manually.
Definition: bc_sht30.c:57
bool bc_sht30_get_temperature_kelvin(bc_sht30_t *self, float *kelvin)
Get measured temperature in kelvin.
Definition: bc_sht30.c:146
bool bc_sht30_get_temperature_celsius(bc_sht30_t *self, float *celsius)
Get measured temperature in degrees of Celsius.
Definition: bc_sht30.c:118
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80