IoT-MBBR (masterthesis)
Masterthesis upgrading a Moving Bed BioReactor with extra sensors and cloud connectivity.
main.c File Reference

The main file for the IoT-MBBR project. More...

#include <stdint.h>
#include <stdbool.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_rtc.h"
#include "pin_mapping.h"
#include "debug_dbprint.h"
#include "delay.h"
#include "util.h"
#include "util_string.h"
#include "interrupt.h"
#include "DS18B20.h"
#include "adc.h"
#include "datatypes.h"
#include "serlcd.h"
#include "BG96_at_driver.h"
#include "VL53L1X.h"
#include "SHT30.h"

Go to the source code of this file.

Macros

#define SEND_STATUS_BOOT   1
 
#define SENDING_DATA   1
 
#define MAX_LENGTH_MM   300
 
#define WAKE_UP_PERIOD_S   3600 /* 360 = every 5 minutes */
 

Functions

bool checkBTNinterrupts (void)
 Method to check if any interrupts are triggered by buttons. More...
 
void displayMeas (void)
 Method to display the latest measurements on the LCD. More...
 
int main (void)
 Main function. More...
 
void NMI_Handler (void)
 NMI interrupt service routine. More...
 
void HardFault_Handler (void)
 HardFault interrupt service routine. More...
 
void SVC_Handler (void)
 SVC interrupt service routine. More...
 
void PendSV_Handler (void)
 PendSV interrupt service routine. More...
 

Variables

static MCU_State_t MCUstate
 
MeasurementData_t data
 

Detailed Description

The main file for the IoT-MBBR project.

Version
1.1
Author
Brecht Van Eeckhoudt

Versions

    • v1.0: Initial version.
    • v1.1: Changed float to float32_t, added ADC measurement functionality.

License

Copyright (C) 2020 - Brecht Van Eeckhoudt

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

A copy of the GNU General Public License can be found in the LICENSE file along with this source code.


Some methods also use code obtained from examples from Silicon Labs' GitHub. These sections are licensed under the Silabs License Agreement. See the file "Silabs_License_Agreement.txt" for details. Before using this software for any purpose, you must agree to the terms of that agreement.

Definition in file main.c.

Macro Definition Documentation

◆ MAX_LENGTH_MM

#define MAX_LENGTH_MM   300

Maximum measured height for percent calculation [mm]

Definition at line 74 of file main.c.

◆ SEND_STATUS_BOOT

#define SEND_STATUS_BOOT   1

Enable (1) or disable (0) the status = 0 message

Definition at line 68 of file main.c.

◆ SENDING_DATA

#define SENDING_DATA   1

Enable (1) or disable (0) sending of messages (for debugging)

Definition at line 71 of file main.c.

◆ WAKE_UP_PERIOD_S

#define WAKE_UP_PERIOD_S   3600 /* 360 = every 5 minutes */

Time between each wake-up in seconds

  • max 500 seconds when using LFXO delay
  • 3600 seconds (one hour) works fine when using ULFRCO delay

Definition at line 79 of file main.c.

Function Documentation

◆ checkBTNinterrupts()

bool checkBTNinterrupts ( void  )

Method to check if any interrupts are triggered by buttons.

Returns
  • true - A button interrupt was triggered.
  • false - No button interrupt was triggered.

Definition at line 97 of file main.c.

98 {
99  bool value = false;
100 
101  if (BTN_getTriggered())
102  {
103  value = true;
104 
105  BTN_setTriggered(false); /* Clear variable */
106  }
107 
108  return (value);
109 }
bool BTN_getTriggered(void)
Getter for the BTN_triggered variable.
Definition: interrupt.c:137
void BTN_setTriggered(bool value)
Setter for the BTN_triggered variable.
Definition: interrupt.c:150

◆ displayMeas()

void displayMeas ( void  )

Method to display the latest measurements on the LCD.

Definition at line 116 of file main.c.

117 {
118  setCursorLCD(1, 2); /* Move to second row, first column */
119  writeStringLCD("T1 ");
120 
121  uint16_t temp1 = data.t1;
122  if (data.t1 > 9999) temp1 /= 10; /* Remove last digit */ // TODO: round up/down!
123  uint8_t temp1L = temp1 / 100;
124  uint8_t temp1R = temp1 - ((temp1 / 100) * 100);
125  char temp1L_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
126  char temp1R_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
127  uint32_to_charDec(temp1L, temp1L_char); // TODO: display negative values!
128  uint32_to_charDec(temp1R, temp1R_char); // TODO: display negative values!
129 
130  writeStringLCD(temp1L_char);
131  writeStringLCD(".");
132  writeStringLCD(temp1R_char);
133  writeStringLCD("C T2 ");
134 
135  uint16_t temp2= data.t2;
136  if (data.t2 > 9999) temp2 /= 10; /* Remove last digit */ // TODO: round up/down!
137  uint8_t temp2L = temp2 / 100;
138  uint8_t temp2R = temp2 - ((temp2 / 100) * 100);
139  char temp2L_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
140  char temp2R_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
141  uint32_to_charDec(temp2L, temp2L_char); // TODO: display negative values!
142  uint32_to_charDec(temp2R, temp2R_char); // TODO: display negative values!
143 
144  writeStringLCD(temp2L_char);
145  writeStringLCD(".");
146  writeStringLCD(temp2R_char);
147  writeStringLCD("C");
148 
149  setCursorLCD(1, 3); /* Move to third row, first column */
150  writeStringLCD("N1 ");
151 
152  char nitr1_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
153  uint32_to_charDec(data.n1, nitr1_char);
154 
155  writeStringLCD(nitr1_char);
156  writeStringLCD("mA N2 ");
157 
158  char nitr2_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
159  uint32_to_charDec(data.n2, nitr2_char);
160 
161  writeStringLCD(nitr2_char);
162  writeStringLCD("mA C");
163 
164  char carbon_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
165  uint32_to_charDec(data.c, carbon_char);
166 
167  writeStringLCD(carbon_char);
168  writeStringLCD("%");
169 
170  setCursorLCD(1, 4); /* Move to fourth row, first column */
171  writeStringLCD("pH ");
172 
173  char pH_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
174  uint32_to_charDec(data.p, pH_char);
175 
176  writeStringLCD(pH_char);
177  writeStringLCD("mA RP ");
178 
179  char red_char[10]; // TODO: Use less chars here because we use uint16_t (check if values aren't bigger than 0xFFFF)
180  uint32_to_charDec(data.r, red_char);
181 
182  writeStringLCD(red_char);
183  writeStringLCD("mA");
184 
185  delay(50); /* Delay so all of the data is shown on the screen */
186 }
MeasurementData_t data
Definition: main.c:86
int8_t writeStringLCD(char *message)
Print a string (char array) to the LCD.
Definition: serlcd.c:264
static void uint32_to_charDec(char *buf, uint32_t value)
Convert a uint32_t value to a decimal char array (string).
Definition: dbprint.c:1124
void delay(uint32_t msDelay)
Wait for a certain amount of milliseconds in EM2/3.
Definition: delay.c:124
int8_t setCursorLCD(uint8_t col, uint8_t row)
Set the cursor to a specific location on the LCD.
Definition: serlcd.c:316
unsigned short uint16_t
Typedef defining 16 bit unsigned short type. The developer should modify this to suit the platform be...
Definition: vl53l1_types.h:88
unsigned char uint8_t
Typedef defining 8 bit unsigned char type. The developer should modify this to suit the platform bein...
Definition: vl53l1_types.h:98

◆ HardFault_Handler()

void HardFault_Handler ( void  )

HardFault interrupt service routine.

Note
The weak definition for this method is located in startup_gcc_efm32hg.h.

Definition at line 461 of file main.c.

462 {
463  while(1);
464 }

◆ main()

int main ( void  )

Main function.

Definition at line 193 of file main.c.

194 {
195  /* Value to keep the remaining sleep time when waking up using the accelerometer */
196  uint32_t remainingSleeptime = 0;
197 
198  while (1)
199  {
200  switch (MCUstate)
201  {
202  case INIT:
203  {
204  /* Initialize chip */
205  CHIP_Init();
206 
207 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
208  dbprint_INIT(DBG_UART, DBG_UART_LOC, false, false);
209 #endif /* DEBUG_DBPRINT */
210 
211  /* Initialize delay and sleep functionality */
212  delay(0);
213  sleep(2); /* Time so the I2C devices have time to start up */
214 
215  /* Initialize the LCD */
216  clearLCD();
217  writeStringLCD("Initializing...");
218 
219  /* Soft reset SHT30 */ // TODO: SHT30 (0x88) seems to respond to VL53L1X (0x52) commands and break the I2C bus until power cycle
220 // softResetSHT30();
221 // delay(2000);
222 
223  /* Initialize GPIO wake-up */
224  initGPIOwakeup();
225 
226  /* Init VL53L1X */
227  initVL53L1X();
228 
229  /* Init ADC */
230  initADC(CH1);
231 
232  /* Initialize BG96 */
233 #if SENDING_DATA == 1 /* SENDING_DATA */
234  initBG96();
235 #endif /* SENDING_DATA */
236 
237 #if SEND_STATUS_BOOT == 1 /* SEND_STATUS_BOOT */
238 
239 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
240  dbwarn("Sending startup status ...");
241 #endif /* DEBUG_DBPRINT */
242 
243  clearLCD();
244  writeStringLCD("Sending status (0)");
245 
246 #if SENDING_DATA == 1 /* SENDING_DATA */
247  sendStatus(0); /* Send the status data */
248 #endif /* SENDING_DATA */
249 
250 #endif /* SEND_STATUS_BOOT */
251 
252  MCUstate = MEASURE;
253  } break;
254 
255  case MEASURE:
256  {
257  clearLCD();
258  writeStringLCD("Measuring...");
259  displayMeas(); /* Display measurements on following rows */
260 
261  /* Measure and store the temperatures */
262  int32_t temp = readTempDS18B20(0);
263  if (temp < 0) data.t1 = 0;
264  else data.t1 = temp;
265 
266  temp = readTempDS18B20(1);
267  if (temp < 0) data.t2 = 0;
268  else data.t2 = temp;
269 
270 // data.t2 = SHT30_readTemp(); // TODO: SHT30 (0x88) seems to respond to VL53L1X (0x52) commands and break the I2C bus until power cycle
271 
272  /* Measure and store distance */
273  uint16_t distance = measureVL53L1X();
274 
275 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
276  dbinfoInt("distance = ", distance, " mm");
277 #endif /* DEBUG_DBPRINT */
278 
279  data.c = (uint16_t)(((float32_t)(MAX_LENGTH_MM - measureVL53L1X()) / MAX_LENGTH_MM) * 100.0);
280 
281  data.n1 = readADC(CH1);
282 
283  // TODO: measure more things!
284  data.n2 = 20;
285  data.p = 20;
286  data.r = 20;
287 
288 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
289  dbprintln("");
290  dbinfoInt(">> t1: ", data.t1, "");
291  dbinfoInt(">> t2: ", data.t2, "");
292  dbinfoInt(">> c: ", data.c, " %");
293  dbinfoInt(">> n1: ", data.n1, " mA");
294  dbinfoInt(">> n2: ", data.n2, " mA");
295  dbinfoInt(">> p: ", data.p, " mA");
296  dbinfoInt(">> r: ", data.r, " mA");
297  dbprintln("");
298 #endif /* DEBUG_DBPRINT */
299 
301  } break;
302 
303  case SEND_DATA:
304  {
305 
306 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
307  dbwarn("Sending measurements ...");
308 #endif /* DEBUG_DBPRINT */
309 
310  clearLCD();
311  writeStringLCD("Sending measurements");
312  displayMeas(); /* Display measurements on following rows */
313 
314 #if SENDING_DATA == 1 /* SENDING_DATA */
316 #endif /* SENDING_DATA */
317 
318  MCUstate = SLEEP;
319  } break;
320 
321  case SEND_STATUS:
322  {
323 
324 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
325  dbwarn("Sending STATUS ...");
326 #endif /* DEBUG_DBPRINT */
327 
328  // TODO
329 
330  MCUstate = SLEEP;
331  } break;
332 
333  case SLEEP:
334  {
335  clearLCD();
336  writeStringLCD("Waiting...");
337  displayMeas(); /* Display measurements on following rows */
338 
339 
340  sleep(WAKE_UP_PERIOD_S); /* Go to sleep for xx seconds */
341 
342  MCUstate = WAKEUP;
343  } break;
344 
345  case WAKEUP:
346  {
347  /* Check if we woke up using a button */
348  if (checkBTNinterrupts())
349  {
350 
351 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
352  dbprintln(" ");
353  dbprintln_color("BTN INT", 4);
354 #endif /* DEBUG_DBPRINT */
355 
356  remainingSleeptime = 0; /* Reset passed sleeping time */
357  }
358 
359  /* Check if we woke up using the RTC sleep functionality and act accordingly */
360  if (RTC_checkWakeup())
361  {
362  RTC_clearWakeup(); /* Clear variable */
363 
364 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
365  dbprintln(" ");
366  dbprintln_color("RTC INT", 4);
367 #endif /* DEBUG_DBPRINT */
368 
369  remainingSleeptime = 0; /* Reset passed sleeping time since it's an RTC wakeup */
370  }
371 
372  /* Check if we woke up because of a current pulse */
374  {
375  RTC_Enable(false); /* Disable the counter */
376 
377 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
378  dbprintln(" ");
379  dbprintln_color("PULSE INT", 4);
380 #endif /* DEBUG_DBPRINT */
381 
382  clearLCD();
383  writeStringLCD("Sending pulses...");
384  displayMeas(); /* Display measurements on following rows */
385 
386  if (PULSE_getTriggered(0))
387  {
388 
389 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
390  dbwarn("Sending P1 pulses ...");
391 #endif /* DEBUG_DBPRINT */
392 
393 #if SENDING_DATA == 1 /* SENDING_DATA */
394  sendPulse (0, 1);
395 #endif /* SENDING_DATA */
396 
397  PULSE_setTriggered(0, false);
398  }
399  else if (PULSE_getTriggered(1))
400  {
401 
402 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
403  dbwarn("Sending P2 pulses ...");
404 #endif /* DEBUG_DBPRINT */
405 
406 #if SENDING_DATA == 1 /* SENDING_DATA */
407  sendPulse (1, 1);
408 #endif /* SENDING_DATA */
409 
410  PULSE_setTriggered(1, false);
411  }
412 
413  MCUstate = WAKEUP;
414 
415  clearLCD();
416  writeStringLCD("Waiting...");
417  displayMeas(); /* Display measurements on following rows */
418 
419  remainingSleeptime += RTC_getPassedSleeptime(); /* Add the time spend sleeping to the variable */
420 
421  /* Go back to sleep for the remaining time until another measurement (we only take measurements on RTC/button wake-up) */
422  sleep(WAKE_UP_PERIOD_S - remainingSleeptime);
423 
424  }
425  else
426  {
427  MCUstate = MEASURE;
428  }
429 
430  } break;
431 
432  default:
433  {
434  error(10);
435  } break;
436  }
437  }
438 }
bool checkBTNinterrupts(void)
Method to check if any interrupts are triggered by buttons.
Definition: main.c:97
void initADC(ADC_Measurement_t peripheral)
Method to initialize the ADC to later check the battery voltage or internal temperature.
Definition: adc.c:87
void sendStatus(int8_t status)
Send status to the cloud using NB-IoT.
#define DBG_UART
Definition: pin_mapping.h:89
void dbprintln(char *message)
Print a string (char array) to USARTx and go to the next line.
Definition: dbprint.c:397
void dbinfoInt(char *message1, int32_t value, char *message2)
Print an info value surrounded by two strings (char array) to USARTx.
Definition: dbprint.c:569
int8_t initVL53L1X(void)
Initialize the sensor.
Definition: VL43L1X.c:69
int8_t clearLCD(void)
Clear the LCD.
Definition: serlcd.c:168
MeasurementData_t data
Definition: main.c:86
#define DBG_UART_LOC
Definition: pin_mapping.h:90
void dbwarn(char *message)
Print a warning string (char array) in yellow to USARTx and go to the next line.
Definition: dbprint.c:523
void initBG96(void)
Initialize the GPIO pins and UART0 module necessary to communicate with the BG96 module.
void sendMeasurements(MeasurementData_t *data)
Send measurements to the cloud using NB-IoT.
Definition: adc.h:50
uint16_t measureVL53L1X(void)
Get a sensor reading.
Definition: VL43L1X.c:160
int8_t writeStringLCD(char *message)
Print a string (char array) to the LCD.
Definition: serlcd.c:264
void error(uint8_t number)
Error method.
Definition: util.c:122
uint32_t RTC_getPassedSleeptime(void)
Method to get the time spend sleeping (in seconds) in the case of GPIO wake-up.
Definition: delay.c:456
int int32_t
Typedef defining 32 bit int type. The developer should modify this to suit the platform being deploye...
Definition: vl53l1_types.h:83
void initGPIOwakeup(void)
Initialize GPIO wake-up functionality.
Definition: interrupt.c:91
void PULSE_setTriggered(uint8_t number, bool value)
Setter for the PULSE0/1_triggered variable.
Definition: interrupt.c:187
void dbprint_INIT(USART_TypeDef *pointer, uint8_t location, bool vcom, bool interrupts)
Initialize USARTx.
Definition: dbprint.c:150
void RTC_clearWakeup(void)
Method to clear RTC_sleep_wakeup.
Definition: delay.c:442
bool PULSE_getTriggered(uint8_t number)
Getter for the PULSE0/1_triggered variable.
Definition: interrupt.c:167
#define MAX_LENGTH_MM
Definition: main.c:74
void delay(uint32_t msDelay)
Wait for a certain amount of milliseconds in EM2/3.
Definition: delay.c:124
void displayMeas(void)
Method to display the latest measurements on the LCD.
Definition: main.c:116
void sendPulse(uint8_t number, uint8_t pulse)
Send current pulses to the cloud using NB-IoT.
#define WAKE_UP_PERIOD_S
Definition: main.c:79
static MCU_State_t MCUstate
Definition: main.c:83
int32_t readADC(ADC_Measurement_t peripheral)
Method to read the battery voltage or internal temperature.
Definition: adc.c:189
Definition: datatypes.h:54
bool RTC_checkWakeup(void)
Method to check if the wakeup was caused by the RTC.
Definition: delay.c:432
void dbprintln_color(char *message, dbprint_color_t color)
Print a string (char array) to USARTx in a given color and go to the next line.
Definition: dbprint.c:482
void sleep(uint32_t sSleep)
Sleep for a certain amount of seconds in EM2/3.
Definition: delay.c:293
int32_t readTempDS18B20(uint8_t number)
Get a temperature value from the DS18B20.
Definition: DS18B20.c:119
unsigned short uint16_t
Typedef defining 16 bit unsigned short type. The developer should modify this to suit the platform be...
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type. The developer should modify this to suit the platform bein...
Definition: vl53l1_types.h:78

◆ NMI_Handler()

void NMI_Handler ( void  )

NMI interrupt service routine.

Note
The weak definition for this method is located in startup_gcc_efm32hg.h.

Definition at line 448 of file main.c.

449 {
450  while(1);
451 }

◆ PendSV_Handler()

void PendSV_Handler ( void  )

PendSV interrupt service routine.

Note
The weak definition for this method is located in startup_gcc_efm32hg.h.

Definition at line 487 of file main.c.

488 {
489  while(1);
490 }

◆ SVC_Handler()

void SVC_Handler ( void  )

SVC interrupt service routine.

Note
The weak definition for this method is located in startup_gcc_efm32hg.h.

Definition at line 474 of file main.c.

475 {
476  while(1);
477 }

Variable Documentation

◆ data

Keep the measurement data

Definition at line 86 of file main.c.

◆ MCUstate

MCU_State_t MCUstate
static

Keep the state of the state machine

Definition at line 83 of file main.c.