Микросхема 74HC595 с 7-сегментным дисплеем постоянно отображает либо все единицы, либо все нули
Я сделал простую схему с Arduino Nano ESP32, к которой я подключил 8-битный чип сдвигового регистра 74HC595, а также 7-сегментный дисплей с резистором 100 Ом на общем проводе (катоде) для отображения состояния сдвигового регистра.
Ожидаемое поведение
Семисегментный дисплей показывает двоичный счет от 0 до 255.
Наблюдаемое поведение
Семисегментный дисплей непрерывно показывает 8.
, что по сути означает, что состояние сдвигового регистра равно 0b11111111
.
Когда я использую 5 В (VBUS) вместо 3,3 В для VCC микросхемы, сдвиговый регистр показывает все нули вместо всех единиц.
Попытки отладки
Я проверил все входные кабели с помощью мультиметра на предмет наличия сломанных соединений, и, похоже, все в порядке. Я также несколько раз менял сам чип, результаты были такими же. Я пробовал заменить резистор на общем выводе семисегментного дисплея на что-то около 1000 Ом, а затем обратно. Результаты были такими же. Я также использовал разные схемы для тестирования, результаты были такими же.
Ресурсы
Я сделал текущую версию своей схемы и кода как проект WOKWI (эмулятор): https://wokwi.com/projects/396140725340271617 [УСТАРЕЛО (также не обновляется по какой-то причине)]
Он имеет примерно те же самые соединения, что и моя макетная плата.
Вот скриншот схемы:
И код, на случай, если Вокви прекратит свое существование в будущем..
//************************************************************//
// Имя: shiftOutCode, Привет, мир
// Автор: Карлин Мо, Том Иго, Дэвид А. Меллис
// Дата: 25 октября 2006 г.
// Изменено: 23 марта 2010 г.
// Версия: 2.0
// Примечания: Код для использования сдвигового регистра 74HC595 //
// : для счета от 0 до 255
//***************************************************************
//Вывод подключен к ST_CP 74HC595
int latchPin = 8;
//Вывод подключен к SH_CP 74HC595
int clockPin = 12;
////Контакт подключен к DS 74HC595
int dataPin = 11;
void setup() {
//установить выводы на выход, чтобы можно было управлять сдвиговым регистром
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
// счет от 0 до 255 ankKomd отображает число
// на светодиодах
for (int numberToDisplay = 0; numberToDisplay < 256; numberToDisplay++) {
// установите latchPin на низкий уровень, чтобы
// светодиоды не меняются во время отправки битов:
digitalWrite(latchPin, LOW);
// сдвигаем биты:
shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
//установите защелку на высокий уровень, чтобы светодиоды загорелись:
digitalWrite(latchPin, HIGH);
// пауза перед следующим значением:
delay(500);
}
}
@Niko, 👍5
Обсуждение3 ответа
Лучший ответ:
Не могу поверить, что для тактирования данных требуется задержка в одну секунду. У меня есть циклы, которые тактируют биты с использованием SPI без задержек, что даже быстрее, чем shiftOut. См. Использование выходного сдвигового регистра 74HC595 в качестве расширителя портов.
У вас есть какая-то другая проблема.
Возможно, дело в том, что все работает отлично, но число меняется так быстро, что создается впечатление, будто включены все сегменты.
Плюс, вам действительно не следует проводить тестирование без токоограничивающих резисторов на каждом сегменте. Один общий резистор будет вести себя странно в зависимости от того, сколько сегментов включено одновременно.
Привет, спасибо за ответ. Я провел еще несколько экспериментов и оказалось, что ты прав, мне не нужна задержка в одну секунду для тактирования данных, но мне нужна НЕКОТОРАЯ задержка, чтобы увидеть, как загораются сегменты. Так что да, я думаю, что цифры менялись так быстро, что я не мог видеть, как они меняются., @Niko
Что касается резисторов, у меня, к сожалению, нет достаточного количества резисторов, чтобы сделать это прямо сейчас, и я немного почитал и пришел к выводу, что единственный побочный эффект наличия одного общего резистора — это более тусклый дисплей, когда включено больше сегментов. Пока что все должно быть в порядке, но как только у меня появятся лучшие ресурсы, я обязательно поставлю резисторы для каждого сегмента., @Niko
Я никогда не ожидал этого, но оказалось, что мой MCU был «слишком быстрым» (я полагаю), и поэтому ничего не отображалось. Вот код до исправления:
digitalWrite(latchPin, LOW); // Защелкиваем данные
// без задержки
digitalWrite(latchPin, HIGH); // Снять фиксацию для следующих данных
а это код после:
digitalWrite(latchPin, LOW); // Защелкиваем данные
delay(1000); // Короткая задержка для видимости (настройте по мере необходимости)
digitalWrite(latchPin, HIGH); // Снять фиксацию для следующих данных
Я все еще экспериментирую со сдвиговым регистром, поэтому я отредактирую этот ответ, если появится что-то новое или если мой ответ будет полностью неверным.
ПРАВКА: Мне не нужна была задержка в одну секунду между тактовыми импульсами, мне, по-видимому, просто нужна была некоторая задержка, чтобы увидеть изменение семисегментных дисплеев. (спасибо @NickGammon)
РЕДАКТИРОВАНИЕ: Вот полный код, если кому-то он нужен. Он отображает спиральную анимацию на 7-сегментном дисплее.
uint8_t latchPin = D8;
uint8_t clockPin = D12;
uint8_t dataPin = D11;
const byte segments[10] = { // Таблица поиска для цифровых шаблонов (общий катод)
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111100, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
void setup() {
// Установить управляющие контакты как выходы
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
Serial.begin(115200); // Запуск последовательной связи для отладки
Serial.println("Starting...");
displaySegments(0x00000000); // сбрасывается при запуске, не нужен, просто выглядит лучше ig
delay(1000);
}
void spiralAnimation() {
// Проходим по каждому сегменту в спиральном порядке
for (int i = 0; i < 7 - 1; i++) { // 7 — количество сегментов, игнорируем G, поэтому выглядит лучше
shiftOut(dataPin, clockPin, MSBFIRST, 0b00000001 << i);
digitalWrite(latchPin, LOW);
delayMicroseconds(1000);
digitalWrite(latchPin, HIGH);
delay(80); // Настройте задержку для скорости анимации
}
}
void loop() {
// Пройти по каждому шаблону цифр (изменить для конкретного дисплея)
// для (int i = 0; i < 10; i++) {
// shiftOut(dataPin, clockPin, MSBFIRST, segments[i]);
// digitalWrite(latchPin, LOW); // Зафиксировать данные
// delay(100); // Короткая задержка для видимости (настройте по мере необходимости)
// digitalWrite(latchPin, HIGH); // Снять фиксацию для следующих данных
// Serial.print("Отображение: ");
// Serial.println(i);
// }
spiralAnimation();
}
void displaySegments(byte pattern) {
shiftOut(dataPin, clockPin, MSBFIRST, pattern);
digitalWrite(latchPin, LOW);
delayMicroseconds(1000); // нет необходимости редактировать это
digitalWrite(latchPin, HIGH);
}
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) // на всякий случай
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}
На данный момент, после быстрого тестирования, все работает так, как и ожидалось., @Niko
Во-первых, код в вопросе не соответствует коду в «предполагаемом решении». Функция ShiftOut довольно медленная, поэтому она может работать как дополнительная задержка при размещении между настройками защелки. Так что рассматриваемый код выглядит надежным в этом смысле, имхо.
Далее, сомнительно требовать задержку в целую миллисекунду даже во втором случае. Чип 74hc595 должен иметь возможность обрабатывать сигнал быстрее 10 МГц даже при питании 3v3. И функция digitalWrite также довольно медленная (как и весь дополнительный слой совместимости Arduino), так что я не вижу здесь никакой проблемы.
Скорее всего, это происходит из-за паразитной емкости. Поэтому линия защелки (слишком длинная?) не успевает разрядиться даже на скорости в несколько мегабайт. Тогда сдвиговый регистр никогда не увидит низкий уровень напряжения, за исключением запуска. Правильные соединения (пайка проводов или, по крайней мере, использование только коротких перемычек) должны решить проблему.
- Как часто надо опрашивать 74HC165, если мы хотим обнаруживать нажатия кнопок?
- esp32, platformio A fatal error occurred: Packet content transfer stopped (received 8 bytes) *** [upload] Error 2
- Как выбрать альтернативные контакты I2C на ESP32?
- Драйверы для чипа последовательного порта CH9102X
- Как преобразовать форматированный оператор print в строковую переменную?
- ESP32 - "Детектор Браунаута был активирован" при запуске Wi-Fi
- Питание esp32cam от аккумулятора
- Контакты RX и TX на esp32
Подумайте о том, чтобы скопировать изображение схемы и код в ваш вопрос выше. Люди здесь не любят ссылки за пределами сайта, поскольку они могут со временем сломаться. Идея в том, чтобы сохранить эти вопросы/ответы для других, чтобы они могли прочитать их даже через много лет., @st2000
Если вам нужны резисторы ограничения тока светодиода, вам понадобится один для каждого сегмента. А не один для всего дисплея. Кстати, на схеме нет резисторов. Вы забыли их разместить?, @st2000
Да, извините. К сожалению, у меня недостаточно резисторов, чтобы разместить по одному на каждый сегмент, поэтому пока я разместил один для общего. Я отредактирую свой вопрос, включив в него скриншот, спасибо., @Niko
Вы не очень ясно дали понять, что вы пытаетесь сделать. Если вы пытаетесь использовать 7-сегментный дисплей для представления 8-битных двоичных чисел (от 0 до 255 dec.), то вам нужно показать сопоставление между каждым сегментом и положением этого сегмента между старшим и младшим двоичными битами. Например, это может быть десятичная точка = старший бит (bit7), среднее тире (сегмент G) = бит 6 и т. д., @6v6gt
Строка, устанавливающая защелку на низкий уровень, закомментирована. Это само по себе нарушает код, так как 74595 защелкивается только на переднем фронте., @Matt
Кстати, вот почему в спецификации 595 этот вывод называется «тактовый регистр хранения», а не «защелка»., @Matt
@Matt, ну конечно. Извините. Я делал это для отладки. Попробую еще раз без него., @Niko
@Мэтт, такое же поведение., @Niko
Это потому, что у вас еще больше проблем. Подача 3v3 для регистра также совершенно неправильна, так как микроконтроллер выдает сигналы с высоким напряжением 5 В. Несмотря на то, что земля общая для обоих чипов, даташит допускает входные напряжения только до vdd+0.5 AFAIR., @Matt
@Matt, хочу напомнить, что я использую Arduino Nano ESP32, рабочее напряжение которого составляет 3,3 В. Что вы имеете в виду, когда говорите, что «МК выдает сигналы высокого уровня 5 В»?, @Niko
На вашей фотографии по-прежнему изображен обычный нано., @Matt
Видимо, распиновка неверная. D12 не 12 для esp32 и т.д., @Matt
@Matt, причина, по которой на картинке показан обычный Nano, заключается в том, что в эмуляторе нет Nano ESP32. Я включил во вступление, что это Arduino Nano ESP32. В любом случае, в своем коде я пробовал использовать
D12
вместо12
,D11
вместо11
и так далее. Разницы в поведении нет., @Niko