Возникли проблемы с запуском двух 74HC595 в качестве одного 16-битного сдвигового регистра.

Я использую два из них вместе, чтобы создать один 16-битный регистр, который даст мне доступ к 16 выходам. Я заставил их работать, но не совсем так, как я себе представлял. Код написан для зарядного/разрядного устройства 18650. Первые 6 бит (0-5) регистра сдвига будут подключены к 6 NPN, которые будут включать или выключать каждый из последовательно соединенных tp4056. Следующие 6 бит (5-11) будут подключены к 6 различным нагрузкам постоянного тока. Пользователь выбирает, хочет ли он заряжать или разряжать свою ячейку, и в зависимости от режима включается зарядное устройство или приемник тока этой конкретной ячейки (но оба не одновременно). На самом деле мне нужно сначала сдвинуть 6 бит вручную, выбрав режим, а затем нажать «Выбор» для всех 6 ячеек в регистре, чтобы он что-то показал, и даже после этого он случайно пропускает биты. Кстати, последние 4 бита (12-15) также будут использоваться в конечном продукте. Для эксперимента я подключил светодиоды ко всем выходам.

#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include <Encoder.h>


// инициализация
LiquidCrystal_I2C lcd(0x27, 20, 4);
Encoder encoder(2, 3);

// программные константы
const int numOfCells = 6;
const int analogInput[numOfCells] = {A0, A1, A2, A3, A6, A7};
const float arduinoPowerLine = 4.80;
const long interval = 60000; //60 секунд
const char* functions [2] = {"CHARGE   ", "DISCHARGE"}; //массив выбора режима
const int dataPin  = 12;//DS - пин 9
const int latchPin = 11;//ST_CP --pin12
const int clockPin = 8;//SH_CP --pin11

//Настройка энкодера
long oldPostion = -999;
long newPostion = 0;
long prevPostion;

//создание массивов батарей и установка их флагов по умолчанию
double batteryVoltage[numOfCells];
bool noBatteryFlag[numOfCells] = {LOW, LOW, LOW, LOW, LOW, LOW}; 
float minimum = 3.00; // Напряжение отсечки
float capacity[numOfCells];
 
//переменные режима
int modeState[numOfCells];
int confirmedModeState[numOfCells];

//настройка кнопки
int inputPin = 5;
int inputState;
int lastInputState = LOW;
int inputFlag = LOW;

// таймер отката
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

//ЖК-переменные
int currentCell = -1;

//Таймеры ячеек
unsigned long prevMillis[numOfCells];
int minute[numOfCells];
unsigned long currentMillis;

//переменные резистора переключения
word outputs = 0B0000000000000000; 


void updateShiftRegister(word bits){//берет биты из функции resolvemode и установит их соответствующим образом
  byte resisterOne  = lowByte(outputs);//самый правый байт
  byte resisterTwo = highByte(outputs);//самый левый байт
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, resisterOne); 
  digitalWrite(latchPin, HIGH);
}
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  pinMode(inputPin, INPUT_PULLUP);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);  
  pinMode(clockPin, OUTPUT);
  updateShiftRegister(outputs);//Сбрасывает все выходы сдвиговых резисторов в LOW
}
void BatteryVoltage(){//чтение каждой ячейки и преобразование значения adc в напряжение
  for (int i = 0; i < numOfCells; i++){
    int reading = analogRead(analogInput[i]);
    batteryVoltage[i] = (reading * arduinoPowerLine) / 1023;
    // помечаем материал
    if (batteryVoltage[i] <= 0.50) {//проверка, вставлена ли батарея в держатель
    noBatteryFlag[i] = HIGH;
    }else{
      noBatteryFlag[i] = LOW;
    }
  }
}
void ButtonDebounce(){//проверка состояния ввода и пометки кнопки
  int reading = digitalRead(inputPin);
  if (reading != lastInputState){
    lastInputState = millis();
  }
  if ((millis() - lastInputState > debounceDelay)){//кнопка устранения дребезга
    if (reading != inputState){
      inputState = reading;
      if (inputState == HIGH) {
        inputFlag = HIGH;
      }
    }
  }
  lastInputState = reading;
}
void ResolveFlags(){
   if (inputFlag == HIGH){ // увеличение текущего экрана
       if (currentCell == numOfCells - 1){ //если счетчик на пределе, он возвращается к началу
        currentCell = 0;
      } else {
        currentCell++;
      }
      confirmedModeState[currentCell] = modeState[currentCell]; //режим, выбранный в сохраненном
      lcd.clear();//очищает лабораторию каждый раз, когда нажимается кнопка
        inputFlag = LOW; 
  }
}
void BatteryTimeKeeper(){//отслеживание времени работы от батареи во время ее разрядки
for (int i = 0; i < numOfCells; i++){
  if (currentMillis - prevMillis[i] > interval){
    if (noBatteryFlag[i] == LOW){//если батарея находится в держателе
      if (batteryVoltage[i] > minimum){//и если оно больше 3 В, его можно разряжать
   minute[i]++; 
   prevMillis[i] = currentMillis;
  }
  if (batteryVoltage[i] <= minimum){
    capacity[i] = (minute[i] / 60) * 500; //общее время, деленное на 500 мА (постоянный ток нагрузки)
    minute[i] = 0;
    }
  }
}
    if (noBatteryFlag[i] == HIGH){//если батарея удалена, ее таймер сбрасывается обратно на 0
      minute[i] = 0;
    }
  }
}
void EncoderFunctionNavigator(){//отслеживает кодировщик
  newPostion = encoder.read();
  if (newPostion != oldPostion){
    oldPostion = newPostion;
  }
  if(prevPostion < newPostion){
    modeState[currentCell]++;
  } else if(prevPostion > newPostion){
    modeState[currentCell]--;
  }
  if (modeState[currentCell] == 2){ // переворачивает режим выделения
    modeState[currentCell] = 0;
  } else if (modeState[currentCell] < 0){
    modeState[currentCell] = 1;
  }
}
void ResolveMode(){//включает или выключает выход сдвигового резистора в зависимости от выбранного режима
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}
void PrintScreen(){//распечатка всей информации на ЖК-дисплее
  lcd.home();
  int cellCounter = currentCell + 1; //это здесь, потому что у меня OCD
  char buffer[25];
  sprintf(buffer, "Cell#:%d    %s", cellCounter, functions[modeState[currentCell]]);
  lcd.print(buffer);
  lcd.setCursor(0, 1);
  lcd.print("VOL:");
  lcd.setCursor(4, 1);
  lcd.print(batteryVoltage[currentCell]);
  lcd.setCursor(0, 2);
  lcd.print("Cap:");
  lcd.setCursor(4, 2);
  lcd.print(capacity[currentCell]);
}
void loop() {
 currentMillis = millis(); //основная переменная currentmillis
 BatteryVoltage();
 BatteryTimeKeeper();
 ButtonDebounce();
 EncoderFunctionNavigator();
 ResolveFlags();
 PrintScreen(); 
 ResolveMode();
 prevPostion = newPostion; // записывает последнюю позицию энкодера
}

, 👍1

Обсуждение

Его регистр, а не резистор, @chrisl

Пробовали ли вы простой тестовый скетч только со сдвиговыми регистрами tl test, если они работают как положено? Вы проверили, являются ли данные, которые вы хотите перенести, именно тем, что вы ожидаете (путем предварительной печати по серийному номеру)? И почему вы обновляете сдвиговые регистры для каждого бита, установленного в ResolveMode()? Я бы сначала установил каждый бит в данных, которые необходимо установить, а затем в конце обновил регистры сдвига только один раз со всеми новыми данными сразу, @chrisl

И что вы подразумеваете под «пропущенными битами случайным образом»? Пожалуйста, объясните точно, чего вы ожидали и что произошло на самом деле, @chrisl

регистрация* мой плохой. Да, я попробовал простой скетч, и я могу переключать все разные биты, и под отсутствующими битами я имею в виду, что один светодиод перестает работать посередине., @Faraz Ahmed

Это хорошая идея, я попробую и сообщу о результатах. Спасибо за ваш ответ, @Faraz Ahmed

@chrisl да, ваше решение сработало. С вашим решением и перемещением resolveMode() все заработало., @Faraz Ahmed


1 ответ


Лучший ответ:

1

Чтобы поместить комментарии в ответ:

Вы управляете регистрами сдвига в этой функции

void ResolveMode(){//включает или выключает выход сдвигового резистора в зависимости от выбранного режима
  for (int i = 0; i < numOfCells; i++){
    if (confirmedModeState[i] == 0){
      bitWrite(outputs, i, HIGH) && bitWrite(outputs, i+6, LOW);
    } else if (confirmedModeState[i] == 1){
      bitWrite(outputs, i, LOW) && bitWrite(outputs, i+6, HIGH);
    }
    updateShiftRegister(outputs);
  }
}

Поскольку вызов updateShiftRegister() находится внутри цикла for, вы обновляете регистры сдвига для каждого установленного вами бита. Я думаю, это тот момент, когда вы получаете свое странное поведение. Вам не нужно обновлять каждый бит. Вместо этого измените все необходимые биты внутри переменной outputs, а затем в конце ResolveMode() вы сможете сразу обновить регистры всеми данными.

Поэтому просто переместите updateShiftRegister(outputs); на одну строку вниз за пределы цикла for.

,