Let There Be Light - Part 3

Automating Plantation Shutters

Peter Stewart

Issue 79, February 2024

In Part 1 of this article, a Programming Connector (PROG CONN) is shown in Figure 6 and the following Photographs (P3 and P4). It is a six-pin male header for connecting to an external programmer.


The PSC is programmed, via a Future Technology Devices International Limited (FTDI) USB to Serial Adapter (Example shown in Photo above).

Figure 1

Figure 1 shows how the FTDI Adapter is connected to the PSC via the PSC PROG CONN. You could put the “Reset” and “Boot” pushbuttons on a small piece of Veroboard and make a simple FTDI to PSC Adapter.

Then to program the PSC, you follow this sequence:

  1. Press the “Reset” button
  2. While holding the “Reset” button pressed, press the “Boot” button
  3. Release the “Reset” button
  4. Release of the “Boot” button

This will then put the ESP32 on the PSC into “Program” mode.

You can then program the ESP32 by clicking on the “Upload” button on the Arduino IDE. Making sure, of course, that you have selected the right “Port” under the “Tools” menu.

A note of warning when using a FTDI Adapter. You have to set the Target operational voltage to either 3.3V or 5V via a jumper on the FTDI Adapter. This does two things. Firstly it sets the voltage levels for the “Tx” and “DTR” output signals and places the selected voltage on the “VCC” pin. Now if you do not use the “VCC” pin to power the target device (Note, usually I do not use the “VCC” pin), all should be good. However, if you intend to power the Target device from the FTDI, the output current capability when “VCC” is set to 3.3Vs, is only 50 mA. The 3.3V is derived from an internal voltage regulator within the USB to Serial chip on the FTDI Adapter, which is only capable of supplying 50 mA. Or you could do what I did and that was to add an AMS1117-3.3V module to the back of the FTDI Adapter. I cut the track connecting 3.3V to the 3-pin jumper header. I then connected the “5V” and “GND” from the FTDI Adapter to the input of the AMS1117-3.3V module. The 3.3V output is then connected to the 3.3V pin on the jumper header, see photo shown here.

While this “Manual” programming method does work, most of the time (sometimes your finger may slip and you get the sequence wrong), I prefer a more automated approach.

If you look at an ESP32 Development Module, eg “ESP32 DEVKIT V1 – DOIT” or just about any Development Module,

you will see a circuit which uses the “DTR” and “RTS” signals from the USB to Serial chip, to basically automate the pressing of the “Reset” and “Boot” buttons described earlier.

So, I wired the “RTS” signal to where the “CTS” signal appears on the 6-pin FTDI edge connector, cutting the track to the “CTS” input of the USB to Serial Chip. I then looked at the “DTR”, which drives the “Reset” and the “RTS”, which drives the “Boot”, on my Digital Storage Oscilloscope (DSO) (one of my best purchases ever!).

The above screen capture shows what I found when you attempt to upload a program. The yellow trace is the “DTR” signal and the purple trace is the “RTS” signal. It does not quite look like what I described in the “sequence” previously. So to cut a long story short, I came up with the circuit shown in Figure 2.

Figure 2

I know it is not the most elegant of solutions and some of those used on ESP32 and ESP8266 Development Boards are simpler (both ESP8266 and ESP32 use the same “Reset” and “Boot” sequence for programming). I did achieve the signal sequence shown in the next screen capture.

You can see it follows the programming sequence I described above and I found the circuit to be extremely reliable. The yellow trace is the “Reset” signal and the purple trace is the “Boot” signal.


As mentioned in Part 1 (December 2023) of this article, I have developed a Remote Control Unit (RCU) to allow “manual” control of the opening and closing of the Plantation Shutters. The RCU also allows you to “Reset” the PSC to allow changing of parameters used to control the PSC.


Figure 3

The design is fairly simple and is shown in the schematic shown here with the Parts List shown in Table 1.

The RCU is a four button remote and is controlled by an ATtiny3224 processor.

When no buttons are pressed, power is only consumed by the HT7333-A 3.3V Voltage Regulator. This is only about 3.5µA or put another way, 200000 hours to discharge the CR16340 Battery I have used.

If one of the Tactile buttons is pressed, this causes 3.3V to be applied to one of the Schottky Diodes, which in turn enables Q2. Q2 then pulls the gate of Q1 to ground turning it on. 3.3V then passes through Q1 to provide power to the ATtiny3224 and the HC-12 Transceiver. The two resistors, R9 and R11 ensure that Q1 and Q2, respectively, are turned off when power is removed by releasing whichever Tactile button was pressed.

Once the ATtiny3224 is powered, it first checks the battery voltage. If it has fallen below “BAT_MIN” (3.3 volts), it flashes “LED1” three times quickly.

The ATtiny3224 then checks to see which button was pressed. R1 through R4 are used to ground the button inputs to the ATtiny3224. Therefore, the ATtiny3224 will only see a “HIGH” (+3.3V), on the button input that was pressed. The ATtiny3224, will then set up the HC-12 for transmission and transmit the code associated with which button was pressed.

As already mentioned, there are four buttons:

  • Button 1 (KEY1) is used to open a shutter
  • Button 2 (KEY2) is used to close a shutter
  • Button 3 (KEY3) is used to reset the ESP32 in the associated PSC and put it into Webserver mode allowing all the settings to be changed as required
  • Button 4 (KEY4) selects the “Code Set”. A different “Code Set” is used for each PSC.

At the moment, up to five “Code Sets” are supported. This can be changed in software.

Once a Command has been issued by the RCU, it waits for an acknowledgement (“ACK”). If it receives one, “LED1” is illuminated for one second. If an “ACK” is not received within approximately five seconds, “LED1” is flashed once quickly.

More detail on the RCU program is described in the “SOFTWARE” section.

The Build

Parts Required:Jaycar
1 x ATtiny3224 SMD Processor (SOP8)*-
1 x HC-12 433MHz Transceiver*-
1 x HT7333A SMD 3.3 Volt Voltage Regulator (SOT89)*-
2 x 2N7002ET1G SMD N-MOSFET (SOT23)*-
4 x SD0805S020S1R0 SMD Schottky Diode*-
1 x NCD0805G1 SMD Green LED*-
1 x 4.7k 0805 SMD Resistor*-
6 x 10k 0805 SMD Resistor*-
1 x 100k 0805 SMD Resistor*-
1 x 180k 0805 SMD Resistor*-
1 x 220k 0805 SMD Resistor*-
1 x 270k 0805 SMD Resistor*-
2 x 100nF 0805 SMD Ceramic Capacitor*-
1 x 10µF 0805 SMD Ceramic Capacitor*-
4 x 6x6 8mmTactile Pushbutton SwitchSP0603
4 x Tactile Switch Buttons (different colours?)SP0596
1 x 2-Pin R/A Male HeaderHM3422
1 x 2-Pin Male Header^HM3212
1 x 3-Pin Male Header^HM3212
4 x M2.5x16mm P/H Screws*-
4 x 4Gx6mm P/H Screws-
1 x CR16340 Li-Ion BatterySB2294
1 x CR16340 Battery Holder-
1 x RCU PCB-
1 x 3D Printed Case-

* Quantity required, may only be sold in packs. ^ Made from 40-pin Header Strip

For the Remote Control Unit (RCU), I have followed the same process as I did for the Plantation Shutter Controller (PSC).

The schematic, as shown in Figure 3 and the PCB was developed using EasyEDA.


Using the Gerber files from the Project Resources, you can get the PCB manufactured.

As for the PSC PCB, I have again used a double sided PCB. This time, however, I have placed components on both sides of the PCB (see photos shown here).

I did this to try and reduce the size of the PCB as much as possible. The smaller the PCB, the smaller the case has to be to contain the PCB and battery.

Once I have the PCB in my hands, it is time to put the components on the PCB. You will see from the Photos shown here and the Parts List, that I have used a lot of SMD components.

I always solder the SMD components in place first. You can use a soldering iron with a fine tip and solder every component I have specified. However, I now use either my W.E.P. 853D Hot Air Gun or my UYUE 946C Reflow Hot Plate.

For the RCU PCB, I have used both my Hot Plate and Hot Air Gun. I am very impressed with my UYUE 946C Reflow Hot Plate, so I decided to use it for the top side components. I could not use the Hot Plate for the bottom side with components already on the Top Side. So I had to use the Hot Air Gun. As you can see from Photos above, both the Hot Plate and Hot Air Gun give very good results.

Now that all the SMD components have been soldered on to both sides of the PCB, all the through hole components are soldered on (see Photos shown here).

Note, all the connectors are placed on the back of the PCB and soldered from the top of the PCB. The last item to be soldered to the PCB is the HC-12 Transceiver.

You can see from the photo shown here, that I have soldered the 5-Pin header and antenna to the HC-12 module, before soldering it to the RCU PCB. Also, the 5-Pin Header and Antenna are placed on the underside of the HC-12 Module and soldered from the topside. The HC-12 Module is then placed on the topside of the RCU PCB and soldered on the bottom side.

Case Installation

Now, it is time to start putting the RCU together. Assuming you have 3D printed the RCU Lid (File “PS Remote Lid.stl”), you should have something similar to that in the photo shown here.

Before placing the PCB on the RCU Lid, put four button caps onto the four tactile switches. I have used colour caps as shown here.

I used four 4Gx6mm Pan Head (P/H) screws to mount the RCU PCB to the RCU Lid.

The Battery Module is the next component to make. The reason I selected the CR16340 Battery is three fold. Firstly it is a Li-ion battery with a nominal 3.7V output, which is maintained close to near the end of its charge. Secondly, because it is close to half the length of the 18650 Li-ion battery. I usually use and as such takes up a lot less space inside a case. Finally, it has a reasonable capacity, so will probably last a couple of years.

To make the Battery Module, solder the CR16340 Battery Holder onto a strip of Veroboard as shown in Figure 4.

Make sure you cut the track between the two terminals. Otherwise when you plug the battery in, there will be a fried Veroboard track and possibly one hot and dead battery. I soldered a red and black wire to the Veroboard at the BAT+ and BAT- respectively. The wires are then terminated with a 2-Pin female header.

I also put a bit of Velcro onto the back of the Battery Module and also onto the bottom of the Case (File “PS Remote Base.stl”).

This is to stop the battery rattling around and possibly shorting out the RCU PCB or damaging the HC-12 antenna.Now all that is required to complete the construction of the RCU, before screwing the Lid to the Base, is to program the ATtiny3224.

The Software

The software consists of single file, “ATtiny3224_HC-12_Tx_Remote_V1.ino”. The ATtiny3224 is programmed using an UPDI Programmer. The one I presented in the article “Portable Power” in Issue 75 (Oct 2023) will do nicely.

Setting up the Arduino IDE

The Arduino IDE needs to be set up as described in the “Portable Power” article. Before you can compile a program for an ATtiny3224, you need to configure the Arduino IDE. Once installed, select the settings shown in the following Screen Capture, under the “Tools” menu item.

Note: the “Clock” is set to “10MHz Internal”. This is the max recommended clock rate when operating at 3.3V.

Program Description

After the initial program description for “ATTiny3224_HC-12_Tx_Remote_V1.ino”, I have all the “#defines” for debugging, if enabled. Next, as usual for Arduino programs, the Libraries (Header Files) used are declared at the beginning of the program. In this case, I have only one Header File, "EEPROM.h". This Header File contains all the data declarations and Function Prototypes for accessing the ATtiny3224 internal EEPROM. As the RCU is powered down, each time a pressed button is released, I keep the last accessed “Code Set” number stored in EEPROM. As previously mentioned, a “Code Set” is associated with a PSC. At the moment, five “Code Sets” are allowed, meaning up to five different PSC’s can be controlled from the one RCU. If you need to control more PSC’s, change the “MAX_CODE_SETS” define. A warning though, a single press of Button D is required to increment to the next “Code Set” (wrapping back to “Code Set” 1 once “MAX_CODE_SETS” is exceeded). So, if you have lots of PSC’s to control manually, you could be pressing Button D many times. The following is all the defines and variable declarations used in the RCU.

#define HC12_SET 10              // Connected to SET pin on HC-12, Setting LOW puts the HC-12 into AT Command mode
#define HC12_CMD_START_DELAY 40  // Time in msec after setting SET low before AT commands can be issued
#define HC12_CMD_END_DELAY 60    // Time in msec after return SET to Tx/Rx Mode before operation can commence
#define HC12_CMD_READ_DELAY 10   // Time in msec to wait before reading response to an AT command
#define HC12_SERIAL_TIMEOUT 1000 // Time in msec to wait for serial output before timing out
#define CHAN_SET 55              // Channel HC-12 will operate on (1-126), note above 100 not guaranteed
#define NUM_CMD_SENDS 5          // Number of times a command is sent before giving up
// Define Buttons A, B, C and D and associated variables
#define But_A 0    // PA4
#define But_B 1    // PA5
#define But_C 2    // PA6
#define But_D 3    // PA7
bool Button_press_flag;
int Sum_Buttons;   // Holds the sum total of the buttons pressed
// LED defines
#define Led_pin 6  // PB1
#define F_FAST 20  // Number of milliseconds for LED Fast Flash (fail)
#define F_NORM 250 // Number of milliseconds for LED Normal Flash (success)
// Data for sending 2.4 MHz Commands
struct {
  unsigned char Code_set;   // Code Set number (0 to 4 currently)
  unsigned char value;      // data to be sent
  unsigned int count;       // counter to be sent with data
// defines for Code Sets
#define Code_set_address 0 // location from beginning of EEPROM
#define MAX_CODE_SETS 5    // Number of code sets (or shutters)
#define NUM_REM_CMDS 3     // Number of Remote commands - Open, Close and Reset
// Battery Pin definition
#define Bat_Pin 7          // Battery voltage read from PB0
uint16_t Bat_Volts;
#define BAT_MIN 330        // Minimum battery Voltage V*100
uint8_t R_F=0;             // Variable for holding Reset Register contents

This is followed by two of the four functions, not counting “Setup()” and “Loop()”, used in the RCU program. The first function is “setup_HC12()”. This is called from the “Set_HC12_to_4800Baud()” function to firstly set the channel number “CHAN_SET” to be used for communicating with the PSC. If you think the default channel number is being interfered with, try changing the channel number. Don’t forget to make the same change in the PSC program. Next the HC-12 Mode is set to low current mode (~80 µA total consumption) using the “FU2” command. Note the “FU2” command automatically sets the baud rate to 4800 baud both through the air and for the HC-12 to communicate with the ATtiny3224 microcontroller. No checking is performed in this function as it is assumed that the baud rate is known and operational for communicating between the ATtiny3224 microcontroller and the HC-12 Transceiver.

// This function sets the channel number and low power mode (FU2) hot the HC-12 transceiver
void setup_HC12( void)
  String R_Str;
  // First set channel to CHAN_SET
  R_Str = Serial1.readStringUntil('n');
  PRINTL("R_Str 1 is ", R_Str);
  // Then set up for low current mode "FU2"
  R_Str = Serial1.readStringUntil('n');
  PRINTL("R_Str 2 is ", R_Str);

Next, is the “Set_HC12_to_4800Baud()” function. This function initially sets the HC-12 into AT command mode. During the execution of the “Setup() function, the serial connection to the HC-12 Transceiver is set to 4800 baud. So, when this function is called, the ATtiny3224 is attempting to communicate at 4800 baud. If it is successful, the HC-12 Transceiver returns the “OKrn” status response. This results in the variable “HC12_cnt” being zero or greater. If “OK” is not received, HC12_cnt will be “-1”. If all is good, “setup_HC12()” is called as described above. If this fails, an attempt is made to communicate at 9600 baud. This would be the case on a first power up of the RCU as the default baud rate of a HC-12 is 9600 baud. If this also fails, the RCU LED is flashed six times fast, to let the user know there is something wrong with the RCU. At the end of all this, the ATtIny3224 Serial interface to the HC-12 Transceiver is set back to 4800 baud.

// This function determines whether the HC-12 is set for 4800 baud operation
void Set_HC12_to_4800Baud( void)
  String Read_Str;
  int HC12_cnt =0;
  // First set HC-12 into AT Command mode
  digitalWrite(HC12_SET, LOW);   
  // Enable AT Cmd Mode
  // First check if set to 4800 baud
  Read_Str = Serial1.readStringUntil('n');
  HC12_cnt = Read_Str.indexOf("OK");
  PRINTL("Read_Str 1 is ", Read_Str);
  if(HC12_cnt >= 0)
    // means baud is set to 4800
    // so set HC-12 to FU2 Mode ie. 4800baud Ch 55
    // baud rate is 9600?
    Read_Str = Serial1.readStringUntil('n');
    PRINTL("Read_Str 2 is ", Read_Str);
    HC12_cnt = Read_Str.indexOf("OK");
    if(HC12_cnt >= 0)
      // If not 4800 or 9600 baud, help
      PRINTLN("Something is wrong!!");
      LED_flash(6, F_FAST); 
      // Let user know there is a problem
  digitalWrite(HC12_SET, HIGH); 
  // Enable AT Cmd Mode
  // wait time for HC-12 to be ready

The next function is found after the “Loop()” function. It is “Send24G_code()”.

As you most probably have realised, I initially stole this function from another project of mine. I changed much of the contents, but not the function name. The original function was used when I was using a 2.4 GHz transceiver, which I mentioned in “Part 1“ of this article.

Initially, the “Send24G_code()” function causes the HC-12 Transceiver to send the command (“val”) associated with the button press, in a “for” loop. There is a delay, while the program waits for an acknowledgement to be received (“ACK” string is received). If this does not occur, the command is transmitted again, up to “NUM_CMD_SENDS” times. If an “ACK” is received, the “for” loop is exited, using the “break” instruction, with the “Tx_Flag” also being set. The command sent as well as the “Code Set”, is then saved in EEPROM. It is important that the “Code Set” is saved so that on a new press of a button, when the ATtiny3224 is powered up again, it knows what the last “Code Set” used was and sends the new command to the same PSC.

If the “Tx_Flag” has been set, a “F_NORM” flash (long) of the RCU LED occurs to let the user know the command was successful and the PSC should execute that command. If the “Tx_Flag” is not set, a “F_FAST” flash (short) of the RCU LED occurs to let the user know the command was not successful and most probably, the PSC will not execute the command.

void Send24G_code(unsigned char val)
  bool Tx_Flag = false;    // Set if transmission successful
  String ACK_Str = "";
  int cnt = 0;
  char fc;
  for(int i = 0; i<NUM_CMD_SENDS; i++)
    ACK_Str = Serial1.readStringUntil('n');
    ACK_Str.trim();    // Remove "r"
    if(ACK_Str == "")
      PRINTLN("NULL String received");
    }    else
    cnt = ACK_Str.indexOf("ACK");
    PRINTL("index = ", cnt);
    if(cnt >= 0)
      Tx_Flag = true;
      PRINTLN("ACK has been received");
  EEPROM.put(Code_set_address, SCD);
  // There could still be data in the Rx Serial buffer, so flush it cou
  while (Serial1.available()) fc =;
    LED_flash(1, F_NORM);     // Quick LED Flash to indicate transmission
    // Tx not succesful, so very short flash so at least you know
    // the remote is still powered
    LED_flash(1, F_FAST);
  Tx_Flag = false;

The last function is the “LED_flash()” function. This function turns the RCU LED on and off for the number of times requested (“count” parameter) and it is on for the time specified in the “rate” parameter.

void LED_flash(uint8_t count, uint8_t rate )
  for(int i = 0; i<count; i++)
    digitalWrite(Led_pin, HIGH);  // LED ON - inverse logic
    digitalWrite(Led_pin, LOW);  // LED OFF - inverse logic

Now, back to the “Setup()” function. This is always first executed on power up, a button has been pressed.

The first thing the program does is save the Reset Flags Register. This is done so that if a “Software Reset” has occurred, buttons A and B pressed at the same time, then, the HC-12 can be re-initialised. See later in the code.

The HC-12 Transceiver is then put into data transceiver mode.

The pins on the ATtiny3224 connected to the four buttons are then set as Inputs.

The LED output is set up and turned off.

You will then see that I have set up the reference voltage for the ADC to be the internal 2.5V. This is because the resistor divider I have used (R7 and R8 on Figure 3), will not exceed 2.5V. This gives me maximum resolution on the reading of the battery voltage, especially as I have also set 12-bit resolution on the ADC. Also, you will notice, I have used direct register addressing for setting up the internal voltage reference. I have done this because the normal “analogReference()” instruction did not appear to work.

The battery voltage is then measured by the ADC and converted to a more real voltage (hundredths of a volt). This is compared to the minimum allowable battery voltage (“BAT_MIN”). If the measured battery voltage is less than “BAT_MIN”, the RCU LED is flashed three times quickly, to let the user know it is time to replace the battery.

The EEPROM is then read to determine the “Code Set” last used to send the new command to the appropriate PSC.

Note, on first execution of this program, the EEPROM could be filled with random data. So a modulo function is executed to ensure the “Code Set” is between 1 and “MAX_CODE_SETS”. The serial ports are then set up, the Debug serial port, if debugging is enabled and the serial port connected to the HC-12 Transceiver. Then a check is performed, as mentioned above, to see if the “Software Reset Flag” has been set. This occurs when buttons A and B are pressed at the same time. This needs to occur on the first power up of the RCU to ensure the HC-12 is initialised properly. This is the only time the HC-12 is initialised. The “Button_press_flag” is initialised to “false”, i.e. no buttons pressed and the “Sum_Buttons” variable initialised to zero indicating no button inputs have been read.

void setup() {
// Reset Flags Register (RSTCTRL.RSTFR) is saved in General Purpose IO Register 0
// (GPIOR0) as part of Boot sequence. Reset flags are required later to determine
// action to be taken.
  R_F = GPIOR0;     
  GPIOR0 = 0;
  RSTCTRL.RSTFR = 0x3F;   // reset all Reset Flags
// Set HC-12 to Transceive Mode
  pinMode(HC12_SET,OUTPUT);    // SET Pin for HC-12
  digitalWrite(HC12_SET, HIGH); // First set to normal Tx/Rx mode
// Set up Button Input Pins
  pinMode(But_A, INPUT);
  pinMode(But_B, INPUT);
  pinMode(But_C, INPUT);
  pinMode(But_D, INPUT);
  // Setup LED
  pinMode(Led_pin, OUTPUT);
  digitalWrite(Led_pin, LOW);  // LED will be off
  // Setup Analog Reference to 2.5V, for when reading battery voltage
  ADC0.CTRLC |= 0x6;
  analogReadResolution(12);   // Want 12 bit resolution, only other option is 8 bit
  // Read the Battery Voltage via the hardware Voltage divider
  Bat_Volts = analogRead(Bat_Pin);
  // Map the 12 bit ADC value to a real voltage in hundreths of a volt
  Bat_Volts = map(Bat_Volts, 0, 4096, 0, 420);
  // If the Battery Voltage has fallen below the minimum setting
  // flash the LED three times quickly
  if(Bat_Volts < BAT_MIN) LED_flash(3, F_FAST);
  // Read EEPROM data
  EEPROM.get(Code_set_address, SCD);
  // There are only MAX_CODE_SETS code sets, 0 to MAX_CODE_SETS-1
  // The very first time through, rubbish may be in the EEPROM
  SCD.Code_set = SCD.Code_set % MAX_CODE_SETS;
  // Setup Debug and HC12 serial ports
  BPRINT(9600);    //Pins 6,7 (RxD0, Txd0) (Debug Port)
  Serial1.begin(4800);   //Pins 12,11 (RxD1, TxD1) (HC-12 Port)
 PRINTLN("nStarting RCU");
  PRINTL("Battery Voltage = ", float(Bat_Volts)/100.0);
  PRINTS("Reset Flags are : ");
  // Only setup HC12 Transceiver on Software Reset, 
  // ie. But A and But B pressed simultaneously
  if(R_F & RSTCTRL_SWRF_bm) Set_HC12_to_4800Baud();
  Button_press_flag = false;
  Sum_Buttons = 0;       // Initialise the buttons sum

Now it is the “Loop()” function where all the work really happens.

Initially, no buttons have been read, so the “Button_press_flag” will be false.

Once the buttons have been processed and the appropriate command transmitted, the “Button_press_flag” will be set to true and while a button is still pressed, nothing but the “delay” function at the end of the “Loop()” function is executed. This continues forever, until the button is released and a button pressed again with the whole process beginning again.

So, on initial button(s) press, there is a half second wait to let the button(s) pressing to settle. Then, depending on which button(s) was pressed, a sum is performed to determine what action is required. A “switch” statement is executed to determine what action to take. “case 0” is not actually a possibility, as this would indicate no buttons have been pressed and you need at least one button being pressed to power up the RCU and execute its program.

If only Button A (“case 1”) was pressed, the “Open” shutter command, a calculation is performed based on the “NUM_REM_CMDS” (Currently only three, “Open”, “Close” and “Reset”) and the “Code Set” stored in EEPROM. This command is then sent to the HC-12 for transmission. All the PSC’s will receive the command, but only the PSC configured with the correct “Code Set” or “Shutter Number” will respond. The “Button_press_flag” is set “true” and the “if” statement will now be bypassed.

The same happens for Button B (“case 2”) and Button C (“case 4”) being pressed. If Button D (“case 8”) is pressed, the “Code Set” number is incremented (with wrapping) and saved to EEPROM. The RCU LED is flashed to let the user know which “Code Set” is now active.

There are a few special button press combinations. Button A and Button B (“case 3”) being pressed at the same time. This causes a Software Reset to be executed. For this to happen, all you need to do is set a bit in the Software Reset Register (SWRR) in the Reset Controller of the ATtiny3224. However, this SWRR Register is under Configuration Change Protection. This means you cannot change it until the appropriate code is written to the CPU Configuration Change Protection (CCP) Register. This is shown at “case 3” with the direct register addressing method commented out and I have used the Arduino code function.

There are three further button combinations which the RCU can process. They are all “Broadcast” commands. That is, all PSC’s will respond. For example, pressing Buttons A and D at the same time sends the command to all PSC’s to open their shutters. Buttons B and D to close all shutters at the same time. Buttons C and D to reset all ESP32’s in each PSC.

I should not have included this combination as it will result in all PSC’s firing up their Webservers at the same time. This would be really confusing as they all have the same SSID and password. You would have to power down all the PSC’s except one to configure it. Then power up the others one at a time. I have never used the Broadcast Reset command and for a good reason as explained.

void loop() {
  // Only process button presses if not already
  // processed
  // give time for button(s) to be pressed properly
    if(digitalRead(But_A)) Sum_Buttons+= 1;
    if(digitalRead(But_B)) Sum_Buttons+= 2;
    if(digitalRead(But_C)) Sum_Buttons+= 4;
    if(digitalRead(But_D)) Sum_Buttons+= 8;
    PRINTL("Sum Buttons = ", Sum_Buttons);
    // Process buttons pressed
      case 0:
        PRINTLN("No Buttons Pressed??");
      case 1:
        // just button A (Open) pressed
        PRINTLN("Open Button pressed");
        SCD.value = SCD.Code_set * NUM_REM_CMDS + 1;
        Button_press_flag = true;
      case 2:
        // just button B (Close) pressed
        PRINTLN("Close Button pressed");
        SCD.value = SCD.Code_set * NUM_REM_CMDS + 2;
        Button_press_flag = true;
      case 3:


Figure 5
Parts Required:Jaycar
1 x CN3795 SMD Battery Charger (SSOP10)-
1 x AO3401 SMD P-MOSFET (SOT23)*-
2 x 1N5822 (SS34) SMD Schottky Diode (DO214AB)*-
1 x NCD0805Y1 SMD Yellow LED (0805)*-
1 x SRR1206-820YL 82µH SMD Inductor*-
4 x SD0805S020S1R0 SMD Schottky Diode*-
1 x NCD0805G1 SMD Green LED*-
1 x 0.27Ω 1206 SMD Resistor*-
1 x 120Ω 0805 SMD Resistor*-
1 x 1kΩ 0805 SMD Resistor (Note can use up to 4.7 k)*-
1 x 10kΩ 0805 SMD Resistor*-
1 x 20kΩ 0805 SMD Resistor*-
1 x 68kΩ 0805 SMD Resistor* ^-
1 x 120k 0805 SMD Resistor*-
2 x 100nF 0805 SMD Ceramic Capacitor*-
1 x 220nF 0805 SMD Ceramic Capacitor*-
1 x 1µF 0805 SMD Ceramic Capacitor*-
2 x 100µF 6032 SMD Tantalum Capacitor* #-
2 x 2-Pin PCB Mount Screw Connector*HM3130
1 x RCU PCB-

* Quantity required, may only be sold in packs. ^ For R5, see section on MPPT. # If the input voltage is likely to be above 16 Volts, C6 needs to be a higher rating.

As mentioned at the beginning of this article, three items were to be covered. This is the third. As also mentioned in Part 1 of this article, I have used a Solar Battery Charger (SBC) module to charge the two Li-ion batteries in the PSC.

I have used a 10 Watt Solar Panel, which provides enough power to charge the batteries for two PSCs.

The design

For the Solar Battery Charger (SBC), I have followed the same process as I did for the Plantation Shutter Controller (PSC) and the Remote Control Unit (RCU).

The schematic, as shown in Figure 5 (Parts List in Table 2) and the PCB was developed using EasyEDA.

The design of the circuit shown in Figure 5 was based on the information supplied in the Datasheet from Consonance for their CN3795. As can be seen from Figure 5, it is a very simple circuit based closely on a Buck regulator.

Most of the smarts, of course, is in the CN3795 chip. It has a driver for the external P-MOSFET, it supports Maximum Power Point Tracking (MPPT), it can sense the battery charge current and the battery charge voltage. It also has an output to drive a LED to indicate when it is charging the battery.

Several components need to be selected and in some cases their values calculated. Again, the Consonance CN3795 Datasheet has been most helpful.


The selection of the P-MOSFET has been fairly straightforward. The CN3795 can drive a P-MOSFET with an input capacitance of up to 2000pF (CISS). It has a voltage clamp, which places a maximum of 8V below VCC onto the gate of the P-MOSFET. This means as long as VGS is greater than 8 volts, the P-MOSFET can be utilised. The P-MOSFET I selected was the AO3401.

It has the following characteristics:

VDS : -30V (Drain-Source Voltage)

VGS : ±12V (Gate-Source Voltage)

ID : 4.1 Amps (Continuous Drain Current)

RDS(on) : 75mΩ (Drain-Source on Resistance)

CiSS : 954 pF (input Capacitance)

Current Sense Resistor

Initially, I was looking at a maximum battery charge current of 500mA. This is much less than the 1C rate for the 3000mAh Li-ion batteries I would be using.

The charge rate is actually, 500/3000 or 0.17C. A lower charging rate can extend the life of a Li-ion battery.

To calculate the Current Sensor Resistor (R7), the CN3795 datasheet recommends the following formula:

ICH = 120 mV/RCS

Where ICH is the full scale charge current and RCS is the current sense resistor (R7).

Then from equation 1, assuming ICH is 500mA, then R7 will be 240mΩ. I selected a value of 270mΩ for R7. This is a bit on the conservative side and gives an actual ICH of 444mA or 0.15C.

Output Voltage

As I wanted to charge two Li-ion batteries in series, the maximum charge voltage should be 8.4V (it is recommended to charge a Li-ion battery to 4.2V per cell). Therefore, using the following equation from the CN3795 datasheet:

VREG = 1.205 x (1+R1/R2) + IB x R1

Where IB is the bias current into the CN3795 FB pin, which is 60nA.

Using the values I had previously calculated, VREG is 8.45V, which is pretty good just using standard value components.

Maximum Power Point Tracking (MPPT)

I decided to use MPPT, as this gives the most efficient use of the Solar Panel output. Basically, the MPPT Voltage of a Solar Panel is the output voltage which gives the maximum output power for any given intensity of light.

While the output power will vary with light intensity, apparently the output voltage for maximum power is the same for different intensities of light.

I performed a check on the Solar Panel I am using, the ATEM VASPZHI-1P 10W, using my Electronic Load (See Issues 70 and 71 of DIYODE Magazine) and determined that the MPPT Voltage was around 15.4V. So, I changed the values of R5 and R6 from that in Figure 5, which were originally derived for a different Solar Panel. From the CN3795 datasheet, the MPPT Voltage is:

VMPPT = 1.205 x (1 +R5/R6)

The value I used for R5 was 120kΩ and the value for R6 was 10kΩ.

From equation 3, this gives a VMPPT of 15.67V, close enough, again considering I am using standard resistor values. What this means is that only when the output voltage of the Solar panel exceeds 15.67V, is the CN3795 charging the Li-ion Batteries.


One of the most critical components of the SBC design is the Inductor (L1). The deriving of the value of the inductance for L1 is through the use of the following equations from the CN3795 datasheet.

ΔIL = 1/(f)(L) x VBAT x (1 - VBAT/VCC)


L > 5 x (VCC - VBAT) (µH)

Where ΔIL is the Inductors ripple current:

f is the switching frequency, 310kHz for the CN3795

L is the inductor value (I derived 82µH)

VBAT is the battery voltage (8.4V)

VCC is the input voltage (~15.7V)

Therefore, from equation 5, L must be greater than 36.5µH, which it is! (Again being very conservative). From equation 4, the ripple current is ~ 154 mA. The recommendation for ripple current, from the CN3795 datasheet is ΔIL = 0.3 x ICH, which from the Current Sensor Resistor section above is 0.3 X 444 = 133mA, which is not a bad outcome. I must admit, I originally used 500mA as ICH, which would have given a ΔIL of 150mA.

Input and Output Capacitors

The CN3795 datasheet suggests the following for the Input and Output capacitors:

Input Capacitors (C1, C5 and C6)

  • A High Frequency (HF) capacitor from 47nF to 1µF (C1 – I chose 100nF as it is commonly used for HF bypassing);
  • A Ceramic capacitor from 1 to 10µF (C5 – I chose 1µF, I had several in my parts box);
  • Electrolytic capacitor for Low Frequency filtering (C6 – I chose 100µF as it was the largest capacitor I could easily obtain in a SMD package and still take up little space).

Output Capacitors (C3 and C7)

  • A Ceramic capacitor from 1 to 10µF (C3 – I chose 1µF, I had several in my parts box);
  • A 10µF Electrolytic capacitor for Low Frequency filtering (C7 – I chose 100µF, as it would be the same as the input capacitor (C6), one less different capacitor. 1. Also, the larger capacitor would improve output ripple.

The Diodes

The Diodes, D1 and D2 both perform important functions.

D1 basically performs a blocking function to prevent current flowing back into the CN3795 VCC pin when power from the Solar Panel is absent.

D2 prevents negative voltages, caused by the Inductor (L1), from being placed on the P-MOSFET and CN3795. This is normal with Buck converters.

Both D1 and D2 are Schottky diodes to minimise the forward voltage drop and are rated at more than the maximum current to be supplied to batteries when charging.


Again, I have used a double sided PCB. Here all components are on the top side of the PCB (See Photo shown here, with only the connectors being soldered on the bottom side of the PCB.

I originally also used a through hole LED for the Charging LED. I have subsequently changed this to a SMD LED.

The bottom side of the PCB is mostly a ground plane, which gives slightly better Electromagnetic Interference (EMI) performance.


This now completes my Plantation Shutter Controller Project. I believe I have covered all the aspects of the Project.

From the PSC and RCU to the support components, which includes the programmers for the ESP32 and the ATtiny3224 and the Solar Battery Charger for the batteries in the PSC.

Through this Project, I have covered many aspects of design. Not only the electronic design of the PSC, RCU and SBC, but also the design of installation and mounting components for the PSC.

I have learnt how to use Fusion 360 to design the cases for the PSC and RCU, plus all the components for mounting the PSC to my shutters. I did go through several iterations of cases and mounting components. I still think I can improve on the components, which attach to the shutter blades and connect to the Servo Motor. But at this time, I am fairly happy with my 3D printing attempts. I have also learnt a lot about how to get the best out of my Creality Ender 3 V2 3D printer.

However, I feel this Project is not entirely complete for DIYODE readers. I believe I can make the Remote Control Unit (RCU) a bit simpler by removing several components, which may improve power consumption. This is my next project improvement on my long running project.

I have also been looking at the Solar Battery Charger (SBC). While I am happy to use the Consonance CN3795, many others may not. I have looked at using a microcontroller to replace the CN3795. I have prototyped two designs. The first uses the ATtiny412 8-Pin microcontroller. There were several discoveries about using the ATtiny412 that many may find of interest. The second design uses one of my favourite microcontrollers, the 14-Pin ATtiny3224.

I hope to present the updated RCU and new SBC designs in a future article.


Peter Stewart is a retired engineer and regular contributor to DIYODE magazine.

Other projects include an ATtiny85-based general purpose timer with buzzer in Issue 53, WiFi Temperature Sensor with Scrolling Display in Issue 60, an ATtiny84-based Auto-Ranging USB Current Meter in Issue 64, and Arduino-based Car Presence Sensor & Parking Assistant.

Now that the Hardware and the Software has been described in Parts 1 and 2 (December 2023 and January 2024). Let’s look at programming the ESP32 based Plantation Shutter Controller (PSC), the Remote Control Unit (RCU) and the Solar Battery Charger (SBC).

Peter Stewart

Peter Stewart