Мультиплексирование трех ламп VFD — почему сегменты и синхронизация отображения неверны?

Я использую Arduino Nano, микросхему UNL2803 и три транзистора 2N3904 для управления тремя семисегментными вакуумными люминесцентными лампами (IV-6) в мультиплексной конфигурации. UNL2803 используется для управления сегментами: когда на вывод Arduino подается низкий уровень, 25 В отправляется в соответствующий сегмент. Транзисторы 2N3904 используются для управления каждой из цифр: когда на выводе Arduino высокий уровень, на сетку цифры подается 25 В, тем самым активируя цифру.

Проблема: трубки показывают неправильные сегменты, а дисплеи не активируются с правильным временем. Я проверил соединение каждого сегмента, чтобы убедиться, что оно подключено к правильному сегменту. Замедляя временной интервал между цифрами, я вижу, что вторая и третья цифры (десятки и единицы) отображаются последовательно с правильным интервалом, но первая цифра (сотни) появляется со второй цифрой и остается на в два раза больше интервала времени. Также кажется, что некоторые цифры пытаются отобразить более одного числа (последовательно) при активации.

Код:

// Назначение контактов для сегментов
const int SEG_A = 2;
const int SEG_B = 3;
const int SEG_C = 4;
const int SEG_D = 6;
const int SEG_E = 5;
const int SEG_F = 7;
const int SEG_G = 8;

// Назначение контактов для цифр
const int DIG1 = 9;
const int DIG2 = 10;
const int DIG3 = 11;

int digit = 1;
int dig_number = 0;
unsigned int number = 321;    

void setup() {

  Serial.begin(9600);
  
  // Установить выводы сегмента в качестве выходов
  pinMode(SEG_A, OUTPUT);
  pinMode(SEG_B, OUTPUT);
  pinMode(SEG_C, OUTPUT);
  pinMode(SEG_D, OUTPUT);
  pinMode(SEG_E, OUTPUT);
  pinMode(SEG_F, OUTPUT);
  pinMode(SEG_G, OUTPUT);
  
  // Установить цифровые контакты в качестве выходов
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  pinMode(DIG3, OUTPUT);

  // Отключаем цифры
  digitalWrite(DIG1, LOW);
  digitalWrite(DIG2, LOW);
  digitalWrite(DIG3, LOW);
}

void loop() {
      if (digit == 1) {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        digitalWrite(DIG3, LOW);
        dig_number = number / 100;
        if (number < 100) {      // отключить цифру, если она не используется
          dig_number == 99;      // запускает 'по умолчанию' в switch/case
          display_number(dig_number); 
        } else {
          display_number(dig_number);
        }
        digit = 2;
        Serial.println("The first digit is: ");
        Serial.print(dig_number);
        delay (250);
      }  

      if (digit == 2) {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        digitalWrite(DIG3, LOW);
        dig_number = (number / 10) % 10;
        if (dig_number == 0 && number < 10) {       // чтобы отключить цифру, если она не используется
          dig_number == 99;        // запускает 'по умолчанию' в switch/case
          display_number(dig_number);          
        } else {
          display_number(dig_number);
        }
        digit = 3;
        Serial.println("The second digit is: ");
        Serial.print(dig_number);
        delay (250);
      }

      if (digit == 3) {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, LOW);
        digitalWrite(DIG3, HIGH);
        dig_number = number % 10;    
        display_number(dig_number);
        digit = 1;
        Serial.println("The third digit is: ");
        Serial.print(dig_number);
        delay (250);
      }
}

void display_number(int dig_number) {

    switch (dig_number) {
        case 0:
        digitalWrite(SEG_A, LOW);   
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 1:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 2:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 3:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 4:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 5:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 6:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 7:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 8:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 9:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
    
    default:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
    }
}

Схема:

До меня доходили слухи, что использование delay() вместо millis() для мультиплексирования может быть проблематичным. Это то, что здесь происходит?

Заранее благодарим за рассмотрение этой проблемы!

, 👍1

Обсуждение

То, как вы подключили его, когда вы включаете цифру, вам нужно отправить НИЗКИЙ уровень на соответствующий контакт и ВЫСОКИЙ уровень на два других контакта с двумя цифрами. У вас это перевернуто. Я предполагаю, что провод, соединяющий R9, R10 и R11, идет до 25 вольт. Базовые резисторы на транзисторах не помешали бы., @6v6gt

Спасибо. Мое понимание использования транзистора 2N3904 в качестве переключателя заключается в том, что на базе необходим высокий контакт, чтобы «открыть» переключатель и позволить току течь от коллектора к эмиттеру. Пожалуйста, помогите мне понять необходимость низкого штифта на базе, чтобы это работало. Я новичок в транзисторах. :), @Thomas Burns

Это правильно, но в вашем случае включение транзисторов притягивает сетки к земле, тем самым отключая дисплеи. Я добавил более полное объяснение ниже в качестве ответа., @6v6gt

Для будущих искателей вы можете проверить окончательный проект [здесь](https://www.hackster.io/tmburns/driving-vfd-tubes-with-an-arduino-nano-14f71e). Большое спасибо тем, кто прокомментировал — ваши отзывы были чрезвычайно полезны., @Thomas Burns


3 ответа


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

0

Похоже, ваш код инвертирует шаблон переключения цифр. Вместо того, чтобы включать выбранную цифру и выключать две другие, вы делаете обратное.

К сетке трубки VFD должно быть приложено напряжение для освещения выбранных сегментов. Эти сегменты также выбираются при подаче напряжения. Схема, которую вы показали, по умолчанию питает как сети, так и сегменты через резисторы 10k, подключенные к шине питания 25 вольт. Транзисторы, также в uln2803, при включении притягивают сетки и сегменты к земле, тем самым отключая эти элементы. Такая компоновка снижает сложность схемы, устраняя необходимость в переключении на стороне высокого напряжения, но при этом возникают "потери". мощность.

Проблему должно решить простое исправление кода:

// Отключаем цифры
   digitalWrite(DIG1, HIGH);  // high выключает сетку.
   digitalWrite(DIG2, HIGH); 
   digitalWrite(DIG3, HIGH);
 }
if (digit == 1) { 
   digitalWrite(DIG1, LOW);  // цифра один ON
   digitalWrite(DIG2, HIGH); // цифра два ВЫКЛ.
   digitalWrite(DIG3, HIGH); // цифра три выключена
}

Проделайте то же самое для цифр 2 и 3.

Используйте резисторы (скажем, 1k) последовательно с базами транзисторов, чтобы ограничить ток и защитить контакты Arduino. См. https://learn.sparkfun.com/tutorials/transistors/applications-i-switches.

Вам все еще необходимо убедиться, что провод, соединяющий R9, R10 и R11, полностью подходит к шине +25 В. Из схемы это не ясно.

,

Большое спасибо за это объяснение! В конце концов я заменил транзисторы 2N3904 на ULN2803, и это решило проблему. Теперь все работает как надо, за исключением одной небольшой особенности: я настроил простой счетчик для циклического перебора чисел и вижу очень слабое свечение на сегментах, на которые не подается питание во время подсчета. Эффект "призрака", так сказать, на всех цифрах. На не выбранные контакты каким-то образом попадает очень низкое напряжение. Любая идея, откуда это может исходить?, @Thomas Burns

@ThomasBurns Если вы получаете ореолы, то перед включением одной цифры сначала выключите две другие, затем настройте сегменты (вызвав display_number() ) и подождите, скажем, 1 мс. Затем включите выбранную цифру. Кроме того, ускорьте мультиплексирование. Вероятно, отображайте каждую цифру в течение примерно 5 мс, чтобы избежать заметного мерцания, но без слишком больших потерь при переключении. Это означает небольшую реструктуризацию вашего кода., @6v6gt

Да, это сработало (пришлось повозиться с этим несколько минут). Большое спасибо за отзыв!, @Thomas Burns


2

Год или около того назад я сделал часы с частотно-регулируемым приводом, используя классные старые лампы DG10B из раннего калькулятора. У меня было чертовски много времени, чтобы заставить его работать, пока я не решил попробовать решать одну проблему за раз, а затем собрать все вместе.

В своих часах я использовал микросхему драйвера VFD MAX6921, RTC DS3231 с суперконденсатором и XIAO для мозгов. Чип драйвера ЧРП управляется ШИМ/последовательным портом (данные, нагрузка, часы), а RTC работает через I2c.

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

распиновка трубки Трубки DG10b

как только у меня появились "шрифты" разобравшись с регистром для каждой цифры, я создал простой цикл, который считал от 0 до 9 на всех цифрах со всеми четырьмя включенными. 4444, 5555 и т. д.

Затем я начал пытаться загорать только одну цифру за раз. (это помогло мне найти другую проблему с проводкой) // [pihgfedcba------1234}; //так выглядит поток данных при отправке драйверу // ...где первые 10 цифр — это сегменты, а последние 4 — сетки для каждой цифры слева направо 1-4. // Остальные в настоящее время не используются и должны быть дополнены нулями или единицами)

Затем я сделал цикл, который будет проверять время и распечатывать цифры. Я ДЕЙСТВИТЕЛЬНО использую delay() в своем коде, чтобы преднамеренно мерцать мои трубки (для эффекта античного стимпанка) Но вот в чем дело, я считаю, что мой код проверяет время для каждой отдельной цифры. цикл говорит для каждой цифры 1-4 (время проверки, отображаемая цифра)

было гораздо больше вовлечено, и я уже давно не работал над этим, поэтому я не уверен, что могу быть здесь полезен. Я просто хотел предложить вам следовать хорошему процессу устранения неполадок. (мелкие проблемы легче решить)

мои часы VFD

,

Это было чрезвычайно полезно. Ваш подход привел меня к выводу, что я использовал неправильную распиновку для микросхемы UNL2803. Исправление этого решило проблемы с моим сегментом. Все еще работаю над выяснением того, что происходит с цифрами. Спасибо! Также хотел быстро сказать, что ваша техника макета вдохновляет — моя выглядит значительно менее организованной., @Thomas Burns

Ха-ха, да, мой пансион для хлеба немного одержим. -и я рад, что смог помочь. Дисплеи VFD настолько увлекательны. Надеюсь, ваш проект окажется таким, каким вы хотите его себе представить. :), @Jon Dresser

Я хотел бы получить в свои руки некоторые из этих трубок VFD с их грубыми рукописными шрифтами. Но я знаю, что такие странные дисплеи с мячами трудно достать, и, вероятно, они выходят за рамки любого разумного бюджета на хобби., @6v6gt


0

Для будущих искателей, я, наконец, получил эту схему с использованием двух массивов транзисторов ULN2803 вместо дискретных транзисторов для цифровых соединений. Вот окончательная схема:

Вы можете узнать больше об окончательном проекте здесь. Большое спасибо тем, кто прокомментировал — ваш отзыв был очень полезен!

,

ваша окончательная схема все еще содержит ошибки. Вы исправили отсутствующий GND в драйверах ULN2803. Но входы COM (контакт 10) и три резистора для сети должны быть подключены к +24В!, @Landroval

@Landroval Спасибо, что указали на это! Я заменил схему на исправленную версию., @Thomas Burns