Проблема с алгоритмом конкатенации символов в матричном светодиоде
Добрый день, я делаю светодиодную матрицу 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);
}
Я ценю помощь.
@Lucio Mazzini, 👍0
Обсуждение1 ответ
Лучший ответ:
Вот несколько проблем, которые я заметил в этом коде. Я думаю, что если вы удастся решить их, вы должны получить плавное отображение:
В выражении
(temp_2>>(8-shift_step)-scroll)
количество сдвиг будет отрицательным, когдаscroll
станет больше 7. Правильно сдвиг на отрицательную величину не является сдвигом влево: он не определен поведение. Судя по видео компилятор ни хрена не делает вообще в этом случае.Если вам нужен интервал в один пиксель между символами, вы должны переходить к следующему символу в строке каждые шесть пикселей, таким образом, переменная прокрутки должна иметь значение от 0 до 5.
Учтите, что одновременно может быть до трех символов. (частично) отображается на экране: когда один символ находится в центре, вы должны видеть края обоих его соседей.
Как заметил в комментарии 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
- Замена большой таблицы поиска оператором switch
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
- Не удается снова загрузиться после смены платы
- Генерация стабильной частоты
- В чем разница между ATMEGA32 и ATMEGA328?
- Arduino UNO для получения подписи чипа ATmega328P-PU
- Последовательная связь ESP8266 с ATMega328P
- Каково время нарастания выходного вывода atmega328, изменяющего свое состояние?
Что касается странного символа в конце дисплея, я думаю, что ваш
index_2
обращается за пределами strlen (сообщения) ближе к концу сообщения., @hcheungЗамедлите видео на Youtube до скорости воспроизведения 0,25, и вы увидите, почему он не отображает символы плавно..., @hcheung