Puts soil moisture reading into the BLE advertisement packet
This commit is contained in:
parent
30162f4628
commit
6ec48b7188
6 changed files with 56 additions and 25 deletions
|
|
@ -7,11 +7,12 @@
|
||||||
#define PRST_LED_PIN NRF_GPIO_PIN_MAP(0, 28)
|
#define PRST_LED_PIN NRF_GPIO_PIN_MAP(0, 28)
|
||||||
|
|
||||||
// Deep sleep.
|
// Deep sleep.
|
||||||
#define PRST_DEEP_SLEEP_IN_SECONDS 2
|
#define PRST_DEEP_SLEEP_IN_SECONDS 3
|
||||||
|
|
||||||
// Analog to digital converter (ADC).
|
// Analog to digital converter (ADC).
|
||||||
// Prints out ADC debug info, such as the values read for battery and soil moisture.
|
// Prints out ADC debug info, such as the values read for battery and soil
|
||||||
#define PRST_ADC_DEBUG 1
|
// moisture.
|
||||||
|
#define PRST_ADC_DEBUG 0
|
||||||
|
|
||||||
// BLE.
|
// BLE.
|
||||||
#define PRST_BLE_ADV_NAME "prst"
|
#define PRST_BLE_ADV_NAME "prst"
|
||||||
|
|
@ -22,4 +23,7 @@
|
||||||
#define PRST_PWM_PIN NRF_GPIO_PIN_MAP(0, 5)
|
#define PRST_PWM_PIN NRF_GPIO_PIN_MAP(0, 5)
|
||||||
#define PRST_FAST_DISCH_PIN NRF_GPIO_PIN_MAP(1, 10)
|
#define PRST_FAST_DISCH_PIN NRF_GPIO_PIN_MAP(1, 10)
|
||||||
|
|
||||||
|
// SHT3C temp/humidity sensor.
|
||||||
|
#define PRST_SHT3C_DEBUG 1
|
||||||
|
|
||||||
#endif // _PRST_CONFIG_H_
|
#endif // _PRST_CONFIG_H_
|
||||||
|
|
@ -11343,7 +11343,7 @@
|
||||||
// <2=> BLOCK_IF_FIFO_FULL
|
// <2=> BLOCK_IF_FIFO_FULL
|
||||||
|
|
||||||
#ifndef SEGGER_RTT_CONFIG_DEFAULT_MODE
|
#ifndef SEGGER_RTT_CONFIG_DEFAULT_MODE
|
||||||
#define SEGGER_RTT_CONFIG_DEFAULT_MODE 2
|
#define SEGGER_RTT_CONFIG_DEFAULT_MODE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// </h>
|
// </h>
|
||||||
|
|
|
||||||
|
|
@ -58,31 +58,22 @@ static void power_manage(void) {
|
||||||
// Here we need to be extra careful with what operations we do. This callback
|
// Here we need to be extra careful with what operations we do. This callback
|
||||||
// has to return fast-ish, otherwise we hit some hard exceptions.
|
// has to return fast-ish, otherwise we hit some hard exceptions.
|
||||||
static void rtc_callback() {
|
static void rtc_callback() {
|
||||||
NRF_LOG_INFO("Batt raw ");
|
|
||||||
NRF_LOG_FLUSH();
|
|
||||||
nrf_gpio_pin_set(PRST_LED_PIN);
|
nrf_gpio_pin_set(PRST_LED_PIN);
|
||||||
prst_shtc3_read_t temp_humi = prst_shtc3_read();
|
prst_shtc3_read_t temp_humi = prst_shtc3_read();
|
||||||
nrf_gpio_pin_set(PRST_FAST_DISCH_PIN);
|
nrf_gpio_pin_set(PRST_FAST_DISCH_PIN);
|
||||||
prst_pwm_init();
|
prst_pwm_init();
|
||||||
prst_pwm_start();
|
prst_pwm_start();
|
||||||
prst_adc_batt_read_t batt_read = prst_adc_batt_read();
|
prst_adc_batt_read_t batt_read = prst_adc_batt_read();
|
||||||
int16_t soil_read = prst_adc_soil_read();
|
prst_adc_soil_moisture_t soil_read = prst_adc_soil_read();
|
||||||
prst_pwm_stop();
|
prst_pwm_stop();
|
||||||
nrf_gpio_pin_clear(PRST_FAST_DISCH_PIN);
|
nrf_gpio_pin_clear(PRST_FAST_DISCH_PIN);
|
||||||
NRF_LOG_INFO("Read soil: %d", soil_read);
|
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_millicelcius,
|
||||||
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_millicelcius, temp_humi.humidity, 0);
|
temp_humi.humidity, soil_read.relative);
|
||||||
NRF_LOG_FLUSH();
|
NRF_LOG_FLUSH();
|
||||||
prst_adv_start();
|
prst_adv_start();
|
||||||
nrf_delay_ms(200);
|
nrf_delay_ms(200);
|
||||||
prst_adv_stop();
|
prst_adv_stop();
|
||||||
nrf_gpio_pin_clear(PRST_LED_PIN);
|
nrf_gpio_pin_clear(PRST_LED_PIN);
|
||||||
UNUSED_VARIABLE(batt_read);
|
|
||||||
// NRF_LOG_INFO("Read batt: " NRF_LOG_FLOAT_MARKER " V (%d), %u mV",
|
|
||||||
// NRF_LOG_FLOAT(batt_read.voltage), batt_read.raw, batt_read.millivolts);
|
|
||||||
// NRF_LOG_INFO("Read temp: " NRF_LOG_FLOAT_MARKER " oC",
|
|
||||||
// NRF_LOG_FLOAT((float) temp_humi.temp_millicelcius / 1000.0));
|
|
||||||
// NRF_LOG_INFO("Read humi: " NRF_LOG_FLOAT_MARKER " %%",
|
|
||||||
// NRF_LOG_FLOAT(100.0 * temp_humi.humidity / (1 << 16)));
|
|
||||||
NRF_LOG_FLUSH();
|
NRF_LOG_FLUSH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,11 +85,18 @@ int main(void) {
|
||||||
prst_ble_init();
|
prst_ble_init();
|
||||||
prst_adc_init();
|
prst_adc_init();
|
||||||
prst_shtc3_init();
|
prst_shtc3_init();
|
||||||
|
|
||||||
|
// Set up RTC. It will call our custom callback at a regular interval, defined
|
||||||
|
// by PRST_DEEP_SLEEP_IN_SECONDS.
|
||||||
prst_rtc_set_callback(rtc_callback);
|
prst_rtc_set_callback(rtc_callback);
|
||||||
prst_rtc_init();
|
prst_rtc_init();
|
||||||
|
|
||||||
nrf_delay_ms(100);
|
// In addition to scheduling it, let's immediatelly call it - it makes
|
||||||
|
// debugging less tedious.
|
||||||
|
rtc_callback();
|
||||||
|
|
||||||
|
// Here we go into a low energy mode. The datasheet calls this mode "System
|
||||||
|
// ON", and in my tests it consumes around 2.7uA.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
power_manage();
|
power_manage();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ static nrf_saadc_value_t sample_adc_channel(uint8_t channel) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Caps the argument to the [0, 1] range.
|
||||||
|
static inline double cap_value(double value) {
|
||||||
|
return value > 1.0 ? 1.0 : (value < 0.0 ? 0.0 : value);
|
||||||
|
}
|
||||||
|
|
||||||
// Unused, since we'll call the SAADC synchronously for now.
|
// Unused, since we'll call the SAADC synchronously for now.
|
||||||
void saadc_callback(nrf_drv_saadc_evt_t const* p_event) {
|
void saadc_callback(nrf_drv_saadc_evt_t const* p_event) {
|
||||||
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) {
|
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) {
|
||||||
|
|
@ -69,16 +74,23 @@ prst_adc_batt_read_t prst_adc_batt_read() {
|
||||||
ret.voltage = (3.6 * result) / (1 << PRST_ADC_RESOLUTION);
|
ret.voltage = (3.6 * result) / (1 << PRST_ADC_RESOLUTION);
|
||||||
ret.millivolts = ret.voltage * 1000;
|
ret.millivolts = ret.voltage * 1000;
|
||||||
#if PRST_ADC_DEBUG
|
#if PRST_ADC_DEBUG
|
||||||
NRF_LOG_INFO("[adc] Read battery voltage: %d (raw); %d mV; ", ret.raw, ret.millivolts,
|
NRF_LOG_INFO("[adc] Read battery voltage: %d (raw); %d mV; ", ret.raw,
|
||||||
ret.voltage);
|
ret.millivolts, ret.voltage);
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t prst_adc_soil_read() {
|
prst_adc_soil_moisture_t prst_adc_soil_read() {
|
||||||
nrf_saadc_value_t result = sample_adc_channel(PRST_ADC_SOIL_CHANNEL);
|
nrf_saadc_value_t result = sample_adc_channel(PRST_ADC_SOIL_CHANNEL);
|
||||||
|
double percentage = cap_value(((double)result - PRST_SOIL_DRY) /
|
||||||
|
(PRST_SOIL_WET - PRST_SOIL_DRY));
|
||||||
|
prst_adc_soil_moisture_t ret;
|
||||||
|
ret.raw = result;
|
||||||
|
ret.relative = percentage * (1 << 16);
|
||||||
#if PRST_ADC_DEBUG
|
#if PRST_ADC_DEBUG
|
||||||
NRF_LOG_INFO("[adc] Read soil moisture: %d", result);
|
NRF_LOG_INFO("[adc] Read soil moisture: %d (raw); " NRF_LOG_FLOAT_MARKER
|
||||||
|
" %% (percentage); %u (relative)",
|
||||||
|
ret.raw, NRF_LOG_FLOAT(percentage * 100), ret.relative);
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -3,16 +3,29 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// ADC values. Assumes 10 bits resolution.
|
||||||
|
// TODO(rbaron) this values drift a little bit as the battery discharges.
|
||||||
|
// I previously did a hacky linear regression to estimate them, but I'm
|
||||||
|
// not super sure how useful that is.
|
||||||
|
#define PRST_SOIL_WET 200
|
||||||
|
#define PRST_SOIL_DRY 500
|
||||||
|
|
||||||
typedef struct prst_adc_batt_val {
|
typedef struct prst_adc_batt_val {
|
||||||
int16_t raw;
|
int16_t raw;
|
||||||
uint16_t millivolts;
|
uint16_t millivolts;
|
||||||
double voltage;
|
double voltage;
|
||||||
} prst_adc_batt_read_t;
|
} prst_adc_batt_read_t;
|
||||||
|
|
||||||
|
typedef struct prst_adc_soil_moisture {
|
||||||
|
int16_t raw;
|
||||||
|
// A value from 0 (cmopletely dry) to 2^10 (completely wet).
|
||||||
|
uint16_t relative;
|
||||||
|
} prst_adc_soil_moisture_t;
|
||||||
|
|
||||||
void prst_adc_init();
|
void prst_adc_init();
|
||||||
|
|
||||||
prst_adc_batt_read_t prst_adc_batt_read();
|
prst_adc_batt_read_t prst_adc_batt_read();
|
||||||
|
|
||||||
int16_t prst_adc_soil_read();
|
prst_adc_soil_moisture_t prst_adc_soil_read();
|
||||||
|
|
||||||
#endif // _PRST_ADC_H_
|
#endif // _PRST_ADC_H_
|
||||||
|
|
@ -47,12 +47,16 @@ prst_shtc3_read_t prst_shtc3_read() {
|
||||||
// TODO(rbaron): verify the CRC of the measurements. The function is described
|
// TODO(rbaron): verify the CRC of the measurements. The function is described
|
||||||
// in the datasheet.
|
// in the datasheet.
|
||||||
|
|
||||||
NRF_LOG_INFO("Computing...");
|
|
||||||
double temp_c = -45 + 175 * ((double)((buff[0] << 8) | buff[1])) / (1 << 16);
|
double temp_c = -45 + 175 * ((double)((buff[0] << 8) | buff[1])) / (1 << 16);
|
||||||
// double humi = ((double)((buff[3] << 8) | buff[4])) / ((1 << 16) - 1);
|
|
||||||
uint16_t humi = (buff[3] << 8) | buff[4];
|
uint16_t humi = (buff[3] << 8) | buff[4];
|
||||||
|
|
||||||
prst_shtc3_read_t ret = {.temp_millicelcius = temp_c * 1000,
|
prst_shtc3_read_t ret = {.temp_millicelcius = temp_c * 1000,
|
||||||
.humidity = humi};
|
.humidity = humi};
|
||||||
|
#if PRST_SHT3C_DEBUG
|
||||||
|
NRF_LOG_INFO("[sht3c] Read temp: " NRF_LOG_FLOAT_MARKER " oC",
|
||||||
|
NRF_LOG_FLOAT((float)temp_humi.temp_millicelcius / 1000.0));
|
||||||
|
NRF_LOG_INFO("[sht3c] Read humi: " NRF_LOG_FLOAT_MARKER " %%",
|
||||||
|
NRF_LOG_FLOAT(100.0 * temp_humi.humidity / (1 << 16)));
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue