0

Its driving me crazy for some couple of days now and i don't get the answer. I'm busy to setup a irrigation system with a shift register 74HC595 and a 8 channel relay board. I see a lot of sketches where it looks like you can turn a specific relay on but i dont get the clue.

I like to turn on a specific relay based on a button press. Is it possible to turn on a specific relay based on the representing button?

Im using the shiftOut option. The code im using now is :

//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

#include <ESP_SSD1306.h>    // Modification of Adafruit_SSD1306 for ESP8266 compatibility -> https://github.com/somhi/ESP_SSD1306
#include <Adafruit_GFX.h>   // Needs a little change in original Adafruit library (See README.txt file) --> https://github.com/adafruit/Adafruit-GFX-Library
#include <SPI.h>            // For SPI comm (needed for not getting compile error)


#include "settings_base.h"
#include "globals.h"
//#include "functions.h"
//#include "blynk_writes.h"



//Pin connected to ST_CP of 74HC595
const int latchPin = 15; //D8
//Pin connected to SH_CP of 74HC595
const int clockPin = 14; //D5
//Pin connected to DS of 74HC595
const int dataPin = 13; // D7


int totalRelays = 2; // Number of relays
int relayState = 0; // default state = off
int relayArr[] = {12, 16}; // Pins on the Wemos
char vbutton1 = V1; char vbutton2 = V2;
char relayVButtons[] = {V1,V2};
int zone = 0;
int relayVButton = 0;
byte data;
byte dataArray[10];


/*
   SETUP
*/
  BLYNK_WRITE(V1)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 12, 49); // Test led on Wemos pin
    //int bitToSet = 49;

    Serial.println("V1 pressed"); 
  }

  BLYNK_WRITE(V2)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 16, 50); // Test led on Wemos pin
    Serial.println("V2 pressed");
  }

void setup() {

  pinMode(dataPin, OUTPUT);   // All 3 pins are output
  pinMode(clockPin, OUTPUT);  
  pinMode(latchPin, OUTPUT);

  // Do some loop through all the relays and buttons for pinMode
  for (int i=0; i<=totalRelays; i++){
    pinMode(relayArr[i], OUTPUT);
    digitalWrite(relayArr[i], 0);
    pinMode(relayVButtons[i], INPUT);
  }

  // COMMUNICATIONS
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  // CONNECT TO BLYNK
  Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS);
  while (Blynk.connect() == false) {}
  // OVER THE AIR UPDATES
  ArduinoOTA.setHostname(OTA_HOSTNAME);
  ArduinoOTA.begin();

  Serial.println(F("Blynk v" BLYNK_VERSION ": Device started"));
}
/*
   LOOP
*/
void loop() {
  Blynk.run();
  ArduinoOTA.handle();
  timer.run();
}

void relayControl(int onoff, int relayNumber, int bitToSet){
if(onoff == 1) // Virtual button set to on
    {
      digitalWrite(relayNumber, HIGH); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet, HIGH);
      relayState = 1;
    }
    else
    {
      digitalWrite(relayNumber, LOW); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet, LOW);
      relayState = 0;
    }
}
void registerWrite(int whichPin, int whichState) {
// the bits you want to send
  byte bitsToSend = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

Sander


i've change the code. Now the result is the led is turning on but only one led. After pressing led 2 the other one is turning on.. Im not able to turn them off.

//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

#include <ESP_SSD1306.h>    // Modification of Adafruit_SSD1306 for ESP8266 compatibility -> https://github.com/somhi/ESP_SSD1306
#include <Adafruit_GFX.h>   // Needs a little change in original Adafruit library (See README.txt file) --> https://github.com/adafruit/Adafruit-GFX-Library
#include <SPI.h>            // For SPI comm (needed for not getting compile error)


#include "settings_base.h"
#include "globals.h"
//#include "functions.h"
//#include "blynk_writes.h"



//Pin connected to ST_CP of 74HC595
const int latchPin = 15; //D8
//Pin connected to SH_CP of 74HC595
const int clockPin = 14; //D5
//Pin connected to DS of 74HC595
const int dataPin = 13; // D7


int totalRelays = 2; // Number of relays
int relayState = 0; // default state = off
int relayArr[] = {12, 16}; // Pins on the Wemos
char vbutton1 = V1; char vbutton2 = V2;
char relayVButtons[] = {V1,V2};
int zone = 0;
int relayVButton = 0;



/*
   SETUP
*/
  BLYNK_WRITE(V1)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 12, 1); // Test led on Wemos pin
    //int bitToSet = 49;

    Serial.println("V1 pressed"); 
  }

  BLYNK_WRITE(V2)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 16, 4); // Test led on Wemos pin
    Serial.println("V2 pressed");
  }

void setup() {

  pinMode(dataPin, OUTPUT);   // All 3 pins are output
  pinMode(clockPin, OUTPUT);  
  pinMode(latchPin, OUTPUT);

  // Do some loop through all the relays and buttons for pinMode
  for (int i=0; i<=totalRelays; i++){
    pinMode(relayArr[i], OUTPUT);
    digitalWrite(relayArr[i], 0);
    pinMode(relayVButtons[i], INPUT);
  }

  // COMMUNICATIONS
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  // CONNECT TO BLYNK
  Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS);
  while (Blynk.connect() == false) {}
  // OVER THE AIR UPDATES
  ArduinoOTA.setHostname(OTA_HOSTNAME);
  ArduinoOTA.begin();

  Serial.println(F("Blynk v" BLYNK_VERSION ": Device started"));
}
/*
   LOOP
*/
void loop() {
  Blynk.run();
  ArduinoOTA.handle();
  timer.run();
}

void relayControl(int onoff, int relayNumber, int bitToSet){
if(onoff == 1) // Virtual button set to on
    {
      digitalWrite(relayNumber, HIGH); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet);
      Serial.println(bitToSet);
      relayState = 1;
    }
    else
    {
      digitalWrite(relayNumber, LOW); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet);
      relayState = 0;
    }
}
void registerWrite(int whichPin) {
// the bits you want to send
   uint8_t data = 1<<whichPin ; 
  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

Im using the shiftOut option. The code im using now is :

//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

#include <ESP_SSD1306.h>    // Modification of Adafruit_SSD1306 for ESP8266 compatibility -> https://github.com/somhi/ESP_SSD1306
#include <Adafruit_GFX.h>   // Needs a little change in original Adafruit library (See README.txt file) --> https://github.com/adafruit/Adafruit-GFX-Library
#include <SPI.h>            // For SPI comm (needed for not getting compile error)


#include "settings_base.h"
#include "globals.h"
//#include "functions.h"
//#include "blynk_writes.h"



//Pin connected to ST_CP of 74HC595
const int latchPin = 15; //D8
//Pin connected to SH_CP of 74HC595
const int clockPin = 14; //D5
//Pin connected to DS of 74HC595
const int dataPin = 13; // D7


int totalRelays = 2; // Number of relays
int relayState = 0; // default state = off
int relayArr[] = {12, 16}; // Pins on the Wemos
char vbutton1 = V1; char vbutton2 = V2;
char relayVButtons[] = {V1,V2};
int zone = 0;
int relayVButton = 0;
byte data;
byte dataArray[10];


/*
   SETUP
*/
  BLYNK_WRITE(V1)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 12, 49); // Test led on Wemos pin
    //int bitToSet = 49;

    Serial.println("V1 pressed"); 
  }

  BLYNK_WRITE(V2)
  {
    // Get the state of the VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 16, 50); // Test led on Wemos pin
    Serial.println("V2 pressed");
  }

void setup() {

  pinMode(dataPin, OUTPUT);   // All 3 pins are output
  pinMode(clockPin, OUTPUT);  
  pinMode(latchPin, OUTPUT);

  // Do some loop through all the relays and buttons for pinMode
  for (int i=0; i<=totalRelays; i++){
    pinMode(relayArr[i], OUTPUT);
    digitalWrite(relayArr[i], 0);
    pinMode(relayVButtons[i], INPUT);
  }

  // COMMUNICATIONS
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  // CONNECT TO BLYNK
  Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS);
  while (Blynk.connect() == false) {}
  // OVER THE AIR UPDATES
  ArduinoOTA.setHostname(OTA_HOSTNAME);
  ArduinoOTA.begin();

  Serial.println(F("Blynk v" BLYNK_VERSION ": Device started"));
}
/*
   LOOP
*/
void loop() {
  Blynk.run();
  ArduinoOTA.handle();
  timer.run();
}

void relayControl(int onoff, int relayNumber, int bitToSet){
if(onoff == 1) // Virtual button set to on
    {
      digitalWrite(relayNumber, HIGH); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet, HIGH);
      relayState = 1;
    }
    else
    {
      digitalWrite(relayNumber, LOW); // set Wemos pin on HIGH (for test)
      registerWrite(bitToSet, LOW);
      relayState = 0;
    }
}
void registerWrite(int whichPin, int whichState) {
// the bits you want to send
  byte bitsToSend = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}
3
  • What is your current code for writing data to the shift register? Do you use the shiftOut() function, or SPI, or something else? Sep 4, 2018 at 19:48
  • yes im using the shiftOut function. Will post the code im using now. Sep 4, 2018 at 19:58
  • I have updated my earlier answer based on your new code sample. Instead of posting your code changes as answers to your own question, you can edit your question itself, so that your question remains in the question area. Sep 5, 2018 at 1:48

2 Answers 2

1

Working from shiftOut() backwards:

Parameters for shiftOut():

Syntax

shiftOut(dataPin, clockPin, bitOrder, value)

Parameters

dataPin: the pin on which to output each bit (int)

clockPin: the pin to toggle once the dataPin has been set to the correct value (int)

bitOrder: which order to shift out the bits; either MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least Significant Bit First)

value: the data to shift out. (byte)

The important part to notice is the value parameter, which is one 8-bit value, and along with the dataPin and clockPin, sets the 8 registers of the shift register to the 8 bits shifted in. Then, as you have in your code, you pull the latchPin high to latch the register values to the output pins.

Binary values can be represented in C++ as b00001010, where the b prefix notes that the number following is in binary notation, and not "one-thousand ten". If the least-significant bit refers to relay-0 and the most-significant bit refers to relay-7, then to turn on relay-0, you would make sure the last digit (least-signficant) is a one: b00000001. To turn on relays 0 and 1, send 'b00000011', and so on.

In your registerWrite() function, you call shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);, thus bitsToSend should be an 8-bit value, with each bit representing the state of one of the 8 relays on your relay board.

within registerWrite(), bitsToSend is set by the bitWrite() function, which sets the bit number identified by whichPin to the value represented by whichState, which are both parameters passed in from the function call. It's worth noting that bitsToSend is initialized to b00000000 and bitWrite() is called only once, and so there can be at most one bit turned on in the value to write; and thus only one relay active at a time.

registerWrite() is called from within relayControl(), and the whichPin value in registerWrite() comes from the bitToSet value in relayControl(), which in turn is called by the BLYNK_WRITE(V1) or BLYNK_WRITE(V2) functions. In both of those functions, you pass 49 or 50 as the bitToSet parameter, but there are only 8 bits in a byte, so the value passed should be between 0 and 7. You cannot set bit 49 of an 8-bit value.

Probably relayControl() should be called with a value between 0 and 7 for the last parameter.


EDIT Based on New Code

Your latest code shows some changes to the registerWrite() function:

void registerWrite(int whichPin) {

You have removed the parameter which contains the value to write to the particular bit position. Now you have no way to tell the function whether to turn the pin on or off.

// the bits you want to send
   uint8_t data = 1<<whichPin ; 

By shifting a 1 to a particular bit position, you have no way to clear a bit, which is probably why you now cannot get an LED to turn off except by turning on the alternate LED.

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);
}

If you wish to maintain the current state of bits, you will need to declare data as a static variable, which means that it's value is retained even when the function ends and is again available when the function is called again. Further, by using the assignment (=) operator, all you are able to do is overwrite the existing data with the new data, erasing the previous data.

You can use the bitSet() and bitClear() functions to set (make equal to 1) and clear (make equal to zero) individual bits in a byte.

A new registerWrite() function might look like:

void registerWrite(int whichPin, int pinValue) {
  // the bits you want to send
  static uint8_t data; 

  if (pinValue==1) {
    bitSet(data, whichPin);    // Turn on the bit at whichPin
  } else {
    bitClear(data, whichPin);  // Turn off the bit at whichPin
  }

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);
}

You noted you have been frustrated for days working on this, and your code examples have mixed coding conventions, so perhaps you are finding many different code examples and trying various ones until you find something that works. I would encourage you, however, to take it slow and read through each line of code you have and make sure you understand exactly what it does, and be sure you can explain to yourself why each statement or command is there. This will help you to see the path of execution for your code and be able to diagnose bugs and come up with solutions that directly fix the problem, rather than swapping and and out a multitude of snippets from websites and forums.

1
  • Hello Jose, Thank you for clearing out the matter. Yes i've tried a lot of things and didn't get the clue. Think i mixed up to much. Most of the time missing part is closer than you think. The code is clear to me for 90% and need to study the scripting lanquage but also the hardware behind the code. The bitset with the static variable did the trick. Sep 5, 2018 at 4:36
0

You already had SPI in use. You can connect SCK to SRCLK, MOSI to Serial data in, and pick a pin for RCLK. D10 needs to be an output for the device to be SPI master. If it's used already, use that.

Then simply clock in the needed data:

digitalWrite (rclk, LOW);
SPI.transfer (yourData);
digitalWrite (rclk, HIGH); // outputs update on this rising edge

MRCLR connects to +5, OE/ connects to Gnd.

SPI.begin(); 

in setup() turns on the defaults of 4 MHz clock rate, MSBFIRST, and SPI Mode 0, that's all you need.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.