![]() |
Altium DesignerAltium Designer
|
|
![]() |
Microchip studio |
|
![]() |
SolidWorksSolidWorks
|
Minimalistic Soil Moisture Sensor
Youtube video -----> https://youtu.be/oqFGDM0aIfc
https://www.youtube.com/@NickElectronics
Description:
If you often forget to water your plants, this is a must-have device for you—a soil moisture tracker based on a PCB capacitive sensor and an ATmega48 microcontroller. Powered by two AAA batteries connected in series, the device can operate for two years without needing a battery replacement.
Functionality:
The device remains in sleep mode most of the time and wakes up every 10 minutes to measure soil moisture. If the soil is dry, it blinks red and then goes back to sleep. If the soil is sufficiently moist, it simply returns to sleep without blinking to avoid disturbing the user. When the battery is low, the device also signals this by blinking twice if the soil is dry or three times if the soil is moist.
/* * SoilSensor.c */ #define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <stdbool.h> #include <util/delay.h> void sleep(void); void wakeup(void); void WDT (void); void PWM_ON (void); void LED_ON (void); void LED_OFF (void); void ADC_ON (void); uint8_t read_adc(void); uint8_t vin = 0; uint8_t sensor = 0; uint8_t WDT_counter = 0; // each interrupt is 8 sec, so 600 sec is 75 interrupts int main(void) { WDT(); //enable WDT sleep(); // Go to sleep while (1) { if(WDT_counter >= 1) // If it`s been 600 seconds, proceed with the routine { wakeup(); //Wake up from sleep, turn on all periphery _delay_ms(500); //Read batteries voltage. 1.1Vref internal source is used for the ADC ADMUX = 0b11100110; DDRD |= (1<<DDD1); // Connect voltage divider vin = read_adc(); // 193 value for 3.3V on batteries. 117 value when battery is at 2.0V level (discharged). DDRD &= ~(1<<DDD1); // Disconnect voltage divider //Read moisture level. Vcc as a voltage reference is used. This allows to read kinda same values when battery discharges. ADMUX = 0b01100111; sensor = read_adc(); // Read moisture level from the filter if(sensor >= 156) // Adjust to control moisture level. 203 is full dry. 110 is full wet { if(vin <= 117)// If battery is discharged blink twice 1 sec each time { LED_ON(); _delay_ms(1000); // Use delays, cause why not. I don`t run any other important stuff in parallel :D LED_OFF(); _delay_ms(1000); LED_ON(); _delay_ms(1000); } else // If battery is above 2.0V just blink once for 2 seconds { LED_ON(); _delay_ms(2000); } } else // If soil is moist enough go to this else { if(vin <= 117) // Blink 3 times fast if battery is discharged { LED_ON(); _delay_ms(500); LED_OFF(); _delay_ms(500); LED_ON(); _delay_ms(500); LED_OFF(); _delay_ms(500); LED_ON(); _delay_ms(500); } else { LED_OFF(); // If battery is charged and soil is moist just keep LED OFF } } sleep(); //Go to sleep after all routine is done } else // If it`s been less than 600 seconds, continue sleeping. { sleep_enable(); } } } void PWM_ON (void) { // PWM DDRD |= (1<<DDRD6); PORTD &= ~(1<<PIND6); TCCR0A |= (1 << COM0A0); // Set OC0A on Compare Match TCCR0A &= ~(1 << COM0A1); TCCR0A |= (1 << WGM01); // CTC mode, top OCRA TCCR0B &= ~((1 << WGM02) | (1 << WGM00)) ; OCR0A = 10; TCCR0B |= (1 << CS00); TCCR0B &= ~((1 << CS01) | (1 << CS02)); } void PWM_OFF (void) { // PWM DDRD &= ~(1<<DDRD6); PORTD &= ~(1<<PIND6); TCCR0A &= ~(1 << COM0A0); // Set OC0A on Compare Match TCCR0A &= ~(1 << COM0A1); TCCR0A |= (1 << WGM01); // CTC mode, top OCRA TCCR0B &= ~((1 << WGM02) | (1 << WGM00)) ; OCR0A = 0; TCCR0B &= ~((1 << CS01) | (1 << CS02) | (1 << CS00)); } void LED_ON (void) { DDRC |= (1<<DDRC2); PORTC |= (1<<PINC2); } void LED_OFF (void) { DDRC &= ~(1<<DDRC2); PORTC &= ~(1<<PINC2); } void ADC_ON (void) { DDRC &= ~(1<<DDRC1); DDRE &= ~((1<<DDRE3) | (1<<DDRE2)); DIDR0=(0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (0<<ADC0D); ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0); } void ADC_OFF (void) { DDRC &= ~(1<<DDRC1); PORTC &= ~(1<<PINC1); DDRE &= ~((1<<DDRE3) | (1<<DDRE2)); PORTE &= ~((1<<PINE3) | (1<<PINE2)); DIDR0=(0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (0<<ADC0D); ADMUX = 0b00000000; ADCSRA=(0<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0); } void wakeup(void) { sleep_disable(); cli(); PWM_ON(); ADC_ON(); } void sleep (void) { cli(); WDT_counter = 0; PWM_OFF(); ADC_OFF(); LED_OFF(); set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); sei(); //ensure interrupts enabled so we can wake up again sleep_cpu(); } void WDT (void) { cli(); // Enable WDT with 8s timeout WDTCSR = (1 << WDCE) | (1 << WDE); // Enable WDT configuration WDTCSR = (1 << WDP3) | (1 << WDP0); // Set prescaler for 8s timeout // Enable WDT interrupt WDTCSR |= (1 << WDIE); // Watchdog Interrupt Enable sei(); // Enable interrupts } ISR(WDT_vect) { WDT_counter++; } uint8_t read_adc(void) { // Delay needed for the stabilization of the ADC input voltage for(int delay = 0; delay < 100; delay++){} // Start the AD conversion ADCSRA|=(1<<ADSC); // Wait for the AD conversion to complete while ((ADCSRA & (1<<ADIF))==0); ADCSRA|=(1<<ADIF); return ADCH;//ADCH; }

Minimalistic Soil Moisture Sensor
*PCBWay community is a sharing platform. We are not responsible for any design issues and parameter issues (board thickness, surface finish, etc.) you choose.

Raspberry Pi 5 7 Inch Touch Screen IPS 1024x600 HD LCD HDMI-compatible Display for RPI 4B 3B+ OPI 5 AIDA64 PC Secondary Screen(Without Speaker)
BUY NOW
ESP32-S3 4.3inch Capacitive Touch Display Development Board, 800×480, 5-point Touch, 32-bit LX7 Dual-core Processor
BUY NOW
Raspberry Pi 5 7 Inch Touch Screen IPS 1024x600 HD LCD HDMI-compatible Display for RPI 4B 3B+ OPI 5 AIDA64 PC Secondary Screen(Without Speaker)
BUY NOW- Comments(0)
- Likes(2)

-
_ Floppy Lab Jan 20,2025
-
Nick Electronics Jan 18,2025
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Nick Electronics
-
Minimalistic Soil Moisture Sensor Youtube video -----> https://youtu.be/oqFGDM0aIfchttps://www.youtube.com/@NickElectronicsDescript...
-
DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case (3rd PCB) DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case (3rd PCB)Third board of the proj...
-
DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case (2nd PCB) Second board of the project DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case (2nd...
-
DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case DIY LED Resin Sticker with Custom Electronics & 3D-Printed CaseYoutube video -----> https://y...
-
DIY LED Resin Sticker with Custom Electronics & 3D-Printed Case DIY LED Resin Sticker with Custom Electronics & 3D-Printed CaseYoutube video -----> https://y...
-
-
-
Modifying a Hotplate to a Reflow Solder Station
748 1 5 -
MPL3115A2 Barometric Pressure, Altitude, and Temperature Sensor
404 0 1 -
-
Nintendo 64DD Replacement Shell
350 0 2 -
V2 Commodore AMIGA USB-C Power Sink Delivery High Efficiency Supply Triple Output 5V ±12V OLED display ATARI compatible shark 100W
969 4 2 -
How to measure weight with Load Cell and HX711
638 0 3