Thursday, February 16, 2023

0000 0000 1011 1101

Tiny ESP-01s smashes Motor, LEDs, buzzer!

I love the idea of a small micro-controller "punching" above it's weight. An anaemic tiny processor bossing around motors when it has no right to is my idea of heaven. OK, so I don't get out much.

AND...if you add a little iOT into the recipe, then I'm there for the "fun".

So it happens that we are looking at a gate opening/closing mechanism for the bottom of the driveway.

You can buy them commercially and that's fine for regular sane people - but what about using a tiny ESP-01S to act as an Access Point, run a web server and turn on and off stuff WAY beyond it's capacity given it's flash memory and GPIO limitations?

Sounds like a little experimentation might be required to tip the balance from BUY to DIY.

Yes please!

This project has some distinct phases:

  • run the 3.3V ESP-01s and a heavy inductive motor (24V) from the same power supply
  • extend the ESP-01s meagre output capacity to be able to address many GPIOs using a 74HC595N shift register
  • use a ULN2803 with it's inbuilt flyback diode to handle the motor and it's current requirement
  • make an Access Point to activate the gate from any WiFi capable device

Let's go!

The power issue was solved (as I've done before) with a combination of a buck/boost module (LM2596 based) and LM1117 3.3V linear voltage regulator. The final drop was 20.5V to 7.5V using the switching regulator and then 7.5V to 3.3V using a TO-220 format LM1117 regulator.

I kept calling this an LM117 regulator in the video - apologies!

With this rig the "top" rail is 20.5V (for the motor) and the "bottom" rail is a steady 3.3V. One hilarious event during testing was the destruction of a 16V rated capacitor I forgot to remove which was still sitting in the top rail when I upped the voltage - love that smell of magic smoke!

The 74HC595N shift register part of the project was fairly easily achieved given that I have worked with these units earlier on this blog.

I will post the code below so that you can see just how simple this stuff can be using standard, mostly "borrowed", code.

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 0;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 1;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 2;

byte shiftbyte = 0;

void setup() 
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}

void loop() {
for (byte countleds = 1; countleds < 5; countleds++) {
  shiftbyte = 0;
  updateShiftRegister(); 
  delay(300);
  bitSet(shiftbyte, countleds);
  updateShiftRegister();
  delay(100);   
}
  shiftbyte = 0;
  updateShiftRegister(); 
  delay(300);
  shiftbyte = 0b00011110;
  updateShiftRegister();
  delay(300);  
}

void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, shiftbyte);
   digitalWrite(latchPin, HIGH);
}

Next up was the ULN2803 component - this is a very handy darlington transistor array that comes complete with a flyback diode (marked in the diagram below with a red arrow and circle) to hopefully prevent damage to the controller of an inductive load - e.g. let's not fry the little ESP8266 with a big nasty kick back from the motor when it stops!

We have also seen this component in action before.

Finally, I coded up the ESP-01S so that it behaved as a WiFi Access Point and could, er, "open the gate" complete with warning lights and buzzers. Very exciting!

/*
   Using an ESP-01s to turn on a motor, as
   well as running a few lights and buzzers
   all via a 74HC595N and ULN28703

   OneCircuit Sun 12 Feb 2023 19:52:25 AEDT

*/

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

/* Put your SSID & Password */
const char* ssid = "GateControl";  // Enter SSID here
const char* password = "1234";  //Enter Password here

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 0;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 1;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 2;

byte shiftbyte = 0; // the state of the shift register

long motor = 0;
boolean motorun = false;
bool GATEstatus = false;
bool openclick = false;
long currenttime = 0;
int turnoffmotortime = 5000;

/* Put IP Address details */
IPAddress local_ip(192, 168, 2, 1);
IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);

ESP8266WebServer server(80);

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  delay(20);
  // clear register
  shiftbyte = 0b00000000;
  updateShiftRegister();
  delay(500);

  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  delay(100);

  server.on("/", handle_OnConnect);
  server.on("/gateon", handle_gateon);
  server.on("/gateoff", handle_gateoff);
  server.onNotFound(handle_NotFound);

  server.begin();
}

void turnonsequence() {

  // turn off green
  shiftbyte = 0b00000000;
  updateShiftRegister();

  // turn on red and buzzer
  shiftbyte = 0b00100100;
  updateShiftRegister();
  delay(3000);
  shiftbyte = 0b00000000;
  updateShiftRegister();

  // flashing yellow, buzzer and motor

  motorun = true;
  motor = millis(); // start timing

  while (motorun) {

    shiftbyte = 0b01001000;
    updateShiftRegister();
    delay(200);
    shiftbyte = 0b01110000;
    updateShiftRegister();
    delay(200);
    shiftbyte = 0b01000000;
    updateShiftRegister();
    currenttime = millis();
    if (currenttime - motor > turnoffmotortime) {
      motorun = false;
    }
  }
  shiftbyte = 0b00000000;
  updateShiftRegister();
  GATEstatus = !GATEstatus;
}

void updateShiftRegister()
{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, shiftbyte);
  digitalWrite(latchPin, HIGH);
}

void loop() {
  server.handleClient();
  // green to start with
  shiftbyte = 0b00000010;
  updateShiftRegister();

  if (!GATEstatus && openclick) {
    turnonsequence();
  }
  if (GATEstatus && !openclick) {
    turnonsequence();
  }
}

void handle_OnConnect() {
  GATEstatus = false;
  openclick = false;
  server.send(200, "text/html", SendHTML(false));
}

void handle_gateon() {
  openclick = true;
  server.send(200, "text/html", SendHTML(true));
}

void handle_gateoff() {
  openclick = false;
  server.send(200, "text/html", SendHTML(false));
}

void handle_NotFound() {
  server.send(404, "text/plain", "Not found");
}

String SendHTML(uint8_t gate) {
  String ptr = "<!DOCTYPE html>\n";
  ptr += "<html>\n";
  ptr += "<head>\n";
  ptr += "<title>Gate Control</title>\n";
  ptr += "</head>\n";
  ptr += "<body>\n";
  ptr += "<h1>Gate Control</h1>\n";
  ptr += "<p>Press to open and close gate.</p>\n";
  ptr += "<form method=\"get\">\n";
  if (gate)
    ptr += "<input type=\"button\" value=\"Gate open\" onclick=\"window.location.href='/gateoff'\">\n";
  else
    ptr += "<input type=\"button\" value=\"Gate closed\" onclick=\"window.location.href='/gateon'\">\n";
  ptr += "</form>\n";
  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

I really enjoyed this project and indeed I think that as part of my continuing learning experience I may repeat the whole project using I2C (two wires!) instead of a shift register in another blog post and video. Watch this space!

In the meantime I hope that you like the result.




No comments:

Post a Comment