Hello Forum members! I recently picked up a few Pico W boards and have been successfully running the example programs inside the Arduino IDE. I then picked up some soil moisture capacitive sensors with the goal of recreating Bill's IoT plant moisture sensor system. But I'm stuck at the calibration step/sketch. No matter what I do, the ADC reads zero, no exception. I've even probed the pins with my voltmeter and I can see varying voltages 0.8 - 1.9v (between ground and ADC0 pins) as I bring my arm near the probe. (Soil theremin, LOL.) I've tried both my pico W boards, so it seems more likely that I'm doing something wrong. Any suggestions?
For what it's worth, I've experimented using ADC0 vs 1 vs 2 (pins 31,32,34); using 3v3_OUT (pin 36) vs ADC_VREF (pin 35) for power; jumpering pins 35 & 36 together.
I've googled around as usual, but haven't found a solution yet.
Thanks for your help!
(Soil theremin, LOL.)
Ha, good one!
I'm curious, what voltage are you gettting from the ADC_VREF pin.
Tom
To err is human.
To really foul up, use a computer.
@thrandell Pin 35 (ADC_VREF) is +3.26v above pin 33 (GND). Pins 35 and 36 (3v3(OUT)) appear identical on my voltmeter.
An update: I got something working a different way, but I still lack understanding...
To simplify my problem, I removed all the probe stuff, and tried just reading ADC4 (the pico w's built-in temperature reading). Again, thru the Arduino IDE, everything came back zeroes.
But then I followed a MicroPython tutorial, and this worked. The "adc = machine.ADC(4)" followed by "voltage = adc.read_u16()" gave me a reasonable and always-slightly-changing number. Bingo!
I then used this same approach to read "machine.ADC(0)" (my soil probe), and to blink an LED when the probe is "too dry" (based on my wet/dry calibration measurements.) This appears to be working fine.
So why didn't the Arduino IDE method of "sensorval = analogRead(0)" work? It's almost like it's addressing the wrong pin..? (I'm always uneasy about hardcoding numbers like "0", instead of using manufacturer-provided, board-specific constants like "ADC0" or "GPIO15").. I'd appreciate whatever insight anyone can offer. Thanks!
(p.s. I can post my microPython code if anyone wants it, but it essentially just follows the linked tutorials above.)
Hi @dk55432
This is something that I got to work in C. Sorry about not paring it down to the basics, you can ignore all the LED stuff. Hope if helps.
Tom
/* Read the voltage divider on ADC2 and display the results on the three LEDs red = whole volts yellow = tenths of a volt green = hundredths of a volt I'm getting about 3.90V - 3.93V from the battery */ #include <stdio.h> #include "pico/stdlib.h" #include "hardware/pwm.h" #include "hardware/gpio.h" #include "hardware/adc.h" #define LED_GN 14 #define LED_YW 9 #define LED_RD 8 uint32_t pwm_set_freq_duty(uint slice_num, uint chan, uint32_t f, int d) { uint32_t clock = 125000000; uint32_t divider16 = clock / f / 4096 + (clock % (f * 4096) != 0); if (divider16 / 16 == 0) divider16 = 16; uint32_t wrap = clock * 16 / divider16 / f - 1; pwm_set_clkdiv_int_frac(slice_num, divider16 / 16, divider16 & 0xF); pwm_set_wrap(slice_num, wrap); pwm_set_chan_level(slice_num, chan, wrap * d / 100); return wrap; } uint32_t pwm_get_wrap(uint slice_num) { valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES); return pwm_hw->slice[slice_num].top; } void pwm_set_duty(uint slice_num, uint chan, int d) { pwm_set_chan_level(slice_num, chan, pwm_get_wrap(slice_num) * d / 100); } int main() { stdio_init_all(); gpio_set_function(LED_GN, GPIO_FUNC_PWM); gpio_set_function(LED_YW, GPIO_FUNC_PWM); gpio_set_function(LED_RD, GPIO_FUNC_PWM); uint slice_LED1 = pwm_gpio_to_slice_num(LED_GN); // slice 7 uint slice_LED23 = pwm_gpio_to_slice_num(LED_RD); // slice 4 uint chan_LED_GN = pwm_gpio_to_channel(LED_GN); // channel 7A uint chan_LED_YW = pwm_gpio_to_channel(LED_YW); // channel 4B uint chan_LED_RD = pwm_gpio_to_channel(LED_RD); // channel 4A pwm_set_freq_duty(slice_LED1, chan_LED_GN, 60, 0); // that's 60Hz for the LEDs pwm_set_freq_duty(slice_LED23, chan_LED_RD, 60, 0); // that's 60Hz for the LEDs pwm_set_duty(slice_LED23, chan_LED_YW, 0); pwm_set_enabled(slice_LED1, true); pwm_set_enabled(slice_LED23, true); adc_init(); adc_gpio_init(28); // Make sure GPIO is high-impedance, no pullups etc adc_select_input(2); // Select ADC input 2 (GPIO28) while (1) { // 12-bit conversion, assume max value == ADC_VREF == 3.3 V const float conversion_factor = 3.3f / (1 << 12); // shift the number 1 to the left 12 bits = 4096, so 0.00080566 uint16_t result = adc_read(); // float converted = result * conversion_factor * 2.0; // the voltage divider gives halve the true battery voltage float converted = result * conversion_factor; // for testing of leds // this all seems kind of silly uint8_t whole_number = converted; uint8_t tenths = (converted - whole_number) * 10; uint8_t hundreds = ((converted - whole_number) * 100) - (tenths * 10); printf("result = %d, converted voltage = %f, whole number = %d, tenths = %d and hundreds = %d \n",result,converted,whole_number,tenths,hundreds); sleep_ms(500); pwm_set_duty(slice_LED1, chan_LED_GN, 0); pwm_set_duty(slice_LED23, chan_LED_YW, 0); pwm_set_duty(slice_LED23, chan_LED_RD, 0); for (int x = 0; x < whole_number; x++) { pwm_set_duty(slice_LED23, chan_LED_RD, 50); sleep_ms(400); pwm_set_duty(slice_LED23, chan_LED_RD, 0); sleep_ms(400); } for (int y = 0; y < tenths; y++) { pwm_set_duty(slice_LED23, chan_LED_YW, 50); sleep_ms(400); pwm_set_duty(slice_LED23, chan_LED_YW, 0); sleep_ms(400); } for (int z = 0; z < hundreds; z++) { pwm_set_duty(slice_LED1, chan_LED_GN, 50); sleep_ms(400); pwm_set_duty(slice_LED1, chan_LED_GN, 0); sleep_ms(400); } } return 1; }
To err is human.
To really foul up, use a computer.
@dk55432 As a rule using supplied constants is advised over hard coded numbers. Not sure why you were fooling around with some of those other pins and shorting pins together, Bill's sketch and wiring diagram is very simple.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.