Проблема с алгоритмом конкатенации символов в матричном светодиоде

Добрый день, я делаю светодиодную матрицу 7x10, в которой я использую CD4017 для обработки 7 строк и 2 каскадных сдвиговых регистра для обработки 10 столбцов. Сначала я попытался запрограммировать, чтобы включить всю мою светодиодную матрицу, и это сработало нормально. Затем я попытался сделать так, чтобы символ отображался статически, и это сработало. Затем я попытался сделать так, чтобы этот символ прокручивался справа налево, и это сработало нормально. Но то, с чем у меня возникают трудности, это плавное перемещение сообщения справа налево с интервалом между столбцами символов.

Первоначально я думал, что если я хочу переместить символ справа налево, мне нужно сдвинуть значения столбца для всех строк на соответствующую величину (шаг сдвига), и как только символ будет достаточно сдвинут, я начните подавать значения столбца следующего символа в сообщении, для которого формула, которая создаст эффект сдвига справа налево: (current_char<scroll) | (next_char>>(8-shift_step)-прокрутка) Но я не получаю ожидаемого результата, сообщение прокручивается справа налево, но оно не делает этого со столбцом разделения между символом и символом, и оно также не делает это плавным образом. Вдобавок к тому, что в конце зачистки сообщения появляется что-то странное, чего там быть не должно.

Я записал видео, показывающее, что я говорю: https://drive.google.com/file/d. /1ebO5zassWY060mvWACPhcSLeOi5JmZAC/просмотр

Код:

/*
 char_data is a two dimensional constant array that holds the 5-bit column values
 of individual rows for ASCII characters that are to be displayed on a 7x10 matrix. 
*/
const byte char_data[95][7]={
    {0, 0, 0, 0, 0, 0, 0}, // пробел
    {0b100, 0b100, 0b100, 0b100, 0b100, 0, 0b100}, // !
    {0b1010, 0b1010, 0b1010, 0, 0, 0, 0}, // "
    {0b1010, 0b1010, 0b11111, 0b1010, 0b11111, 0b1010, 0b1010}, // #
    {0b100, 0b1111, 0b10100, 0b1110, 0b101, 0b11110, 0b100}, // $
    {0b11000, 0b11001, 0b10, 0b100, 0b1000, 0b10011, 0b11}, // %
    {0b1000, 0b10100, 0b10100, 0b1000, 0b10101, 0b10010, 0b1101}, // &
    {0b100, 0b100, 0b100, 0, 0, 0, 0}, // '
    {0b100, 0b1000, 0b10000, 0b10000, 0b10000, 0b1000, 0b100}, // (
    {0b100, 0b10, 0b1, 0b1, 0b1, 0b10, 0b100}, // )
    {0b100, 0b10101, 0b1110, 0b100, 0b1110, 0b10101, 0b100}, // *
    {0, 0b100, 0b100, 0b11111, 0b100, 0b100, 0}, // +
    {0, 0, 0, 0, 0b100, 0b100, 0b1000}, // ,
    {0, 0, 0, 0b11111, 0, 0, 0}, // -
    {0, 0, 0, 0, 0, 0, 0b100}, // .
    {0, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0}, // /
    {0b1110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b1110}, // 0
    {0b110, 0b1100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // 1
    {0b1110, 0b10001, 0b1, 0b110, 0b1000, 0b10000, 0b11111}, // 2
    {0b11111, 0b1, 0b10, 0b110, 0b1, 0b10001, 0b1111}, // 3
    {0b10, 0b110, 0b1010, 0b10010, 0b11111, 0b10, 0b10}, // 4
    {0b11111, 0b10000, 0b11110, 0b1, 0b1, 0b10001, 0b1110}, // 5
    {0b01110, 0b10001, 0b10000, 0b11110, 0b10001, 0b10001, 0b1110}, // 6
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b1000, 0b1000}, // 7
    {0b01110, 0b10001, 0b10001, 0b1110, 0b10001, 0b10001, 0b1110}, // 8
    {0b01110, 0b10001, 0b10001, 0b1111, 0b1, 0b10001, 0b1110}, // 9
    {0, 0, 0b100, 0, 0b100, 0, 0}, // :
    {0, 0, 0b100, 0, 0b100, 0b100, 0b1000}, // ;
    {0b10, 0b100, 0b1000, 0b10000, 0b1000, 0b100, 0b10}, // <
    {0, 0, 0b11111, 0, 0b11111, 0, 0}, // =
    {0b1000, 0b100, 0b10, 0b1, 0b10, 0b100, 0b1000}, // >
    {0b1110, 0b10001, 0b1, 0b10, 0b100, 0, 0b100}, // ?
    {0b1110, 0b10001, 0b10111, 0b10101, 0b10110, 0b10000, 0b1111}, // @
    {0b1110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // А
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110}, // В
    {0b1110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b1110}, // С
    {0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110}, // Д
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111}, // Е
    {0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000}, // F
    {0b1110, 0b10001, 0b10000, 0b10111, 0b10101, 0b10001, 0b1110}, // Г
    {0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001}, // Н
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b11111}, // В
    {0b1, 0b1, 0b1, 0b1, 0b1, 0b10001, 0b1110}, // J
    {0b10001, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001, 0b10001}, // К
    {0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111}, // л
    {0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001}, // М
    {0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001}, // N
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // О
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000}, // П
    {0b1110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10011, 0b1111}, // Q
    {0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b10001}, // R
    {0b1111, 0b10000, 0b10000, 0b1110, 0b1, 0b1, 0b11110}, // С
    {0b11111, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // Т
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1110}, // U
    {0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // В
    {0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001}, // Вт
    {0b10001, 0b10001, 0b1010, 0b100, 0b1010, 0b10001, 0b10001}, // X
    {0b10001, 0b10001, 0b1010, 0b100, 0b100, 0b100, 0b100}, // Y
    {0b11111, 0b1, 0b10, 0b100, 0b1000, 0b10000, 0b11111}, // Z
    {0b1110, 0b1000, 0b1000, 0b1000, 0b1000, 0b1000, 0b1110}, // [
    {0, 0b10000, 0b1000, 0b100, 0b10, 0b1, 0}, // обратная косая черта
    {0b1110, 0b10, 0b10, 0b10, 0b10, 0b10, 0b1110}, // ]
    {0, 0, 0b100, 0b1010, 0b10001, 0, 0}, // ^
    {0, 0, 0, 0, 0, 0, 0b11111}, // _
    {0b1000, 0b100, 0b10, 0, 0, 0, 0}, // `
    {0, 0, 0b1110, 0b1, 0b1111, 0b10001, 0b1111}, // а
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b11110}, // б
    {0, 0, 0b1110, 0b10001, 0b10000, 0b10001, 0b1110}, // с
    {0b1, 0b1, 0b1, 0b1111, 0b10001, 0b10001, 0b1111}, // д
    {0, 0, 0b1110, 0b10001, 0b11111, 0b10000, 0b1111}, // е
    {0b1110, 0b1001, 0b11100, 0b1000, 0b1000, 0b1000, 0b1000}, // ф
    {0, 0, 0b1110, 0b10001, 0b1111, 0b1, 0b1110}, // г
    {0b10000, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b10001}, // ч
    {0b100, 0, 0b100, 0b100, 0b100, 0b100, 0b1110}, // в
    {0b1, 0, 0b11, 0b1, 0b1, 0b10001, 0b1110}, // j
    {0b10000, 0b10000, 0b10001, 0b10010, 0b11100, 0b10010, 0b10001}, // к
    {0b1100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b1110}, // л
    {0, 0, 0b11110, 0b10101, 0b10101, 0b10101, 0b10101}, // м
    {0, 0, 0b11110, 0b10001, 0b10001, 0b10001, 0b10001}, // п
    {0, 0, 0b1110, 0b10001, 0b10001, 0b10001, 0b1110}, // о
    {0, 0, 0b1111, 0b1001, 0b1110, 0b1000, 0b1000}, // р
    {0, 0, 0b1111, 0b10001, 0b1111, 0b1, 0b1}, // q
    {0, 0, 0b10111, 0b11000, 0b10000, 0b10000, 0b10000}, // г
    {0, 0, 0b1111, 0b10000, 0b1110, 0b1, 0b11110}, // с
    {0b100, 0b100, 0b1110, 0b100, 0b100, 0b100, 0b11}, // т
    {0, 0, 0b10001, 0b10001, 0b10001, 0b10011, 0b1101}, // и
    {0, 0, 0b10001, 0b10001, 0b10001, 0b1010, 0b100}, // v
    {0, 0, 0b10001, 0b10001, 0b10101, 0b11111, 0b10101}, // ш
    {0, 0, 0b10001, 0b1010, 0b100, 0b1010, 0b10001}, // х
    {0, 0, 0b10001, 0b10001, 0b1111, 0b1, 0b11110}, // г
    {0, 0, 0b11111, 0b10, 0b100, 0b1000, 0b11111}, // г
    {0b10, 0b100, 0b100, 0b1000, 0b100, 0b100, 0b10}, // {
    {0b100, 0b100, 0b100, 0b100, 0b100, 0b100, 0b100}, // |
    {0b1000, 0b100, 0b100, 0b10, 0b100, 0b100, 0b1000}, // }
    {0, 0, 0, 0b1010, 0b10101, 0, 0} // ~
};
char message[] = "MATRIX LED 7X10 WITH ATMEGA328p";
int string_length = strlen(message);
byte shift_step = 1;

void setup(){
    // PORTB в качестве вывода.
    // Контакт 13: ClockRegister
    // Контакт 12: защелка
    // Контакт 11: Данные
    // Контакт 10: сброс
    // Пин 9: Clock4017
    DDRB = 0b111111;
    // Проверяем, что значение 4017 равно 0.
    PORTB |= (1 << PB2);
    PORTB &= ~(1 << PB2);
    Serial.begin(9600);
}

void send_data(uint16_t data){
    uint16_t mask = 1, flag = 0;
    for (byte i=0; i<10; i++){
        flag = data & mask;
        if (flag) PORTB |= (1 << PB3);
        else PORTB &= ~(1 << PB3);
        PORTB |= (1 << PB5);
        PORTB &= ~(1 << PB5);
        mask <<= 1;
    }
    PORTB |= (1 << PB4);
    PORTB &= ~(1 << PB4);
}

void display_pattern(byte loops){
    for (byte c=0; c<string_length; c++){ // Для каждого символа
        for (byte scroll=0; scroll<10; scroll++){ // Для каждого столбца.
            for (byte t=0; t<loops; t++){ // Задержка, которую мы получаем с помощью циклов.
                for (byte z=0; z<7; z++){ // Для каждой строки.
                    // Чтобы получить позицию текущего символа в массиве char_data, вычтите 32 из значения ASCII самого символа.
                    byte index = message[c];
                    byte temp = char_data[index-32][z];
                    byte index_2 = message[c+1];
                    byte temp_2 = char_data[index_2-32][z];
                    send_data((temp<<scroll) | (temp_2>>(8-shift_step)-scroll));
                    delayMicroseconds(800);
                    // Очистить строку, чтобы мы могли перейти к следующей строке без размытия.
                    send_data(0);
                    // На следующую строку.
                    PORTB |= (1 << PB1);
                    PORTB &= ~(1 << PB1);
                }
                // Выбираем первую строку.
                PORTB |= (1 << PB2);
                PORTB &= ~(1 << PB2);
            }
        }
    }
}

void loop(){
    display_pattern(10);
    delay(100000);
}

Я ценю помощь.

, 👍0

Обсуждение

Что касается странного символа в конце дисплея, я думаю, что ваш index_2 обращается за пределами strlen (сообщения) ближе к концу сообщения., @hcheung

Замедлите видео на Youtube до скорости воспроизведения 0,25, и вы увидите, почему он не отображает символы плавно..., @hcheung


1 ответ


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

2

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

  1. В выражении (temp_2>>(8-shift_step)-scroll) количество сдвиг будет отрицательным, когда scroll станет больше 7. Правильно сдвиг на отрицательную величину не является сдвигом влево: он не определен поведение. Судя по видео компилятор ни хрена не делает вообще в этом случае.

  2. Если вам нужен интервал в один пиксель между символами, вы должны переходить к следующему символу в строке каждые шесть пикселей, таким образом, переменная прокрутки должна иметь значение от 0 до 5.

  3. Учтите, что одновременно может быть до трех символов. (частично) отображается на экране: когда один символ находится в центре, вы должны видеть края обоих его соседей.

  4. Как заметил в комментарии hcheung, когда вы дойдете до последнего символа в строке выражение message[c+1] читается за конец этой строки.

,

Вы правы насчет прокрутки, я уменьшил диапазон прокрутки до scroll<7 и она не застревает, но персонаж исчезает раньше. Я не могу понять правильную формулу, когда прокрутка больше 6. Видео: https://drive.google.com/file/d/1bkDzEiGrz1c6avpHSnl6ox7D34MD-mp9/view?ts=635b02e3, @Lucio Mazzini

Я пытался сделать это: if (scroll < 7) send_data((temp<<scroll) + (temp_2 >> 6-scroll)); else send_data((temp<<scroll) + (temp_2 << (scroll-6))); Но ведет себя странно, проходит первый символ, потом моргает, идет обратно и снова идет., @Lucio Mazzini

@LucioMazzini: трудно помочь в отладке, не видя весь код. При этом я думаю, что правильной формулой должна быть send_data(temp<<scroll+6|temp_2<<scroll|temp_3>>6-scroll);., @Edgar Bonet

Где temp будет текущим символом, temp_2 — следующим символом, а temp_3 — символом, который идет после temp_2, верно?, @Lucio Mazzini

@LucioMazzini: temp_2 — единственный символ, который полностью помещается на дисплее (может быть только один). temp — это символ (если есть), который частично отображается слева от temp_2, видимый только при прокрутке≤3. temp_3 — это символ (если есть), который частично отображается справа от temp_2, видимый только при прокрутке ≥2. Обратите внимание, что вам придется дополнять свое сообщение пробелами с обоих концов., @Edgar Bonet

Привет, ну, я смог внести изменения в свое программирование, и подметание символов работает правильно, но у меня возникла небольшая проблема... Символы отображаются в зеркальном отображении., @Lucio Mazzini

Видео: https://drive.google.com/file/d/1qM7w7Zx73k8dR_xCpCwLOzvuMJoXU7vZ/view, @Lucio Mazzini

Код: https://pastebin.com/seL3RTch, @Lucio Mazzini

Забудь, я уже решил. Я начал маску с 0b10000 и прокручиваю маску вправо, а двоичное смещение составляет 4 столбца. Теперь работает нормально, спасибо., @Lucio Mazzini