ATtiny10 Moisture sensor

Built an ATiny10 moisture sensor with multiple indicators to show how wet or dry soil is. Also it has the feature of low voltage alert (using VLM).

For the probes I used about 12 cm long 12 gauge copper wire. Then soldered them to H1 and H2. The rest is pretty simple.. I did find the reset button redundant. I used a jumper between the battery circuit. Pull jumper (J1) and then program without issue.

Updated code 5/8/23: fixed VLM so it doesn't consume so much power

Microchip Studio Code:

/* * Tiny 10 Moisture sensore and indicator v2.2 * with voltage detection works 2.4v is trigger *  * Sherman Stebbins * 2022-02-17 *  * Firmware v2.2  * *  * Attiny10;                +====+;     SCK -> PB0 |*   | PB3 (RESET);            GND |    | Vcc;    MOSI -> PB1 |    | PB2 ;                +====+
Updated 2.1 on 3-19-22changed light alerts and added moreset at 8mhz in arduino ide to get correct timing2** Updated 3-19/22* changed when lit and more green and red light alert.* Faster is less good. ** Updated 5/6/23* Changed battery low code to include ISR.. * and fixed low voltage, on test chip, * triggered at 2.35v, But changed current from 4uA to 46uA !!* So Put crap back, now low voltage does not work. *     VLMCSR = 0; //shutdown VLM* was added back in.** Updated 5/8/23* FIXED low voltage detection and works and now sleeps at about 5ua!!* also dropped clock back to 1mhz, 8mhz was over kill.* Green slow - full of water* Green fast - good on water* Green and red - medium on water* Red slow - low water* Red Fast - dry on water** Alternating Red and Green - Battery low* */#define F_CPU 1000000UL#include <util/delay.h>#include <avr/interrupt.h>
#define Moisture PB0#define RedLed PB1#define GreenLed PB2//#define SleepTimes 4  //8=58 sec //4=29 secvolatile uint8_t SleepTimes=4;  //8=58 sec //4=29 sec //2=15sec //1=8sec//volatile static uint8_t LowVoltage =0;
volatile unsigned char count __attribute__((section(".noinit"))); // Not cleared on RESETvolatile unsigned char LowVoltage  __attribute__((section(".noinit"))); // Not cleared on RESETvoid goToSleep(void);uint8_t analog_read(uint8_t pin);void LightLed(uint8_t Led);void LedOff(void);
int main(void){  CCP = 0xD8; // unlock protected register  //CLKPSR = 0; // No divider full 8mhz  CLKPSR = 0b00000011; //just set to default to test  VLMCSR |= (1<<VLM0)|(1<<VLM1)|(1<<VLMIE);  _delay_us(30);//  VLMCSR = 0b01000011;  WDTCSR &= ~(1<<WDE);  //must have or won't sleep  WDTCSR &= ~(1<<WDIE);  DDRB = 0b00000110;  sei();  while(1){
    //xc mm cc    if(count==0){ //if Battery below 2.4v gives warning light flash if(VLMCSR & (1<<VLMF)){ //VLMCSR & 0b10000000  either one reads VLMF flag for(int i=0;i<3;i++){ LightLed(GreenLed); _delay_ms(10); LedOff(); LightLed(RedLed); _delay_ms(10); LedOff(); LowVoltage=1; } } uint8_t Wetness=0;        Wetness = analog_read(Moisture); //get moisture reading        for(int i=0;i<12;i++){  //8        //display moisture level:        if(Wetness >= 242){ if(LowVoltage){ LightLed(GreenLed); _delay_ms(15); LedOff(); _delay_ms(15); }else{ LightLed(GreenLed); _delay_ms(150); LedOff(); _delay_ms(150); }          SleepTimes=4; //4 //8=58 sec //4=29 sec //2=15sec //1=8sec        }else if(Wetness <=242 && Wetness >= 230){ if(LowVoltage){ LightLed(GreenLed); _delay_ms(15); LedOff(); _delay_ms(15); }else{ LightLed(GreenLed); _delay_ms(50); LedOff(); _delay_ms(50); } SleepTimes=4; //4 //8=58 sec //4=29 sec //2=15sec //1=8sec        }else if(Wetness <=229 && Wetness >= 218){  if(LowVoltage){ LightLed(RedLed); LightLed(GreenLed); _delay_ms(15); LedOff(); _delay_ms(15); }else{ LightLed(RedLed); LightLed(GreenLed); _delay_ms(100); LedOff(); _delay_ms(100);  } SleepTimes=2; //2 //8=58 sec //4=29 sec //2=15sec //1=8sec        }else if(Wetness <=217 && Wetness >= 200){ if(LowVoltage){ LightLed(RedLed); _delay_ms(15); LedOff(); _delay_ms(15); }else{ LightLed(RedLed); _delay_ms(150); LedOff(); _delay_ms(150); } SleepTimes=1;  //8=58 sec //4=29 sec //2=15sec //1=8sec           }else if( Wetness < 200){ if(LowVoltage==1){ LightLed(RedLed); _delay_ms(5); LedOff(); _delay_ms(5); }else{ LightLed(RedLed); _delay_ms(50); LedOff(); _delay_ms(50); }            SleepTimes=1;  //8=58 sec //4=29 sec //2=15sec //1=8sec         // }        } LowVoltage=0;      }    }    count++;         if(count>=SleepTimes){      count=0;          }      goToSleep();        }}//low voltage interuptISR(VLM_vect){  /*    LowVoltage=1; //didn't carry over due to sleep    DUHHHH use volitile..       like: volatile unsigned char count __attribute__((section(".noinit"))); // Not cleared on RESET       */  LowVoltage=1;    }
void goToSleep(void){    VLMCSR = 0; //shutdown VLM    ADCSRA &= ~(1<<ADEN);   //shut off ADC
  SMCR |= (1<<2); //SMCR.SM bit 2 (010) Power-down  SMCR |= (1<<0); //SMCR.SE =1; SET JUST before Sleep starts    sei() ; //set Global Interrupt Enable  //__asm__ __volatile__("sleep") ; //enter sleep, waiting for interrupt -- This worked great!!!  WDTCSR = 0b01100001; //1000 4 sec 0111 2 sec watchdog timer 1001 8 sec.//  WDTCSR |= (1<<WDIE)|(1<<WDP3)|(1<<WDP0)|(1<<WDE); //1000 4 sec 0111 2 sec watchdog timer 1001 8 sec.  __asm__ __volatile__ ( "sleep" "\n\t" :: ); //Sleep instruction to put controller to sleep (found this syntax later, probably more proper)// cli(); //wake:  // VLMCSR |= (1<<VLM0)|(1<<VLM1)|(1<<VLMIE);}
void LedOff(void){  PORTB &= ~(1<<PB1);  PORTB &= ~(1<<PB2);}
void LightLed(uint8_t Led){  PORTB |= (1<<Led);}
uint8_t analog_read(uint8_t pin){ switch(pin) {       case PB0: ADMUX = 0; DIDR0 = _BV(ADC0D); break; // ADC0        case PB1: ADMUX = _BV(MUX0); DIDR0 = _BV(ADC1D); break; // ADC1        case PB2: ADMUX = _BV(MUX1); DIDR0 = _BV(ADC2D); break; // ADC2 //default: ADMUX = 0; break; }
ADCSRA |= _BV(ADEN);  // Enable ADC ADCSRA |= _BV(ADSC);  // Run single conversion while(bit_is_set(ADCSRA, ADSC)); // Wait conversion is done
// Read values return  ADCL;}

ATtiny10 actual size.

ATtiny10 actual size..