CC Blog Projects Research & Design Hub

Artificial Dawn and Dusk

Written by Jeff Bachiochi

Don’t Scare the Chickens!

Egg laying by chickens requires a minimum number of daylight hours, and naturally decreases during the fall and winter, when days are shorter. In this month’s project, I create an ingenious device that not only extends the number of daylight hours in a chicken coop artificially, but also simulates the gradual increase of light at dawn and decrease at dusk, to avoid stressing the chickens with abrupt lighting changes.

  • How can I build a lighting project with a timer at home?
  • How can I provide artificial lighting for my chickens during winter?
  • How can I use an ESP32 MCU in a lighting project?
  • TRIAC
  • TLP3021
  • TLP620
  • WEMOS D1 R32 ARDUINO BOARD
  • ESP32
  • AC Dimmer Module

When you get the same question from two different sources, you can’t help but think there is a problem that needs solving. My grandson, Travis, has been raising chickens for some time now. We supported his venture by giving him socks, tee shirts, hats, and other apparel with chickens on them. The coop is along the edge of the property, and is completely enclosed to give the chickens some level of protection at night from whatever might be roaming the area, looking for an easy meal. Once the weather got colder and the days got shorter, egg production fell off.

For some reason, we are now in an egg crisis that has led to the price of eggs going sky high. Now I don’t do eggs for breakfast, so it hasn’t bothered me. But my wife, Beverly, brings it up each morning as she is cracking a pair of tough yet fragile shells into the sizzling fry pan on the stove.

At a recent Connecticut Robotics Society meeting, one member was also talking about chickens and how he was able to improve production by tricking the chickens into thinking the days were longer. This was done with a timer to turn on lights in the coop before the sun came up.

While this indeed affected production, there was quite an uproar among the chickens when it suddenly became daytime. This was akin to going into the kids’ room, turning on the lights, and pronouncing it was time to get up to prepare for another school day. While chickens don’t groan and complain, they obviously were not happy and showed distress that took some time to get over, potentially having a negative effect on production. If only the light level could more closely mimic a natural sunrise (and sunset), emotional scarring might be avoided.

TRY ACTS!

Actually, that’s “TRIAC,” as in “TRIode for Alternating Current”— a three-terminal electronic component that conducts current in either direction when triggered. This semiconductor device has two main terminals, MT1 and MT2, and a Gate terminal to get the conduction process started. Unlike the PNP or NPN transistor, the TRIAC can pass current in both directions. A TRIAC is two back-to-back SCRs (silicon control rectifiers). Each SCR can pass current in one direction.

Unlike the transistor, removing the Gate signal on a TRIAC will not stop current flow. Fortunately, it will stop (if the Gate signal has been removed) when the polarity of the AC voltage passes through zero. It will stay off until a Gate signal is again applied.

If you were to apply a Gate pulse just after each positive and negative zero crossing, the TRIAC would turn ON (conducting) for almost the complete cycle. Depending on when you apply a pulse referenced to the zero crossing, you can get the TRIAC to stay OFF (non-conducting) for some percentage of the cycle, and therefore cause a connected device to receive power only part of the time. This is great for controlling the speed of a universal motor (commutated), dimming lamps, and controlling electric heaters. While this can switch ON/OFF the standard AC motor, the speed of these motors cannot be controlled by using percentages other than 0% (OFF) or 100% (ON). So, a warning here: “User know thy Load!”

— ADVERTISMENT—

Advertise Here

When a TRIAC is to be controlled by a microcontroller (MCU), it is a good idea to isolate the TRIAC’s Gate input from the MCU. This can be done with a special optocoupler, such as the TLP3021, it couples well to the TRIAC, because the opto isolation uses a small, embedded TRIAC to drive the larger current TRIAC (Figure 1). Note that two “flavors” of opto-TRIACs are illustrated; the second has a zero-crossing detector built in. You can use this one if you just want to turn a TRIAC ON or OFF, since it will automatically apply a Gate signal at zero crossings. This device cannot be used where a MCU controls the point of Gate trigger.

FIGURE 1
Two "flavors" of opto-TRIACs. The DIP8 device on the left uses light from the LED to turn on the isolated internal TRIAC. This TRIAC is used to turn on an external TRIAC that can handle more power. The DIP8 device on the right is identical to the other, except it has a zero-crossing detector built in. This device ensures that the external TRIAC is only turned on at zero-crossing (while current is zero). It can only be used as an ON/OFF switch. You must use the device left to be able to turn a device ON at any point between zero crossings.
FIGURE 1
Two “flavors” of opto-TRIACs. The DIP8 device on the left uses light from the LED to turn on the isolated internal TRIAC. This TRIAC is used to turn on an external TRIAC that can handle more power. The DIP8 device on the right is identical to the other, except it has a zero-crossing detector built in. This device ensures that the external TRIAC is only turned on at zero-crossing (while current is zero). It can only be used as an ON/OFF switch. You must use the device left to be able to turn a device ON at any point between zero crossings.

Our MCU can be used to produce a Gate pulse, and even delay that pulse from a zero-crossing, except for one thing—we don’t know when zero crossings occur. We need to safely determine when a zero crossing occurs, while keeping the AC separated from our low-voltage circuitry. So, we turn again to an optocoupler-device for this. The TLP620 contains two LEDs and a photo transistor (Figure 2). The two LEDs will capture both polarities of the AC voltage and give us a transistor output that looks like a train of pulses, where each pulse corresponds to alternate zero crossings.

FIGURE 2
To get and stay in sync with zero-crossings, a separate device is used to opto-couple the AC to a photo transistor. The TLP620 contains two LEDs and a photo transistor. The photo transistor remains ON while the AC voltage is above the LEDs' operating voltage. The short transition while neither LED is lit produces a narrow pulse. All timing is based on this pulse.
FIGURE 2
To get and stay in sync with zero-crossings, a separate device is used to opto-couple the AC to a photo transistor. The TLP620 contains two LEDs and a photo transistor. The photo transistor remains ON while the AC voltage is above the LEDs’ operating voltage. The short transition while neither LED is lit produces a narrow pulse. All timing is based on this pulse.

Add a sprinkling of some discrete parts, and you get a module that takes a 120V AC input and provides both a Gate control input and an open-collector, zero-crossing output. Figure 3 shows the module I found on the Internet for about $14 dollars that handles up to 2A. You can find modules that carry higher current, but this will be adequate for this project.

FIGURE 3 
I found this AC dimmer module on the Web for about $14. It contains the zero-crossing detector, the control TRIAC, and a power TRIAC that can handle about 5A.
FIGURE 3
I found this AC dimmer module on the Web for about $14. It contains the zero-crossing detector, the control TRIAC, and a power TRIAC that can handle about 5A.

We are going to need a power supply for our MCU. Normally I’d use a 5V wall wart or USB charger, but that would mean a separate AC plug. I found a small AC to 5V DC power supply (Figure 4) for $2, but you had to buy five—so I splurged, spent the $10, and will have some left over for future projects. This is enough to get us started so let’s wire it all up, and jump into some code.

FIGURE 4 
My device all wired up. The 5V power supply is in the small plastic case. The TRIAC module and WEMOS Arduino board are fastened down to a clear plate in the bottom of a 2-gang utility box. The Arduino Proto Shield has connectors for the power supply, TRIAC module, SSD1306 OLED display, Real-time Clock, input buttons, and output beeper.
FIGURE 4
My device all wired up. The 5V power supply is in the small plastic case. The TRIAC module and WEMOS Arduino board are fastened down to a clear plate in the bottom of a 2-gang utility box. The Arduino Proto Shield has connectors for the power supply, TRIAC module, SSD1306 OLED display, Real-time Clock, input buttons, and output beeper.
WEMOS D1 R32 ARDUINO BOARD

An ESP32 MCU that comes in an Arduino UNO form factor is shown in Figure 4. With the 5V power supply connected, I only need two I/Os to interface with the opto-coupled TRIAC and zero-crossing detectors. The zero-crossing pulse train comes into D13, and the Gate control will come from D12. Let’s begin by determining the 120Hz (twice per 60Hz) zero crossings.

Any variables that may be accessed from the main program and an interrupt routine should use the special qualifier volatile when declaring a variable, as in myZero, it gets set each time we get a zero-crossing interrupt. We also need to measure the time between crossings. Note that the actual zero crossing is halfway between the falling pulse and the rising pulse of the zero-crossing detector. Since this is such a small part of the overall cycle width, I’ll just use the falling edges as the zero-crossing point.

The Arduino can determine time in microseconds and milliseconds. Our cycle time for the 60Hz line frequency is 1/60Hz or 16.667ms. That means we should see a zero crossing every 16.668ms/2 or 8.334ms. Let’s measure this in microseconds to see more than just an “8” all the time. We’ll force the program to print “No Power” once when started, and again if the timer ever exceeds 15ms (Listing 1).

LISTING 1
Provided that the WEMOS Arduino board is powered through the USB connector, this simple application will print the status of the AC power based on seeing a train of pulses from the zero-crossing detector. Note the use of myDebug to allow all the display code to be eliminated just by changing that variable to "0."

//  start variables
const byte myDebug = 1;
const String signOn =”Wemos_D1_R32_Zero_Crossing_Time”;
//  end variables
//  start Zero crossing variables
#define PSM_PIN 19                      // TRIAC control output pin
#define GPIOINT_PIN 18                  // zero-crossing input pin
#define GPIOINT_MODE RISING             // zero-crossing interrupt mode
volatile boolean myZero = false;        // interrupt flag
boolean myPowerOff = true;              // should we display a no power message
long myCycle;                           // 1/2 cycle time (time between zero-crossings)
long myLast;                            // start time of next cycle measurement             
//  end Zero crossing variables
//  start Zero Crossing Interrupt
void IRAM_ATTR zeroCrossing()
{
  // interrupt should be every 8.334ms
  myZero = true;                        // we got an interrupt (zero-crossing)
}
//  end Zero Crossing Interrupt
//  start setup
void setup()
{
  if(myDebug)
  {
    Serial.begin(115200);               // initialize serial
    // wait for serial port to connect. Needed for native USB    
    while (!Serial); 
    Serial.println(signOn);
  }
  // start Zero Crossing setup
   myLast = micros();                   // start with some value
  pinMode(GPIOINT_PIN, INPUT_PULLUP);   // zero-crossing signal (0=voltage)
  pinMode(PSM_PIN, OUTPUT);             // Triac control output
  attachInterrupt(GPIOINT_PIN, zeroCrossing, GPIOINT_MODE);     
  // end Zero Crossing setup
}
//  end setup
//  start loop
void loop() 
{
  // Is there a zero-crossing (Power On)
  if(myZero)
  {
    myCycle = micros() - myLast;        // get a new myCycle time
    myLast = micros();                  // get a new start time
    myZero = false;                     // the interrupt was processed
    if(myDebug & 1)
    {
      Serial.println(“1/2 cycle = “ + String(myCycle)); // display 1/2 cycle time
      // we should display the “No Power” message if power is lost
      myPowerOff = true; 
    }                 
  }  
  else
  //  No zero-crossings (No Power)
  {
    if(myDebug & 1)
    {
      // has there been no zero-crossing for longer than 1/2 cycle
      // and we should display one “No Power” message
      if(((micros() - myLast) > 15000) && myPowerOff)
      {
        Serial.println(“No Power”);       // display “no Power” 
        myPowerOff = false;               // OK we displayed “no Power” one time
      }
    }
  }
}
//  end loop
LISTING 2
We need to initialize a few things and add to the zero-crossing interrupt. Two additional timer interrupts keep everything happening in a timely fashion.

//  start timer variables
#define PB1_PIN 23                     // Push Button input pin
#define BUZZ_PIN 13               				// buzzer output pin
const int buzzTime = 200;
boolean myPowerState = false; 						// requested state of the power switch
byte myPercent = 0;                    // requested percentage of the power switch     
byte myDelayCount = 100;         				// 100 - byte myPercent       
const byte stepTime = 70;          			// us 1000000/(60Hz*2*100Steps) - 13
hw_timer_t * timer0 = NULL;
hw_timer_t * timer1 = NULL;
// 100~1min
const byte myStepDelay = 100; 						// number of 1/2 cycles for percent step
byte myStepDelayCounter = myStepDelay;	// cycle counter
const byte countPB = 3;            			// number of 100ms counts a PB must be pushed
byte myPBCounter1 = countPB; 							// PB1 counter
//  end timer variables
…
//  start Zero Crossing Interrupt
void IRAM_ATTR zeroCrossing()
{
 // interrupt should occur every 8.334ms
  myZero = true;                        // we got an interrupt (zero-crossing)
  if(myPercent)
  {  
    timerAlarmWrite(timer0, myDelayTime, false);  // set up the timer to count myDelay once
    timerRestart(timer0);
    timerAlarmEnable(timer0);
  }
}
//  end Zero Crossing Interrupt
//  start Timer0 Interrupt
void IRAM_ATTR onTimer0() 
{
  digitalWrite(PSM_PIN, HIGH);          // high output on the PSM_PIN
  delayMicroseconds(10);
  digitalWrite(PSM_PIN, LOW);           // low output on the PSM_PIN
  timerAlarmDisable(timer);
}  
//  end Timer0 Interrupt
//  start Timer1 Interrupt
void IRAM_ATTR onTimer1() 
{
  digitalWrite(BUZZ_PIN, LOW);           // low output on the PSM_PIN
}  
//  end Timer1 Interrupt
LISTING 3
Two additional I/Os add a push button input and a beeper output. To prevent the need for a delay command to provide a beep duration, a second timer interrupt is used. This timer turns off the beeper after 200,000µs, without using a delay command that would halt execution and prevent necessary interrupts. 

void setup()
{
...
  // start PSM Interrupt setup
  pinMode(PB1_PIN, INPUT_PULLUP);        // push button 1 as input (low=pushed)
  pinMode(BUZZ_PIN, OUTPUT);            // buzzer as output (high=On)
  timer0 = timerBegin(0, 80, true);      // initialize timer 0
  timer1 = timerBegin(1, 80, true);      // initialize timer 1
  // initialize the timer interrupt with timer variable, ISR routine, and edge
  timerAttachInterrupt(timer0, &onTimer0, true);
  timerAttachInterrupt(timer1, &onTimer1, true);
  // end PSM Interrupt setup
…
}
// functions
//  start check for push button
void checkPB()
{
  if(!digitalRead(PB1_PIN))              // pushed
  {
    myPBCounter1++;
  }  
  else                                  // released
  {
    myPBCounter1 = 0;  
  }
  if(myPBCounter1 > countPB)
  {
    myPBCounter1 = 0;
    beep();
    myPowerState = !myPowerState;
    if(myDebug & 4)
    {
      Serial.println(“Button 1 Pushed”);  // display message
    }  
  }
}
//  end check for push button

//  start beep
void beep()
{
  digitalWrite(BUZZ_PIN, HIGH); 
  timerAlarmWrite(timer1, 200000, false); // set up the timer to count 200ms once  
  timerRestart(timer1);   
  timerAlarmEnable(timer1);
}
//  end beep
LISTING 4
These routines determine a step's delay time and the time frame between each change in pulse position to ramp up or down myPercent—essentially controlling the pulse delay. Note that nothing more is changed once myPowerState == true (request is to be ON) and myPercent reaches 100%, or myPowerState == false (request is to be OFF) and myPercent reaches 0%.

// functions
...
//  start calculate Delay Time
void calculateDelayTime()
{
  myDelayCount = 100 - myPercent;
  myDelayTime = myDelayCount * stepTime;
}
//  end calculate Delay Time
//  start calculate Percent
void setPercent()
{
  if(myPowerState && (myPercent != 100))      // if myPowerState = true
  {    
    myStepDelayCounter--;
    if(myStepDelayCounter == 0)
    {
      myStepDelayCounter = myStepDelay;
      myPercent++;
      if(myPercent == 100)
      { 
        if(myDebug & 4)
        {
          Serial.println(“Power is now fully On”); // display message
        }
      }
    }
  }     
  if(!myPowerState && (myPercent != 0))   // if myPowerState = false
  {
    myStepDelayCounter--;
    if(myStepDelayCounter == 0)
    {
      myStepDelayCounter = myStepDelay;
      myPercent--;
      if(myPercent == 0)
      { 
        if(myDebug & 4)
        {
          Serial.println(“Power is now fully Off”); // display message
        }
      }
    }
  }
}
//  end calculate Percent
TIMING IS EVERYTHING

If we wanted to control the speed of a DC motor or intensity of an LED, we would most likely use the PWM function. The duty cycle used in the command would produce a continuous PWM output of the appropriate duty cycle. The higher the duty cycle, the larger the average voltage applied to your load. You might normally run the frequency of the PWM signal (which is independent of the duty cycle) at some high frequency, such as 1kHz, 10kHz, or even 20kHz, so you can’t hear the whine of the motor. The problem with using the PWM command is that it cannot be synced to the AC zero crossings—so even though we could provide a good 120Hz PWM output, it won’t apply control to the TRIAC properly, based on the zero crossings of each half cycle.

— ADVERTISMENT—

Advertise Here

Instead, we will need to divide each half cycle into multiple pieces, so we can have a smooth transition between each piece or step. Let’s arbitrarily choose 0-100% in steps of 1%. At 0%, we will not produce any control signal to the TRIAC. At 100%, we will tell the TRIAC to turn ON immediately after a zero crossing. At 50%, we will delay the control pulse for half of the half duty cycle time of 8.334ms, or 4.167ms. We’ll divide this 8.334ms into pieces, where each piece is 8.33ms/100 or 83µs per step. Since the timing is inverse, where the delay is smallest at 100% and the largest at 0%, we need to change myPercent into myDelayCount.

myDelayCount = 100 – myPercent;

Now the delay time can be calculated using a step time of 83µs above.

myDelayTime = myDelayCount * 83;

We will need to delay myDelayTime after seeing a zero crossing before outputting a high on the PSM_PIN to turn on the TRIAC ON at our predetermined point in the AC cycle. This will apply power to the load during just this portion of the cycle. We will allow the micro to handle this timing by invoking a timer interrupt.

So, let’s add some more code—a timer interrupt, a push button to manually start an ON/OFF process, and some code to increment/decrement myPercent (Listing 2).

The timer0 interrupt will be used to provide a pulse on the PSM_PIN to turn on the TRIAC ON. It is the zero-crossing interrupt that will start timer0. In that interrupt, the calculated variable myDelayTime, will tell the timer how long to count (delay) before the timer0 interrupt fires. A second timer, timer1 is used to allow a beeper to be turned OFF, 200ms after the push button has been pushed and the beeper turned ON. Ordinarily, I might just delay(200) without using a timer interrupt. However, since we are using interrupts for zero crossings and pulse delays, a delay command would halt execution and really mess up some timings. Be careful using delays.

Now we add some code to initialize the new timers (Listing 3). Additional functions include checking for a push button and acknowledging a “good” push. The variable myPBCounter1 keeps track of the number of 100ms counts while the PB1 is pushed. Contact noise (or a button release) will clear the counter. If the count exceed countPB = 3, then we signal a “good” press calling beep() and toggling the state of myPowerState. This variable will determine if we should ramp up or down percent.

Now we can take a closer look at the state of myPowerState. This variable describes the requested state of the TRIAC ON or OFF. The whole idea of this application is to move from the ON state to the OFF state (or vice versa) in a timed process. We already determined that the number of steps between ON and OFF will be 100 (70µs/step). The routine calculateDelayTime, takes the variable myPercent (0-100), and calculates out how long the timer0 variable myDelayTime should be. We discussed this earlier. The last function setPercent is the how the value of myPercent is adjusted in a timed fashion. We know this will be done in 100 steps, however the time between steps is set via the variable myStepDelay. Increase this count and it takes more times through loop() before we increment myPercent, essentially causing a longer time between the 100 myPercent steps (Listing 4).

At this point, a push of the button will change the state of myPowerState. This, in turn, begins a process to change the TRIAC’s control pulse between the states of ON (myPercent = 100) and full OFF (myPercent = 0). The time it takes between max and min is determined by the number of steps fixed at 100 and myStepDelay, the number of passes through loop() before the next step change. If we set myStepDelay large enough, we can have a ramp time of over an hour, which is about the time it takes the sun to fully breach the horizon. The trouble is that we have a push button to start the process, and we really need to have this done automatically, based on the time of day!

The MCU can, in fact, be used to keep track of time. Again, we have a issue with synchronization. Like having to stay in sync with the 60Hz AC, we also want to stay in sync with the actual time of day. The most accurate way might be to use Wi-Fi to contact the National Institute of Standards and Technology Internet Time Service. I want to make this project independent of the need for Wi-Fi, so let’s add a real-time clock (RTC) to the project.

I chose the DS3231 RTC module (about $3), because it has excellent accuracy (a few seconds per month), and it has two alarm registers, which, in our application, can be used for Dawn/Dusk times. It is interfaced through I2C, so it only requires two pins, and will survive extended durations without power and still maintain clock accuracy. Once the present time, Dawn, and Dusk times have been set, you shouldn’t need to adjust the clock at all.

We could use the USB connection to set the RTC, but then you would need a computer to interface with the device. Instead, I chose to add a small display and at least one more button, so you could interface with the RTC without anything but the on-board display and buttons. This will need a whole lot more programming, but will really make this project a stand-alone. Let’s look at what we’ll need to add.

ESTABLISHING A NEW DAWN

Interfacing the RTC module is easy. We define the I2C Clock and Data I/Os, and make the connections. This device uses the I2C address 0x90 to open up 18 registers in the RTC that we can access and alter. I will use the DS3231.h library to make this device more friendly to use.

The SSD1306, a 256×128 OLED display, is also I2C-based. While the display is rather small—around 1 square inch—it can put up several short lines of text. That’s just what we need to handle any adjustments necessary to the RTC. This device uses the I2C address 0x3C, so it will share the same I/Os as the RTC. Adafruit libraries are used to simplify its use.

— ADVERTISMENT—

Advertise Here

We can add another push button, as a minimum, to complete the user interface. Let’s use the first one to choose Modes or screens. What Modes do we need? I’ll try to keep this as simple as possible by defining just six main Modes: present Settings, change actual Date, change actual Time, change Dawn time, change Dusk time, and change Ramp time (Table 1).

Once Pushbutton2 has selected a Mode to edit, there will be a new set of Sub-modes. These Sub-modes will allow Pushbutton2 to increment the values of whatever item is being edited. The simplest case would be Mode5. If Pushbutton2 is pressed while on Mode5, a new set of Sub-menus will be displayed. In this case only two, sequenced by Pushbutton1 and changed by Pushbutton2. These two displays are shown in Table 2.

The code for all of this is too lengthy to include here. You’ll need to refer to the actual code on Circuit Cellar’s Article Code and Files webpage [1].

TABLE 1 
Pushbutton1 is used to sequence through all Modes. Pushbutton2 is used to select the present Mode to edit. While Mode0 has no properties to edit, Pushbutton2 can be used as a toggle for myPowerState. While an Alarm match will handle ON or OFF, you may want to toggle this for testing.
TABLE 1
Pushbutton1 is used to sequence through all Modes. Pushbutton2 is used to select the present Mode to edit. While Mode0 has no properties to edit, Pushbutton2 can be used as a toggle for myPowerState. While an Alarm match will handle ON or OFF, you may want to toggle this for testing.
TABLE 2
Each Mode has its own set of Sub-modes. Pushbutton1 is used to sequence through all Sub-modes. Pushbutton2 is used to select the present Mode to edit. In this case, when on Submode0, Pushbutton2 selects the "Change Ramp Time" Mode When on Submode1, Pushbutton2 exits the Sub-mode and returns to the Mode displays.
TABLE 2
Each Mode has its own set of Sub-modes. Pushbutton1 is used to sequence through all Sub-modes. Pushbutton2 is used to select the present Mode to edit. In this case, when on Submode0, Pushbutton2 selects the “Change Ramp Time” Mode When on Submode1, Pushbutton2 exits the Sub-mode and returns to the Mode displays.
ALARMS

Let’s take a closer look at what happens in the RTC when the actual time matches an Alarm time. Table 3 shows the two Alarm registers available in the DS3231 RTC. Note that the present time and date are stored in registers 0x00:0x06. Alarm 1 (Dawn time) is stored in registers 0x07:0x0A. Alarm 2 (Dusk time) is stored in registers 0x0B:0x0D. Bit 7 in each of the Alarm registers allows you to select which registers are used to determine a match.

TABLE 3
Register table from the DS3231 data sheet [2]. FYI, the I2C device also has a temperature sensor available.
TABLE 3
Register table from the DS3231 data sheet [2]. FYI, the I2C device also has a temperature sensor available.

In our case, we want to match each of these once a day. Here are the possibilities we can choose from for Alarm 1 (Dawn):

A-Alarm once per second
B-Alarm when seconds match
C-Alarm when minutes and seconds match
D-Alarm when hours, minutes, and seconds
match
E-Alarm when date, hours, minutes, and
seconds match
F-Alarm when day, hours, minutes, and
seconds match

We must choose D and set the bits correctly; otherwise, we could get many matches (A, B, or C) per day or not one every day (E or F). We must also enable these interrupts using bits 0 & 1 of the Control register 0x0E. When a match occurs, bits 0 or 1 of the Status register 0x0F will be set. An interrupt output is available on the DS3231. I am not using this output. Instead, I will “poll” the Status register 0x0F, and determine if either bit 0 or bit 1 is set. Then I can make the appropriate action—ON if the match is Alarm 1 (Dawn) or OFF if the match is Alarm 2 (Dusk).

CONCLUSION

Depending on the Earth’s latitude where you live, the length of daylight you receive will vary. Unless you live at the equator, we all have shorter days and longer nights in winter. In Florida, there are 3 hours more daylight in the summer, whereas in Alaska there are 13 hours more daylight in the summer. Since a chicken’s reproductive cycle is affected by light, the farther north you live, the greater the number of shorter winter days, which may affect your chickens’ egg production. According to the Michigan State University Extension [3], hens start to lay eggs when there are 14 hours of daylight, and maximum egg production occurs with 16 daylight hours. With the project described here, we can artificially extend the duration of daylight in my grandson’s chicken coop to 15 hours, to ensure that the hens continue to be productive.

It is normal for chickens to molt in the early fall, and this, too, is affected by the amount of daylight. At this time, they lose their feathers, grow new ones, and refrain from laying eggs. Molting can last from 2 to 4 months, depending on the breed. It’s a time for resting and rejuvenation, and is important to the hens’ health. Although the lifespan for a backyard chicken may exceed 5 years, egg production will begin to taper off after 3 years. At some point, their feed intake will outstrip their egg production. Unless these chickens are pets, you’d better get your grill ready, because eggs aren’t the only benefit of raising chickens.

What seemed like an easy problem to solve at the beginning of this project grew into a much larger project. They say that engineers are never quite satisfied with a project. There’s always another bell or whistle that could be added to improve it. This project involved controlling AC power, juggling interrupts, dealing with an accurate time of day, providing visual status, and giving the user a way to set certain parameters. Yikes! Too much to do, so little time. 

RESOURCES
Analog Devices | www.analog.com
Arduino | www.arduino.cc
DFRobot | www.dfrobot.com
Espressif System | www.espressif.com
Toshiba | www.toshiba.com

REFERENCES
[1] Circuit Cellar Article Code and Files Webpage.
https://drive.google.com/open?id=1xeU29a9ZSZfGGtYFe625S9jttg_Ra2Oy
[2] DS3231 Real-time Clock datasheet
https://www.analog.com/media/en/technical-documentation/data-sheets/DS3231.pdf
[3] Katie Ockert, “Decreasing daylight and its effect on laying hens.” Michigan State University Extension. October 01, 2019. https://www.canr.msu.edu/news/decreasing-daylight-and-its-effect-on-laying-hens

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JUNE 2023 #395 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
Website | + posts

Jeff Bachiochi (pronounced BAH-key-AH-key) has been writing for Circuit Cellar since 1988. His background includes product design and manufacturing. You can reach him at: jeff.bachiochi@imaginethatnow.com or at: www.imaginethatnow.com.

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Artificial Dawn and Dusk

by Jeff Bachiochi time to read: 20 min