Timed Relay On with Momentary Digital Encoder Push Button

Hi there, folks.

I found a project online, and it suits everything I need for it. I've gathered all the bits, which include;

  • Pro Micro (Project calls for Pro Mini)
  • Relay
  • Digital Encoder
  • Buck Converter
  • Power Switch

The Arduino loads the code, which reads

Relay timer - User settable timer controlling a relay output
Implementation 2 - Arduino outputs directly runs LED segments

Hardware requirements
---------------------
- Arduino Uno/Nano/Mini/etc
- 7 segment 4 Digit LED display (similar to http://www.taydaelectronics.com/led-displays/7-segment-4-digit/led-display-7-segment-4-digit-0-56-inch-common-cathode-super-yellow.html)
- Rotary encoder with built in selection switch
- Relay output or relay module (commonly avaiable on eBay and other suppliers)

Function
--------
- Arduino manages the display as a multiplexed POV refresh using direct I/O
- Rotary encoder allows setting the required timer value
- Rotary encoder switch used to start the timer
- Timer can be paused with a press of switch. Second press resumes and long press ends the timer.
- While timer is active (running or paused) the relay output is switched on.

Circuit Connections
-------------------
+---------+--------------------+
| Arduino | Connected to       |
+---------+--------------------+
| D0      | N/C (Arduino Rx)   |
| D1      | N/C (Arduino Tx)   |
| D2      | Rotary Encoder B   |
| D3      | Rotary Encoder A   |
| D4      | LED pin 6 (dig 4)  |
| D5      | LED pin 8 (dig 3)  |
| D6      | LED pin 9 (dig 2)  |
| D7      | LED pin 12 (dig 1) |
| D8      | Selection Switch   |
| D9      | N/C                |
| D10     | Relay Output       |
| D11     | N/C                |
| D12     | LED pin 11 (seg A) |
| D13     | LED pin 7 (seg B)  |
| A0      | LED pin 4 (seg C)  |
| A1      | LED pin 2 (seg D)  |
| A2      | LED pin 1 (seg E)  |
| A3      | LED pin 10 (seg F) |
| A4      | LED pin 5 (seg G)  |
| A5      | LED pin 3 (seg DP) |
+---------+--------------------+

Library Dependencies
--------------------
MD_KeySwitch and MD_REncoder can be found at https://github.com/MajicDesigns/MD_KeySwitch

Revision History 
----------------
Feb 2016 - version 1.0
- First release

Copyright
---------
Copyright (C) 2015 Marco Colli. All rights reserved.

This is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <MD_REncoder.h>
#include <MD_KeySwitch.h>

// Debugging stuff -------------------------
#define DEBUG 0

#if DEBUG
#define PRINTS(s)   Serial.print(F(s));
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(F("0x")); Serial.print(v, HEX); }
#else
#define PRINTS(s)
#define PRINT(s, v)
#define PRINTX(s, v)
#endif

// Hardware pin definitions  ---------------
// Rotary Encoder
const uint8_t RE_A_PIN = 3;
const uint8_t RE_B_PIN = 2;

// Selection key
const uint8_t SEL_PIN = 8;

// Control output
const uint8_t OUTPUT_PIN = 10;

// Digit multiplex selection - [0] is least sig dig (LSD), [n] is MSD
const uint8_t digitPin[] = {4, 5, 6, 7 };

// Segment multiplex selection - in order segments A B C D E F G DP
const uint8_t segmentPin[] = { 12, 13, A0, A1, A2, A3, A4, A5 };

// Static Data tables ----------------------
// LED segments are defined as uint8_t values with bits mapped as follows:
//     MSB               LSB
// +----+-----------------+
// |Bit | 7 6 5 4 3 2 1 0 |
// +----+-----------------+
// |Seg |DP G F E D C B A |
// +----+-----------------+

// LED segments for digits
const PROGMEM uint8_t digits[] = 
{ 
  0x3f, 0x06, 0x5b, 0x4f, // 0123
  0x66, 0x6d, 0x7d, 0x07, // 4567
  0x7f, 0x6f  //89
};

// LED segments for alpha characters
const PROGMEM uint8_t alpha[] =
{
  0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, // ABCDEF
  0x3d, 0x76, 0x06, 0x0e, 0x00, 0x38, // GHIJKL
  0x00, 0x54, 0x3f, 0x73, 0x67, 0x60, // MNOPQR
  0x6d, 0x78, 0x3e, 0x3e, 0x00, 0x00, // STUVWX
  0x6e, 0x5b  // YZ
};

const uint8_t DECIMAL = 0x80;

// Miscellaneous ---------------------------
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))

// Digital state to turn each digit on or off during multiplexing
const uint8_t DIGIT_ON = LOW;
const uint8_t DIGIT_OFF = HIGH;
const uint8_t SEGMENT_ON = (DIGIT_ON == HIGH ? LOW : HIGH);
const uint8_t SEGMENT_OFF = (DIGIT_OFF == HIGH ? LOW : HIGH);

// Finite state machine states
typedef enum state_t { S_INIT, S_IDLE, S_START, S_RUNNING, S_PAUSE, S_END };

// All time duration b=values for setup and storage are held in units of 
// the smallest time interval, in seconds. This is translated into minutes 
// and seconds for the display and countdown.
const uint8_t TIME_MAX_MINUTES = 99;
const uint8_t TIME_INTERVAL = 5; // smallest time interval in seconds
const uint16_t TIME_MAX_SP = ((TIME_MAX_MINUTES * 60) + 59) / TIME_INTERVAL;  // max setting value

// Global Objects --------------------------
MD_KeySwitch SW(SEL_PIN);
MD_REncoder  RE(RE_A_PIN, RE_B_PIN);

// Code ------------------------------------
void updateSegments(uint8_t val)
// update the segments with the value specified
{
	for (uint8_t i=0; i<ARRAY_SIZE(segmentPin); i++)
	{
		digitalWrite(segmentPin[i], (val & 1 ? SEGMENT_ON : SEGMENT_OFF));
		val >>= 1;
	}
}

void displayMessage(char *pMesg, uint16_t duration = 2000)
// Display the message specified for the specified duration in milliseconds
{
  uint32_t startTime = millis();
  char *p;      // temporary string pointer
  uint8_t v;    // LED pattern for display

  while ((millis() - startTime) < duration)
  {
    p = pMesg;
    for (int8_t i = ARRAY_SIZE(digitPin) - 1; i >= 0; i--)
    {
      if (*p != '\0')
      {
        v = pgm_read_byte(alpha + toupper(*p) - 'A');
        p++;
      }
      else
        v = 0;

      // turn all the digits off
      for (uint8_t j = 0; j < ARRAY_SIZE(digitPin); j++)
        digitalWrite(digitPin[j], DIGIT_OFF);

      // SPI transfer of new data
      updateSegments(v); // send value

      // show new data
      digitalWrite(digitPin[i], DIGIT_ON);
    }
  } 
}

void displayTime(uint16_t val, uint8_t decDigit = 0)
{
  uint8_t dig = 0;

  for (uint8_t i=0; i<ARRAY_SIZE(digitPin); i++)
  {
    dig = val % 10;
    val /= 10;

    // turn all the digits off
    for (uint8_t j=0; j<ARRAY_SIZE(digitPin); j++)
      digitalWrite(digitPin[j], DIGIT_OFF);

    // SPI transfer of new data
    updateSegments(pgm_read_byte(digits + dig) + (decDigit == i ? DECIMAL : 0)); // send value

    // show new data
    digitalWrite(digitPin[i], DIGIT_ON);
  }
}

void setup()
{
#if DEBUG
  Serial.begin(57600);
  PRINTS("[Timer]\n");
#endif // DEBUG

  RE.begin();
  SW.begin();

  // initialise hardware
  pinMode(OUTPUT_PIN, OUTPUT);

  for (uint8_t i = 0; i<ARRAY_SIZE(digitPin); i++)
  {
    pinMode(digitPin[i], OUTPUT);
    digitalWrite(digitPin[i], DIGIT_OFF);
  }

  for (uint8_t i = 0; i<ARRAY_SIZE(segmentPin); i++)
  {
    pinMode(segmentPin[i], OUTPUT);
    digitalWrite(segmentPin[i], SEGMENT_OFF);
  }

  displayMessage("helo");
}

void loop()
{
  static state_t state = S_INIT;
  static uint16_t setPoint = 0;
  static int8_t  minutes = 0, seconds = 0;
  static uint32_t timeStart = 0;
  static boolean  inMessage = false;

  if (!inMessage)
    displayTime((minutes*100)+seconds, 2);

  switch (state)
  {
  case S_INIT:
    PRINT("\nS_INIT set:", setPoint);
    {
      uint16_t totalSeconds = setPoint * TIME_INTERVAL;
      seconds = totalSeconds % 60;
      minutes = totalSeconds / 60;

      if (minutes > TIME_MAX_MINUTES) minutes = TIME_MAX_MINUTES;

      state = S_IDLE;
    }
    break;

  case S_IDLE:  // handle user input or just wait
    //PRINTS("\nS_IDLE ");
    // rotary encoder block
    {
      uint8_t x = RE.read();

      switch (x)
      {
      case DIR_CW: PRINTS(" CW");  if (setPoint < TIME_MAX_SP) setPoint++; break;
      case DIR_CCW: PRINTS(" CCW"); if (setPoint > 0) setPoint--; break;
      }
      if (x != DIR_NONE) state = S_INIT;
    }
    // switch block
    if (SW.read() == MD_KeySwitch::KS_PRESS && setPoint != 0)
    {
      PRINTS(" Press");
      state = S_START;
    }
    break;

  case S_START:
    PRINTS("\nS_START");
    timeStart = millis();
    digitalWrite(OUTPUT_PIN, HIGH);
    state = S_RUNNING;
    break;

  case S_RUNNING:
    PRINTS("\nS_RUNNING");
    // Time counter
    if(millis() - timeStart >= 1000)
    {
      timeStart += 1000;
      if (seconds != 0)
        seconds--;
      else
      {
        seconds = 59;
        if (minutes != 0)
          minutes--;
        else
          state = S_END;
      }
    }
    // Check if pausing
    if (SW.read() == MD_KeySwitch::KS_PRESS)
    {
      PRINTS(" Pause");
      state = S_PAUSE;
    }
    break;

  case S_PAUSE:
    PRINTS("\nS_PAUSE");
    inMessage = true;
    displayMessage("pause", 50);
    {
      uint8_t x = SW.read();

      switch (x)
      {
      case MD_KeySwitch::KS_PRESS:
        PRINTS(" Restart");
        timeStart = millis();   // approximate, but we have paused so accurate time is out the window
        inMessage = false;
        state = S_RUNNING;
        break;

      case MD_KeySwitch::KS_LONGPRESS:
        PRINTS(" Stop");
        inMessage = false;
        state = S_END;
        break;
      }
    }
    break;

  case S_END:
    PRINTS("\nS_END");
    digitalWrite(OUTPUT_PIN, LOW);
    displayMessage("end");
    state = S_INIT;
    break;

  default:
    PRINTS("\nDEFAULT");
    state = S_IDLE; // in case we get into trouble!
    break;
  }
}

Does anyone know how to wire/ code the Micro Pro to make this circuit work?

I had a full head of hair when I started, and now I'm down to two strands...

Thanks so much in advance

Yes. Start by putting together a preliminary schematic showing how you plan on interconnecting the parts. Also do the same with your code. Post it and we will help you.

Is this a school project by chance? If so what class level?

1 Like

I should have known superiority would get the better of people.
This is all completely alien to me, but obviously knowing everything, you'd know that. Some people have clearer headspace than others... Anyhow, as I'm an adult here, and assuming you are too; I'm sure we can move long without too much fuss.

Below are the images found on the site I pulled the project from. The site owner is an active member here, as he's helped others complete it in the past. apologies for not posting along with the original post.

relay_timer_block_diagram



relay_timer_state_diagram

Obviously incredibly simple for someone in the know, but it's not something I'm savvy with, really. Finished a button matrix for midi project but that's it.

Each line on the schematic is a wire. Just do one line after another until all are connected. The result should be something like the picture.

Hey, Paul, thanks for your reply. I'm familiar with schematics etc and audio electronics, just not programming and connections where things don't seem all that clear. The penny will drop one day.

My problem, is that I have the pro micro and it calls for a pro mini, but without understanding it, I can't work out where the connections are meant to go for the pro micro.

Pins on the mini go to 12 on the left column as you face the AT chip. Micro goes to 9. Right side of the micro has 10, 16, 15, 14 - A pins then VCC I'm having trouble transposing this to another board. Got the Pro micro pins all pre wired and the cathode based 7 segment display soldered up on perf along with the Digital encoder.

I had a feeling it wouldn't be simple, that's why it's become complicated. Someone will look at this and laugh, but I'm still none the wiser.

Are you also rewriting the software?

No I'm wanting to keep it as simple as swapping the device (Pro Mini to Pro Micro) that functions the code, but having trouble understanding the routing of the pins. If it was just a straight swap, I wouldn't have an issue, but isn't the code corresponding to each pin of the Mini. Meaning it was written to specifiy those pins? I don't see it as directly interchangeable with the Micro?

Well, pins can be either input or output. Some can be analog input, some can be PWM output. Match that part up and most pins will be the same on both boards. Change the code to match the new pin numbers/id.

Look at the setup() part of the code to see what the programs wants.

That's exactly what I'm troubled with!!

  • This is an example of what we need to see from you.

  • You do not need to present this exact style, a hand drawn version will suffice and should include all the components you will be using in this project.

The schematic of what I'm trying to achieve is already there.
I just need to rewire it and make it compatible with the Micro Pro, which is what I'm asking.
The flow chart and all other info is there earlier in the thread.
Along with photo's and a link to the original project page, which is at the end of this post.

-12v power source
-12V to buck converter in
-5v from buck converter out to arduino
-Arduino displaying 7 segment display (minutes and seconds)
-Digital encoder changing the value of time
-Digital encoder momentary switch on/pause/off function
-Relay engaged powering LED's for user given time

I can't give you any more than this, as I'd be guessing. I've had the segment light up in part but not completely. Pins 2&3 are connected to the encoders outer lugs, and the center is connected to ground. connecting the relay as shown on the project page here;
LED Exposure Unit Project
connects the relay regardless of switch function.

Thanks for responding,
J

  • Please read the posting guidelines, post things here, don’t make volunteers search for things.

  • Here is a freebie:

  • No 7 segment resistors on the display, no relay circuit included, need to confirm the code turns on pull-ups on D02, D03 and D08.

I'm really confused... ive posted everything users need to understand what I'm trying to achieve. Everything needed is there... if you read the topic from the off, you'll see there are images that accompany... am i missing something?

Pin 10 - "Relay_Output".... No? The code is in the first post which states pins 2 and 3 are used. Are people reading this from the 1st post. Surely if this is foundation level, you'd all see it instantly; unless you're trying to teach me that I have to do it alone? Which isn't bad.

If I had knowledge like this, I'd write books and tutorials. I have free layouts and information for people to use, and when this is finished, guess what, it'll be going online, for people to use, for free. You won't be helping just me, you'll be helping potentially thousands.

  • Since the start of this thread you have added additional information, this is good.
  • Before any of the volunteers here start to spend time on this, we need to see the complete schematic.
  • As mentioned, the schematic offered is not properly designed and is not complete.
  • We can help produce a proper schematic with your help.

  • What we attempt to do here is teach the correct way of doing things.
    Nobody will support a wrong design, nobody is going to proceed until the schematic is corrected and is all encompassing.

  • Same thing is done here by the many volunteers that dedicate their time for you.

  • Your frustration is obvious from your writings; you will get help if you are willing learn at our pace.

  • Are you able to commit to taking directions, if so we can proceed ?

Hi, Larry. Thanks for your response. Your patience doesn't go unnoticed. I apologize for any negativity or evident frustration. Everything has been delayed with it. Delivery of components and people being somewhat dishonest regarding dispatch times.

I see after reading the frustration that was relayed. Pardon the pun. All pettiness aside, I really appreciate you want to help me with this. I know the schematic isn't complete, but it's all that was provided. Problem is, I don't know where the connections are supposed to go, so drawing a complete new schematic would only set me/the forum/ us back?

Apparently I shouldn't have any issues wiring this as they're all pretty similar.

Thanks again

  • Please show us good images of the project components you have to date.

  • Please give us links to the components you purchased.

  • What electronic background do you have, soldering skills; what have you made along these lines in the past ?

This is what I have so far;







  • The relay was purchased from Ebay, but I can only presume it would be something that's sold widely on AliExpress.

  • The Encoders and Segment Display came from AliExpress.

  • Buck Converter Purchased on Ebay, but again, I've seen these all over AliExpress.

My knowledge of electronics is very much paint by numbers. I can solder, read drawings, Modify and fault find (usually). I've been working with electronics since I was a Kid. Usually not able to the family radio back together, but doing so eventually. I made my first wah pedal when I was 17. Since then I've built valve amps and audio equipment, but never coding or anything else.

  • Please show us a more closeup image of your relay module.