сдвиговый регистр 74HC595 включает определенный вывод

Это сводит меня с ума уже несколько дней, и я не могу найти ответа. Я занят настройкой системы орошения с использованием сдвигового регистра 74HC595 и 8-канальной релейной платы. Я вижу много эскизов, где кажется, что можно включить определенное реле, но я не понимаю, в чем подсказка.

Мне нравится включать определенное реле нажатием кнопки. Можно ли включить определенное реле на основе соответствующей кнопки?

Я использую опцию shiftOut. Код, который я использую сейчас:

//#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);

}

Сандер


Я изменил код. Теперь результат - светодиод включается, но только один. После нажатия светодиода 2 включается другой.. Я не могу их отключить.

//#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>    // Модификация Adafruit_SSD1306 для совместимости с ESP8266 -> https://github.com/somhi/ESP_SSD1306
#include <Adafruit_GFX.h>   // Необходимо небольшое изменение в оригинальной библиотеке Adafruit (см. файл README.txt) --> https://github.com/adafruit/Adafruit-GFX-Library
#include <SPI.h>            // Для связи SPI (необходимо, чтобы не возникало ошибок компиляции)


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



//Вывод подключен к ST_CP 74HC595
const int latchPin = 15; //D8
//Вывод подключен к SH_CP 74HC595
const int clockPin = 14; //D5
//Вывод подключен к DS 74HC595
const int dataPin = 13; // D7


int totalRelays = 2; // Количество реле
int relayState = 0; // состояние по умолчанию = выключено
int relayArr[] = {12, 16}; // Контакты на Wemos
char vbutton1 = V1; char vbutton2 = V2;
char relayVButtons[] = {V1,V2};
int zone = 0;
int relayVButton = 0;



/*
   SETUP
*/
  BLYNK_WRITE(V1)
  {
    // Получить состояние VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 12, 1); // Тестовый светодиод на выводе Wemos
    //int bitToSet = 49;

    Serial.println("V1 pressed"); 
  }

  BLYNK_WRITE(V2)
  {
    // Получить состояние VButton
    relayVButton = param.asInt();
    relayControl(relayVButton, 16, 4); // Тестовый светодиод на выводе Wemos
    Serial.println("V2 pressed");
  }

void setup() {

  pinMode(dataPin, OUTPUT);   // Все 3 контакта являются выходными
  pinMode(clockPin, OUTPUT);  
  pinMode(latchPin, OUTPUT);

  // Выполняем цикл по всем реле и кнопкам для pinMode
  for (int i=0; i<=totalRelays; i++){
    pinMode(relayArr[i], OUTPUT);
    digitalWrite(relayArr[i], 0);
    pinMode(relayVButtons[i], INPUT);
  }

  // КОММУНИКАЦИИ
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  // ПОДКЛЮЧИТЬСЯ К BLYNK
  Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS);
  while (Blynk.connect() == false) {}
  // ОБНОВЛЕНИЯ ПО ВОЗДУХУ
  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) // Виртуальная кнопка включена
    {
      digitalWrite(relayNumber, HIGH); // устанавливаем вывод Wemos на HIGH (для теста)
      registerWrite(bitToSet);
      Serial.println(bitToSet);
      relayState = 1;
    }
    else
    {
      digitalWrite(relayNumber, LOW); // устанавливаем вывод Wemos на HIGH (для теста)
      registerWrite(bitToSet);
      relayState = 0;
    }
}
void registerWrite(int whichPin) {
// биты, которые вы хотите отправить
   uint8_t data = 1<<whichPin ; 
  // отключаем выход, чтобы контакты не загорались
  // пока вы сдвигаете биты:
  digitalWrite(latchPin, LOW);

  // сдвигаем биты наружу:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // включаем выход, чтобы светодиоды загорелись:
  digitalWrite(latchPin, HIGH);

}

Я использую опцию shiftOut. Код, который я сейчас использую:

//#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);

}

, 👍0

Обсуждение

Какой у вас текущий код для записи данных в сдвиговый регистр? Вы используете функцию shiftOut(), или SPI, или что-то еще?, @jose can u c

да, я использую функцию shiftOut. Опубликую код, который я сейчас использую., @Sander Rozemuller

Я обновил свой предыдущий ответ на основе вашего нового примера кода. Вместо того, чтобы публиковать изменения кода как ответы на ваш собственный вопрос, вы можете отредактировать сам свой вопрос, чтобы он оставался в области вопросов., @jose can u c


2 ответа


1

Работаем от shiftOut() в обратном направлении:

Параметры для shiftOut():

Синтаксис

shiftOut(dataPin, clockPin, bitOrder, значение)

Параметры

dataPin: контакт, на котором выводится каждый бит (int)

clockPin: контакт для переключения после установки dataPin в положение правильное значение (целое)

bitOrder: в каком порядке следует сдвигать биты; MSBFIRST или LSBFIRST. (Самый значимый бит первым, или наименее значимый бит первым) Первый)

value: данные для сдвига. (байт)

Важная часть, на которую следует обратить внимание, — это параметр value, который представляет собой одно 8-битное значение и вместе с dataPin и clockPin устанавливает 8 регистров регистра сдвига на 8 сдвинутых бит. Затем, как и в вашем коде, вы устанавливаете latchPin на высокий уровень, чтобы зафиксировать значения регистра на выходных контактах.

Двоичные значения могут быть представлены в C++ как b00001010, где префикс b указывает, что следующее число указано в двоичной системе счисления, а не «одна тысяча десять». Если младший бит относится к реле-0, а старший бит относится к реле-7, то для включения реле-0 необходимо убедиться, что последняя цифра (младший бит) — единица: b00000001. Чтобы включить реле 0 и 1, отправьте 'b00000011' и т. д.

В вашей функции registerWrite() вы вызываете shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);, таким образом, bitsToSend должно быть 8-битным значением, где каждый бит представляет состояние одного из 8 реле на вашей релейной плате.

внутри registerWrite(), bitsToSend устанавливается функцией bitWrite(), которая устанавливает номер бита, идентифицированный whichPin, в значение, представленное whichState, которые являются параметрами, переданными из вызова функции. Стоит отметить, что bitsToSend инициализируется значением b00000000, а bitWrite() вызывается только один раз, и поэтому может быть включено не более одного бита в значении для записи; и, таким образом, одновременно может быть активным только одно реле.

registerWrite() вызывается из relayControl(), а значение whichPin в registerWrite() получается из значения bitToSet в relayControl(), которое в свою очередь вызывается функциями BLYNK_WRITE(V1) или BLYNK_WRITE(V2). В обеих этих функциях вы передаете 49 или 50 в качестве параметра bitToSet, но в байте всего 8 бит, поэтому переданное значение должно быть между 0 и 7. Вы не можете установить бит 49 8-битного значения.

Вероятно, relayControl() следует вызывать со значением от 0 до 7 для последнего параметра.


РЕДАКТИРОВАТЬ на основе нового кода

Ваш последний код показывает некоторые изменения в функции registerWrite():

void registerWrite(int whichPin) {

Вы удалили параметр, содержащий значение для записи в определенную позицию бита. Теперь у вас нет возможности указать функции, включать или выключать вывод.

// биты, которые вы хотите отправить
   uint8_t data = 1<<whichPin ; 

Сдвинув 1 на определенную позицию бита, вы не сможете очистить бит, и, вероятно, поэтому теперь вы не можете заставить светодиод выключиться, кроме как включив альтернативный светодиод.

  // отключаем выход, чтобы контакты не загорались
  // пока вы сдвигаете биты:
  digitalWrite(latchPin, LOW);

  // сдвигаем биты наружу:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // включаем выход, чтобы светодиоды загорелись:
  digitalWrite(latchPin, HIGH);
}

Если вы хотите сохранить текущее состояние битов, вам нужно будет объявить data как переменную static, что означает, что ее значение сохраняется даже после завершения функции и снова доступно при повторном вызове функции. Кроме того, используя оператор присваивания (=), все, что вы можете сделать, это перезаписать существующие данные новыми данными, стирая предыдущие данные.

Вы можете использовать функции bitSet() и bitClear() для установки (сделания равными 1) и очистки (сделания равными нулю) отдельных битов в байте.

Новая функция registerWrite() может выглядеть так:

void registerWrite(int whichPin, int pinValue) {
  // биты, которые вы хотите отправить
  static uint8_t data; 

  if (pinValue==1) {
    bitSet(data, whichPin);    // Включаем бит на whichPin
  } else {
    bitClear(data, whichPin);  // Отключаем бит на whichPin
  }

  // отключаем выход, чтобы контакты не загорались
  // пока вы сдвигаете биты:
  digitalWrite(latchPin, LOW);

  // сдвигаем биты наружу:
  shiftOut(dataPin, clockPin, MSBFIRST, data);

    // включаем выход, чтобы светодиоды загорелись:
  digitalWrite(latchPin, HIGH);
}

Вы отметили, что были расстроены в течение нескольких дней, работая над этим, и ваши примеры кода имеют смешанные соглашения о кодировании, поэтому, возможно, вы находите много разных примеров кода и пробуете разные, пока не найдете то, что работает. Однако я бы посоветовал вам не торопиться и прочитать каждую строку кода, чтобы убедиться, что вы точно понимаете, что он делает, и убедиться, что вы можете объяснить себе, почему каждый оператор или команда там. Это поможет вам увидеть путь выполнения для вашего кода и быть в состоянии диагностировать ошибки и предлагать решения, которые напрямую устраняют проблему, а не менять и выдавать множество фрагментов с веб-сайтов и форумов.

,

Привет, Хосе, Спасибо, что прояснили ситуацию. Да, я пробовал много вещей и не получил подсказки. Думаю, я слишком много перепутал. В большинстве случаев недостающая часть ближе, чем вы думаете. Код мне понятен на 90%, и мне нужно изучить язык сценариев, а также аппаратное обеспечение, стоящее за кодом. Битовый набор со статической переменной справился с задачей., @Sander Rozemuller


0

У вас уже был SPI в использовании. Вы можете подключить SCK к SRCLK, MOSI к последовательному входу данных и выбрать вывод для RCLK. D10 должен быть выходом для устройства, чтобы быть ведущим SPI. Если он уже используется, используйте его.

Затем просто введите необходимые данные:

digitalWrite (rclk, LOW);
SPI.transfer (yourData);
digitalWrite (rclk, HIGH); // выводит обновление по этому переднему фронту

MRCLR подключается к +5, OE/ подключается к Gnd.

SPI.begin(); 

в setup() включает значения по умолчанию тактовой частоты 4 МГц, MSBFIRST и SPI Mode 0, это все, что вам нужно.

,