Below is a description of what the Arduino should do, however I found that after the first loop in main, the pins are not activated again:
The mainRoutine function retrieves the current time from the RTC. If the current hour is between 6AM and 5PM, it triggers each relay module in sequence, which in turn controls the electric valves. If the current day is an odd day, it pauses for 4 hours before triggering the relay connected to pin8 again. After all the relay modules have been triggered, it calculates the delay time until the next 6AM and waits for that duration.
Below is the logic implementation:
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc;
const int dayStart = 6;
const int dayEnd = 17;
const int pin8 = 8;
const int pin7 = 7;
const int pin6 = 6;
const int pin5 = 5;
const int pin4 = 4;
const unsigned long pinActiveTime = 420000;
unsigned long shutDown;
void setup() {
Wire.begin();
Serial.begin(9600);
pinMode(pin8, OUTPUT);
pinMode(pin7, OUTPUT);
pinMode(pin6, OUTPUT);
pinMode(pin5, OUTPUT);
pinMode(pin4, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
if (!rtc.begin()) {
blinkLED(10);
while (1);
}
}
void loop() {
//rtc.adjust(DateTime(__DATE__, __TIME__));
mainRoutine();
delay(60000);
}
void mainRoutine(){
DateTime now = rtc.now();
unsigned long delayTime;
if (now.hour() >= dayStart && now.hour() < dayEnd) {
activatePin(pin8);
activatePin(pin7);
activatePin(pin6);
activatePin(pin5);
activatePin(pin4);
if (evenDAY(now.day()) == false){
delay(14400000);
activatePin(pin8);
}
}
delayTime = computeDelay(now.hour(),now.minute(),now.second());
delay(delayTime);
}
bool evenDAY(int day){
return day % 2 ==0;
}
void activatePin(int pin) {
digitalWrite(pin, HIGH);
delay(pinActiveTime);
digitalWrite(pin, LOW);
}
unsigned long computeDelay(int currentHour, int currentMinutes, int currentSeconds) {
if (currentHour >= dayStart ){
shutDown = ((24 - currentHour + dayStart)* 3600 - currentMinutes * 60 - currentSeconds)*1000;
}
else{
shutDown = ((dayStart - currentHour)* 3600 - currentMinutes * 60 - currentSeconds)*1000;
}
return shutDown;
}
void blinkLED(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
}
I have a small project that requires the Arduino to activate one pin at a time, starting at 6:00 AM, for a specified duration. The activation of these pins should follow a specific logic, which I have previously described.
At present, in order to irrigate my crops, I have to manually press a small red button on the Arduino board. Once this button is pressed, the Arduino successfully executes the aforementioned logic. I am seeking a solution that would automate this process and eliminate the need for manual intervention.
1
I have an example from a project that ran a fan for 10 minutes out of every half hour. This shows how to use an AVR (in this case a ATTiny85) timer to count seconds while sleeping most of the time.
If you are using a RTC timer you might be able to use the alarm interrupt on that or a 1s interrupt line to wake the microcontroller using an external interrupt to do things. The DS3232 can output a square wave at 1s that can be used to drive an interrupt.
Note that the registers below will be a bit different for different AVR micros. ATtiny and ATmega are similar but not identical.
/* fan_control - Copyright (c) 2016 Pat Thoyts <[email protected]>
*
* ATtiny85 with LED on pin PB2 and a 2N7000 MOSFET on PB3 which controls
* a computer fan run off 12V supply. Toggle the fan on for 10 minutes then
* off for 20 minutes. Start with the fan ON
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
/* Timing is designed for 8MHz system clock */
#ifndef F_CPU
# define F_CPU 8000000UL
#endif
#define LED_PIN PB2
#define FAN_PIN PB3
volatile uint8_t ticks;
volatile uint8_t seconds;
volatile uint8_t minutes;
ISR(TIMER0_COMPA_vect)
{
/* count up to 1s (254 ticks) then toggle the LED.
* after 15 minutes, toggle the fan
* Note: should in theory be 250 but measured it and require 254 for 1s
* Note: 125Hz on oscilloscope is for full wave so on and off.
*/
if (++ticks == 254)
{
if (++seconds == 61)
{
/*
* 33% duty cycle
* on for 10 minutes out of every 30
*/
if (minutes == 0) /* on */
DDRB |= _BV(FAN_PIN);
if (minutes == 10) /* off */
DDRB &= ~_BV(FAN_PIN);
if (++minutes == 30)
minutes = 0;
seconds = 0;
}
ticks = 0;
/* toggle the led every other second */
if ((seconds & 1) == 0)
PORTB |= _BV(LED_PIN);
}
}
/* put the processor into the currently defined sleep mode */
static void
sleep_now(void)
{
cli();
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
/* configure timer 0 as a counter. Raises interrupts at 250 Hz */
static void
init_timer0(void)
{
cli();
ticks = seconds = minutes = 0;
/*
* WGM = 0b010: CTC mode (0 -> OCRA)
* COM0A = 0b00: PWM A disabled
* COM0B = 0b00: PWM B disabled
* CS = 0b011: CLK/64; 0b100: CLK/256
* freq = 8e6 / 64 / 125 == 1000.0 ie 1kHz.
* freq = 8e6 / 256 / 125 == 250 Hz
*/
TCCR0A = _BV(WGM01);
TCCR0B = _BV(CS02);
TCNT0 = 0;
OCR0A = 125;
TIMSK |= (1 << OCIE0A); /* interrupt on compare match with OCR0A */
sei();
}
/* Configure fast PWM on PB3 (OC1B) */
static void
init_pwm_timer1()
{
cli();
/* set pin PB3 (OC1B) as output */
DDRB |= _BV(DDB3);
PORTB &= ~_BV(PB3);
/*
* PWM1A = 0: disabled modulator A (attached to PB0 and PB1)
* PWM1B = 1: enable PWM mode for OCR1B and 0 when match OCR1C
* COM1A = 0b00: OC1A disconnected
* COM1B = 0b01: OC1B clear on compare match, set at BOTTOM,
* OC1B# set on compare match, clear at 0. (Table 12-1).
* CS = 0b0001: PCK/1
* OCR1C = 0xFF: TOP, resets counter when matches
* freq = (8MHz / 1 / 256) -> 31kHz.
*/
TCCR1 = _BV(CS10);
GTCCR = _BV(PWM1B) | _BV(COM1B0);
OCR1B = 60; //lower is faster 190 is stalled
OCR1C = 255;
sei();
}
int
main(void)
{
wdt_enable(WDTO_1S);
power_adc_disable();
power_usi_disable();
/* set all unused pins high-z, led pin output and low */
DDRB = _BV(LED_PIN);
PORTB = ~(_BV(LED_PIN));
init_timer0();
init_pwm_timer1();
set_sleep_mode(SLEEP_MODE_IDLE);
sei();
for (;;)
{
/* sleep all the time. Gets woken up by the timer at 250Hz */
wdt_reset();
sleep_now();
}
}