Сопоставление сегментов и распределение памяти в драйвере сегментного ЖК-дисплея

Я только что настроил сегментный ЖК-дисплей и драйвер, все работает нормально, но поскольку я решил не использовать переходные отверстия на печатной плате, соединения между ними смешанные.

Если точнее, то для отображения числа 12 необходимо обращение к обоим адресам памяти.

Поэтому сейчас невозможно отобразить одну цифру без сопоставления всех сегментов.

В статическом режиме память ОЗУ распределяется для SEG0-SEG7 и SEG8-SEG15 соответственно: сопоставление объединительной платы

Я попробовал создать два многомерных массива и отобразить возможные комбинации двух цифр, вот так:

// от 01 до 09
const byte map1[10][2] = {
  {B01110111, B111111 },
  {B01110001, B100111},
  {B01111011, B011111},
  {B01111011, B110111},
  {B01111101, B100111},
  {B01111110, B110111},
  {B01111110, B111111},
  {B01110011, B100111},
  {B01111111, B111111},
  {B01111111, B110111}
};

// от 10 до 19
const byte map2[10][2] {
  {B00010111, B111100},
  {B00010001, B100100},
  {B00011011, B011100},
  {B00011011, B110100},
  {B00011101, B100100},
  {B00011110, B110100},
  {B00011110, B111100},
  {B00010011, B100100},
  {B00011111, B111100},
  {B00011111, B110100}
};

Если нет возможности смешать или сопоставить их динамически, чтобы можно было получить любую возможную комбинацию от 00 до 99, единственное решение — добавить переходные отверстия на печатную плату и перемонтировать все, как описано в таблице данных.

Есть идеи?

Спасибо

, 👍1

Обсуждение

пожалуйста, объясните, как этот пост посвящен Arduino, @jsotola

Имейте таблицу поиска, чтобы сопоставить каждый сегмент с битом в памяти ЖК-дисплея (14 (или 2x7) сегментов, сопоставляя (вероятно, самый простой) uint16_t для бита). Затем еще одна таблица поиска чисел (0–9) в сегментах. Есть несколько способов сделать это. Я сделал это сам, поскольку более простая компоновка означала некоторую дополнительную абстракцию в моем коде, чтобы исправить странный выбор распиновки. Иногда я писал отдельный код, который генерировал массив 0-99; скопируйте и вставьте это в мой эскиз. Это заставляет код работать очень быстро, поскольку это всего лишь поиск. Для экономии оперативной памяти я использовал PROGMEM, чтобы хранить таблицу во флэш-памяти., @Gerben


1 ответ


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

0

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

Шаг первый: создайте пару масок, определяющих, какие биты памяти связаны с какой цифрой.

Представьте, что ваши цифры записаны в памяти в таком порядке. Для простоты я работаю с 16-битными значениями, но нет причин, по которым вы не могли бы разделить их на два 8-битных значения каждое, если вам так проще (P — десятичная точка. Нижний регистр — левая цифра, верхний регистр — правая цифра):

      MSB                         LSB
      a C d g E B p A c D f b e G F P

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

      MSB                         LSB
      a C d g E B p A c D f b e G F P
Left  1 0 1 1 0 0 1 0 1 0 1 1 1 0 0 0 
Right 0 1 0 0 1 1 0 1 0 1 0 0 0 1 1 1 

Право — это инверсия левого, поэтому для right вы можете использовать ~left и сэкономить 2 байта.

В конечном итоге это будет так:

uint16_t leftDigit = 0xB2B8;
uint16_t rightDigit = 0x4D47;

Теперь вы создаете таблицу, из каких сегментов какие числа создаются. Волшебство здесь в том, что вам не нужны отдельные цифры. Еще нет. Вам нужна таблица 16-битных значений, которые представляют числа 00, 11, 22, 33, 44, 55, 66, 77, 88, 99 (и, возможно, два пробела, но это всего лишь 0x0000, поэтому вам может не понадобиться чтобы сохранить это явно).

В конечном итоге у вас может получиться что-то вроде:

uint16_t digits[] = {
    0b1110110111111010, // 00
    0b0100010010010000, // 11
    0b1011110101011100, // 22
    // ... etc ...
};

Теперь происходит настоящее волшебство.

Вам нужен буфер памяти, который отражает содержимое памяти вашего драйвера. Вы не изменяете память драйвера напрямую — вы изменяете свой буфер памяти, а затем отправляете оба его байта в драйвер дисплея одновременно, обновляя все сегменты вместе.

uint16_t buffer = 0;

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

// Шаг первый, стираем левую цифру
buffer &= ~leftDigit;
// Шаг второй, помещаем в него биты для 1 с наложенной маской левой цифры:
buffer |= (digits[1] & leftDigit);

// Шаг третий, стираем правую цифру
buffer &= ~rightDigit;
// Шаг четвертый, помещаем в него биты для 1 с наложенной маской левой цифры:
buffer |= (digits[2] & leftDigit);

На самом деле это довольно долгий путь. Но это позволяет вам просто изменить одну цифру, не затрагивая другую. Если вы хотите просто заменить все содержимое дисплея (обе цифры одновременно), вам не потребуется много усилий:

buffer = (digits[1] & leftDigit) | (digits[2] & rightDigit);

Я просто разберу его, чтобы вы увидели, что он делает.

            MSB                         LSB
            a C d g E B p A c D f b e G F P
 digits[1]: 0 1 0 0 0 1 0 0 1 0 0 1 0 0 0 0
 leftDigit: 1 0 1 1 0 0 1 0 1 0 1 1 1 0 0 0
       AND: 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 // b and c enabled

 digits[2]: 1 0 1 1 1 1 0 1 0 1 0 1 1 1 0 0
rightDigit: 0 1 0 0 1 1 0 1 0 1 0 0 0 1 1 1
       AND: 0 0 0 0 1 1 0 1 0 1 0 0 0 1 0 0 // A B D E and G enabled

OR of ANDS: 0 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 // b c A B D E G enabled

И сопоставьте эти сегменты со стандартной раскладкой 7-сегментного дисплея:

И вы образуете число 12.

Затем вы берете значение буфера и записываете его в память дисплея. Вы можете разделить 16-битное значение на 8-битные значения с помощью маскировки битов (& 0xFF) и сдвига битов (>> 8).

uint8_t b1 = buffer & 0xFF; // Младший байт памяти
uint8_t b2 = (buffer >> 8) & 0xFF; // Верхний байт памяти
,

Отличный ответ, большое спасибо за ваше время и усилия. Я попробую сегодня и вернусь к вам с обновлениями., @Meepo