Created
September 26, 2025 06:54
-
-
Save lptr/ccdc23f15069fada8be5228f144823e7 to your computer and use it in GitHub Desktop.
FDC1004 for soil moisture IDC sensor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ////////////////////////////////////////////////////////////////////////////////////////// | |
| // | |
| // Basic Single channel demo for the FDC1004 capacitance sensor breakout board | |
| // | |
| // Author: Ashwin Whitchurch | |
| // Copyright (c) 2018-2025 Protocentral Electronics | |
| // | |
| // This example measures capacitance on CHANNEL0 with | |
| // automatic CAPDAC adjustment. | |
| // | |
| // Arduino connections: | |
| // | |
| // Arduino FDC1004 board | |
| // ------- ------------- | |
| // 5V -> Vin | |
| // GND -> GND | |
| // A4 -> SDA | |
| // A5 -> SCL | |
| // | |
| // For boards with multiple I2C interfaces (ESP32, Arduino Mega, etc.): | |
| // You can use Wire1 or other I2C interfaces by modifying the constructor. | |
| // See the constructor examples below. | |
| // | |
| // This software is licensed under the MIT License(http://opensource.org/licenses/MIT). | |
| // | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT | |
| // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
| // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
| // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| // | |
| // For information on how to use, visit https://github.com/protocentral/ProtoCentral_fdc1004_breakout | |
| // | |
| ///////////////////////////////////////////////////////////////////////////////////////// | |
| #include <Wire.h> | |
| #include <Protocentral_FDC1004.h> | |
| // Constructor Options - Choose one of the following: | |
| // Option 1: Default Wire interface (backwards compatible) | |
| FDC1004 capacitanceSensor(FDC1004_RATE_100HZ); | |
| // Option 2: Specify custom I2C interface (for boards with multiple I2C ports) | |
| // FDC1004 capacitanceSensor(&Wire1, FDC1004_RATE_100HZ); | |
| // Option 3: Alternative syntax with TwoWire as third parameter | |
| // FDC1004 capacitanceSensor(FDC1004_RATE_100HZ, FDC1004_I2C_ADDRESS, &Wire1); | |
| // Option 4: Custom I2C address with default Wire | |
| // FDC1004 capacitanceSensor(FDC1004_RATE_100HZ, 0x51); // Different address | |
| void setup() { | |
| Serial.begin(115200); | |
| // Initialize I2C interface | |
| // Note: If using Wire1 or custom I2C interface, initialize that instead | |
| // Example for ESP32 with custom pins: Wire1.begin(21, 22); | |
| Wire.begin(4, 5); | |
| Serial.println("FDC1004 Capacitance Sensor"); | |
| Serial.println("=========================="); | |
| Serial.println("Using default Wire interface"); | |
| Serial.println(); | |
| // Initialize the sensor with error checking | |
| if (capacitanceSensor.begin()) { | |
| Serial.println("✓ FDC1004 sensor initialized successfully"); | |
| } else { | |
| Serial.println("✗ Failed to initialize FDC1004 sensor"); | |
| Serial.println("Check wiring and restart Arduino"); | |
| while (1) { | |
| delay(1000); | |
| } | |
| } | |
| // Verify device connection | |
| if (capacitanceSensor.isConnected()) { | |
| Serial.println("✓ FDC1004 device is responding"); | |
| } else { | |
| Serial.println("✗ FDC1004 device not responding"); | |
| Serial.println("Check I2C connections"); | |
| } | |
| Serial.println(); | |
| Serial.println("Starting continuous measurements on Channel 0..."); | |
| Serial.println("Capacitance(pF)\tCAPDAC\tStatus"); | |
| Serial.println("----------------------------------------------"); | |
| } | |
| void loop() { | |
| static unsigned long lastMeasurement = 0; | |
| // Hysteresis & timing params | |
| const float CAPDAC_STEP_PF = 3.125f; // 1 LSB of CAPDAC | |
| const float LOWER_HYST_PF = 6.0f; // go down if residual < this | |
| const uint8_t DOWN_STICKY_SAMPLES = 3; // require N consecutive low-residual samples | |
| static uint8_t lowResidualCount = 0; | |
| // Track CAPDAC; sync with what the driver actually used on the last read | |
| static int capdacSetting = 0; | |
| static bool capdacInit = false; | |
| // Take measurement every 250ms | |
| if (millis() - lastMeasurement >= 250) { | |
| fdc1004_capacitance_t m = capacitanceSensor.getCapacitanceMeasurement(FDC1004_CHANNEL_0); | |
| // One-time sync (first sample) or re-sync every time to follow library auto-increase | |
| if (!capdacInit) { | |
| capdacSetting = m.capdac_used; | |
| capdacInit = true; | |
| } else { | |
| // If the library auto-increased CAPDAC, follow it | |
| if (m.capdac_used != capdacSetting) { | |
| capdacSetting = m.capdac_used; | |
| lowResidualCount = 0; // reset the down hysteresis | |
| } | |
| } | |
| // Print timestamp | |
| // Serial.print(millis()); | |
| // Serial.print("\t\t"); | |
| if (!isnan(m.capacitance_pf)) { | |
| // Compute residual inside the ADC window | |
| float residual = m.capacitance_pf - capdacSetting * CAPDAC_STEP_PF; | |
| // Pretty print values | |
| Serial.print(">"); | |
| Serial.print("capacitance:"); | |
| Serial.print(m.capacitance_pf, 4); | |
| Serial.print(",capdac:"); | |
| Serial.print(capdacSetting); | |
| Serial.print("\n"); | |
| // --- Auto-decrease logic with hysteresis --- | |
| // Count consecutive "comfortably low" residual samples | |
| if (residual < LOWER_HYST_PF) { | |
| if (lowResidualCount < 255) lowResidualCount++; | |
| } else { | |
| lowResidualCount = 0; | |
| } | |
| bool steppedDown = false; | |
| if (lowResidualCount >= DOWN_STICKY_SAMPLES && capdacSetting > 0) { | |
| // try one step down | |
| uint8_t nextCapdac = static_cast<uint8_t>(capdacSetting - 1); | |
| if (capacitanceSensor.setCapdac(FDC1004_CHANNEL_0, nextCapdac) == FDC1004_SUCCESS) { | |
| capdacSetting = nextCapdac; | |
| steppedDown = true; | |
| lowResidualCount = 0; // re-arm hysteresis | |
| } | |
| } | |
| // Status text | |
| if (m.capdac_out_of_range) { | |
| Serial.println("CAPDAC ADJUST (up by lib)"); | |
| } else if (steppedDown) { | |
| Serial.println("CAPDAC STEP DOWN"); | |
| } else { | |
| Serial.println("OK"); | |
| } | |
| } else { | |
| Serial.println("ERROR\t\t-\tMEASUREMENT FAILED"); | |
| lowResidualCount = 0; // be conservative | |
| } | |
| lastMeasurement = millis(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment