Improvements to photo resistor-based lux estimation

- Code now compiles
- Estimation of the photo resistor resistance works
- Lux estimation from the photo resistor resistance needs more work and calibration
- Lux is now encoded in the BLE advertisement payload
This commit is contained in:
rbaron 2021-09-02 21:29:11 +02:00
parent dcd0fc4ae1
commit e32803d44d
5 changed files with 38 additions and 16 deletions

View file

@ -11,13 +11,14 @@
#define PRST_PHOTO_OUT NRF_GPIO_PIN_MAP(0, 2)
// Deep sleep.
#define PRST_DEEP_SLEEP_IN_SECONDS 300
#define PRST_DEEP_SLEEP_IN_SECONDS 2
// Analog to digital converter (ADC).
// Prints out ADC debug info, such as the values read for battery and soil
// moisture.
#define PRST_ADC_BATT_DEBUG 0
#define PRST_ADC_SOIL_DEBUG 0
#define PRST_ADC_PHOTO_DEBUG 1
// BLE.
// Prints out BLE debug info, such as the final encoded advertisement packet.
@ -27,7 +28,7 @@
// 1. Two most significant bits are set to 1;
// 2. The remaining bits should not _all_ be set to 0;
// 2. The remaining bits should not _all_ be set to 1;
#define PRST_BLE_MAC_ADDR "f0:ca:f0:ca:00:01"
#define PRST_BLE_MAC_ADDR "f0:ca:f0:ca:01:01"
#define PRST_BLE_ADV_NAME "prst"
// Total time spend advertising.
#define PRST_BLE_ADV_TIME_IN_MS 1000

View file

@ -63,12 +63,13 @@ static void rtc_callback() {
prst_pwm_stop();
nrf_gpio_pin_clear(PRST_FAST_DISCH_PIN);
nrf_gpio_pin_set(PRST_PHOTO_V); // set GPIO for photoresistor HIGH
prst_adc_photo_sensor_t photo_read = prst_adc_photo_read(batt_read.voltage); // read PHOTO SENSOR value
nrf_gpio_pin_clear(PRST_PHOTO_V); // clear GPIO for photoresistor
nrf_gpio_pin_set(PRST_PHOTO_V);
prst_adc_photo_sensor_t photo_read = prst_adc_photo_read(batt_read.voltage);
nrf_gpio_pin_clear(PRST_PHOTO_V);
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_millicelcius,
temp_humi.humidity, soil_read.relative, photo_read.lux, run_counter);
temp_humi.humidity, soil_read.relative,
photo_read.lux, run_counter);
prst_adv_start();
nrf_delay_ms(PRST_BLE_ADV_TIME_IN_MS);
prst_adv_stop();

View file

@ -71,8 +71,8 @@ void prst_adc_init() {
nrf_saadc_channel_config_t photo_channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PRST_ADC_PHOTO_INPUT);
APP_ERROR_CHECK(
nrf_drv_saadc_channel_init(PRST_ADC_PHOTO_CHANNEL, &photo_channel_config));
APP_ERROR_CHECK(nrf_drv_saadc_channel_init(PRST_ADC_PHOTO_CHANNEL,
&photo_channel_config));
}
prst_adc_batt_read_t prst_adc_batt_read() {
@ -131,14 +131,28 @@ prst_adc_soil_moisture_t prst_adc_soil_read(double battery_voltage) {
}
prst_adc_photo_sensor_t prst_adc_photo_read(double battery_voltage) {
nrf_saadc_value_t raw_photo_output = sample_adc_channel(PRST_ADC_PHOTO_CHANNEL);
nrf_saadc_value_t raw_photo_output =
sample_adc_channel(PRST_ADC_PHOTO_CHANNEL);
prst_adc_photo_sensor_t ret;
ret.raw = raw_photo_output;
ret.voltage = (3.6 * raw_photo_output) / (1 << PRST_ADC_RESOLUTION);
ret.lux = (uint16_t)ret.voltage*100000/(battery_voltage-ret.voltage);
#if PRST_ADC_SOIL_DEBUG
NRF_LOG_INFO("[adc] Read lux level: %d (raw); %d (lux)",
ret.raw, ret.lux);
// This value needs to be calibrated.
// The photo resistor forms a voltage divider with a 10 kOhm resistor.
// The voltage here is measured in the middle of the voltage divider.
// Vcc ---- (R_photo) ---|--- (10k) ---- GND
// Vout
// So we can estimate R_photo = R * (Vcc - Vout) / Vout
const double photo_resistance =
1e4 * (battery_voltage - ret.voltage) / ret.voltage;
// TODO: Now that we have the resistor value of the photo resistor, we need to
// estimate the value in lux. This needs to be calibrated with a real board in
// complete dark and in a super bright environment.
// This current value is just a placeholder.
ret.lux = (uint16_t)UINT16_MAX * (photo_resistance / 1e4);
#if PRST_ADC_PHOTO_DEBUG
NRF_LOG_INFO("[adc] Read lux level: %d (raw); %d (lux)", ret.raw, ret.lux);
#endif
return ret;
}

View file

@ -33,8 +33,9 @@
| 6-7 | Relative air humidity, scaled from 0 (0%) to 0xffff (100%) |
| 8-9 | Soil moisture, scaled from from 0 (0%) to 0xffff (100%) |
| 10-15 | b-parasite's own MAC address |
| 16-17 | Lux level from the photoresistor |
*/
#define SERVICE_DATA_LEN 16
#define SERVICE_DATA_LEN 18
static uint8_t service_data[SERVICE_DATA_LEN];
// Stores the encoded advertisement data. As per BLE spec, 31 bytes max.
@ -135,7 +136,8 @@ void prst_ble_init() {
void prst_ble_update_adv_data(uint16_t batt_millivolts,
uint16_t temp_millicelcius, uint16_t humidity,
uint16_t soil_moisture, uint8_t run_counter) {
uint16_t soil_moisture, uint16_t lux,
uint8_t run_counter) {
// 4 bits for a small wrap-around counter for deduplicating messages on the
// receiver.
service_data[1] = run_counter & 0x0f;
@ -152,6 +154,9 @@ void prst_ble_update_adv_data(uint16_t batt_millivolts,
service_data[8] = soil_moisture >> 8;
service_data[9] = soil_moisture & 0xff;
service_data[16] = lux >> 8;
service_data[17] = lux & 0xff;
// Encodes adv_data_ into .gap_adv_data_.
uint32_t err_code = ble_advdata_encode(
&adv_data_, gap_adv_data_.adv_data.p_data, &gap_adv_data_.adv_data.len);

View file

@ -13,6 +13,7 @@ void prst_adv_stop();
void prst_ble_update_adv_data(uint16_t batt_millivolts,
uint16_t temp_millicelcius, uint16_t humidity,
uint16_t soil_moisture, uint8_t run_counter);
uint16_t soil_moisture, uint16_t lux,
uint8_t run_counter);
#endif // _PRST_BLE_H_