Последняя версия в посте от 9 октября, а текст я редактирую прямо в Arduino IDE (можно копировать и вставлять из блокнота, но не из ворда - там своё форматирование) и сразу заливаю - проблем нет. Декодируется из UTF-8, а из других кодировок конечно надо по-другому декодировать.
Пользователь ардуиновского форума "danigom", на которого есть ссылка в скетче, уже куда-то подевался и ссылка устарела.
(http://forum.arduino.cc/index.php?actio ... e;u=188950)
Заодно хотел ответить тем, кто спрашивает про покупку такого светодиодного модуля. Ссылка на модуль в первом посте приведена в качестве примера и ни в коей мере не является рекламой именно этого продавца. Наоборот, у других продавцов можно купить существенно дешевле.
привет, внесу свои 5 копеек насчет бекслеша и кавычек, чтобы их выводить в строках достаточно их экранировать, тоесть будет строка вида "Велосипед \"Костыль\"", возможно в скетче нужно будет добавить пропуск бекслеша и ввести счетчик подряд идущих, чтобы откидывать первый но выводить все остальные тогда можно будет смело написать "\"234\"" и компилятор поймет что от него хотят)
P.S. Спасибо за проделанную работу, похоже буду использовать ваши наработки.
Появился второй блок из 4-х матричных модулей 8х8. Припаял к первому - получилось 8 модулей.
Пока поправил первый скетч - добавил комментарии для пущей ясности и количество модулей -
int Modules = 8; // количество матричных модулей 8х8 точек
Если там вписать 1 вместо 8, то скетч будут работать только с одним модулем (матрицей). И если убрать (закомментировать) задержки delay(500); и delay(800); то будет наглядно видно, как происходит передача информации от одного модуля к другому. Спойлерunsigned char i;
unsigned char j;
unsigned char n;
int Max7219_pinCLK = 10; // назначение пина тактовых импульсов (у ATM328 это 16-й вывод)
int Max7219_pinCS = 9; // назначение пина импульсов загрузки (у ATM328 это 15-й вывод)
int Max7219_pinDIN = 8; // назначение пина вывода данных (у ATM328 это 14-й вывод)
int Modules = 8; // количество матричных модулей 8х8 точек
unsigned char disp2[16][2] = {
0x05, 0x40, // рисунок сердца по строкам (адрес строки, данные)
0x04, 0x40,
0x03, 0x80,
0x02, 0x80, // строки в каждом матричном модуле -
0x01, 0x40, // нумеруются сверху вниз (разъём справа)
0x01, 0x60,
0x02, 0x90, // в каждой строке по две точки -
0x03, 0x88, // добавляются по одной в порядке рисования
0x04, 0x44,
0x05, 0x44, // в рисунке сердца 16 точек (сердце на боку) -
0x06, 0x08, // всего 16 элементов массива
0x07, 0x10, // в первый раз строка рисуется с одной точкой
0x08, 0x20, // во второй раз - с двумя точками
0x08, 0x60,
0x07, 0x90,
0x06, 0x88, // рисунок сердца по строкам (адрес строки, данные)
};
void Write_Max7219_byte(unsigned char DATA) { // подпрограмма записи байта DATA от старшего бита
unsigned char i;
digitalWrite(Max7219_pinCS, LOW);
for (i = 8; i >= 1; i--) {
digitalWrite(Max7219_pinCLK, LOW);
digitalWrite(Max7219_pinDIN, DATA & 0x80);
DATA = DATA << 1;
digitalWrite(Max7219_pinCLK, HIGH);
}
}
void Write_Max7219(unsigned char address, unsigned char dat) { // подпрограмма записи байта адреса и байта данных
digitalWrite(Max7219_pinCS, LOW); // установка сигнала CS (пин 9) в логический 0
for (n = 1; n < Modules+1; n++) { // повторяем для нескольких матричных модулей
Write_Max7219_byte(address); // запись байта адреса в индикатор (в регистр сдвига)
Write_Max7219_byte(dat); // запись байта данных в индикатор (в регистр сдвига)
}
digitalWrite(Max7219_pinCS, HIGH); // установка сигнала CS (пин 9) в логическую 1 (защёлкивание)
}
void Init_MAX7219(void) { // подпрограмма инициализации MAX7219
Write_Max7219(0x09, 0x00); // регистр управления режимом декодирования данных - отключено
Write_Max7219(0x0a, 0x03); // регистр настройки яркости - 7/32 (меньше четверти)
Write_Max7219(0x0b, 0x07); // регистр количества активных индикаторов - максимум (8)
Write_Max7219(0x0c, 0x01); // режим работы: 0 - shutdown, 1 - включено
Write_Max7219(0x0f, 0x00); // регистр тестирования - не отображать тест
}
void setup() { // установка пинов в режим вывода
pinMode(Max7219_pinCLK, OUTPUT);
pinMode(Max7219_pinCS, OUTPUT);
pinMode(Max7219_pinDIN, OUTPUT);
delay(50);
Init_MAX7219(); // обращение к подпрограмме инициализации
}
void loop() {
//рисуем сердце по кадрам
for (j = 0; j < 17; j++) { // элементы массива нумеруются от 0
for (i = 1; i < 9; i++)
Write_Max7219(i, disp1[j]);
delay(100);
}
delay(500);
//все стираем
for (i = 1; i < 9; i++) { // i - строка сверху вниз для каждого модуля
Write_Max7219(i, 0x00);
delay(100);
}
delay(500);
//рисуем сердце по строкам
for (j = 0; j < 16; j++) { // элементы массива нумеруются от 0
Write_Max7219(disp2[j][0], disp2[j][1]);
delay(100);
}
delay(500);
//все закрашиваем
for (i = 1; i < 9; i++) { // i - строка сверху вниз для каждого модуля
Write_Max7219(i, 0xFF);
delay(100);
}
delay(500);
//все стираем
for (i = 1; i < 9; i++) {
Write_Max7219(i, 0x00);
delay(100);
}
Длинный буфер действительно надо ещё удлинять, но тут я был неправ:
Полосатый писал(а):Максимальная длина переменной в здешнем языке - тоже 32 бита, double precision тут не работает.
Это в Фортране double precision, а в СИ такое, оказывается, тоже есть, только "дважды длинное" - long long.
unsigned long long bufferLong [16] = {0};
Только почему-то удлинилось не на 8 матриц, а на 7,5. Пока просто сдвинул на четверть матрицы (два столбца) вправо для симметрии, а глубоко копать сейчас недосуг. Если кто что раскопает, напишите. Спойлер// based on an orginal sketch by Arduino forum member "danigom"
// h t t p://forum.arduino.cc/index.php?action=profile;u=188950
// Русифицированная "бегущая строка" для светодиодных матриц 8х8 с чипом MAX7219.
// Вот скетч, который слепил "danigom" (см выше).
// А вот кириллица, которая в длинном массиве хранится, в скетче, который слепил "danigom".
// А вот Николай, которому мёду с утра не давай, а дай лишь добавить вот эту кириллицу,
// которая в длинном массиве хранится, к скетчу, который слепил "danigom"...
// Русифицированная версия называется "Велосипед V.1.01." На странице обсуждения мне сказали, что я изобретаю
// велосипед и я подумал: зачем строке пешком бежать? - пусть едет на велосипеде Обсуждали тут: h t t p://
// arduino.ru/forum/programmirovanie/i-snova-pro-begushchuyu-stroku-na-svetodiodnykh-matritsakh-dlya-novichkov
// В строке scrollText можно использовать русские и английские буквы и другие стандартные символы, вводимые
// с русскоязычной клавиатуры, в любой последовательности.
#include <avr/pgmspace.h>
#include <LedControl.h>
const int numDevices = 8; // number of MAX7219s used (количество соединённых матриц 8х8)
const long scrollDelay = 8; // adjust scrolling speed (задержка сдвига текста в мс)
const unsigned char interval = 1; // интервал между символами (в исходном варианте было только число,
// на 1 превышающее ширину символа)
unsigned long long bufferLong [16] = {0};
LedControl lc=LedControl(8,10,9,numDevices); // Номера выводов платы Arduino Uno, на которые поступают
// сигналы DIN, CLK, CS (можно выбрать другие)
const unsigned char scrollText[] PROGMEM = {
" -=* ''Велосипед v.1.03.'' The quick brown fox still jumps, но это её проблемы, а пока съешь же ещё этих мягких французских булок, да выпей чаю. А если не хватит, закуси круассанами, лягушачьими лапками, e.t.c... *=- "};
void setup(){
for (int x=0; x<numDevices; x++){
lc.shutdown(x,false); //The MAX72XX is in power-saving mode on startup
lc.setIntensity(x,3); // Set the brightness to default value
lc.clearDisplay(x); // and clear the display
}
}
const unsigned char font5x7[] PROGMEM = { // Numeric Font Matrix (Arranged as 7x font data + 1x kerning data)
B00000000, //Space (Char 0x20) // Массив шрифта переделан на 8х, чтобы высота текста была 8 точек,
B00000000, // вместо 7, при этом появилась возможность правильно расположить
B00000000, // символы с "подстрочными" элементами (в т.ч. английские);
B00000000, // также вместо 1x kerning data можно задать свой интервал.
B00000000,
B00000000,
B00000000,
B00000000,
5 + interval,
void scrollFont() {
for (int counter=0x20;counter<0xC2;counter++){
loadBufferLong(counter);
delay(200);
}
}
// Scroll Message
void scrollMessage(const unsigned char * messageString) {
int counter = 0;
int myChar = 0;
int CharRange = 0;
do {
// read back a char
myChar = pgm_read_byte_near(messageString + counter);
if (myChar < 0x20 || myChar > 0xbf) // байт не выводится, т.к. либо не включён в шрифт,
{
if (myChar == 0xd0 || myChar == 0xd1){ // либо это первый байт русских символов
CharRange = myChar - 0xd0 + 1 ; // запоминается признак первого байта
}
}
else if (myChar > 0x7f && myChar < 0x90) // второй байт русского символа
{
switch (CharRange) {
case 1: // код 0xd081 - буква Ё в UTF-8
myChar = myChar - 1 ;
break;
case 2: // русские буквы р - я (0xd180 - 0xd18f в UTF-8)
myChar = myChar + 49 ;
break;
}
if (myChar != 0 && myChar < 194){loadBufferLong(myChar);
CharRange = 0 ; // признак обнуляется после вывода второго байта символа
}
}
else if (myChar > 0x8f && myChar < 0xc0)
{
switch (CharRange) {
case 1: // русские буквы А - Я (0xd090 - 0xd0af в UTF-8)
myChar = myChar - 15 ; // и русские буквы а - п (0xd0b0 - 0xd0bf в UTF-8)
break;
case 2: // код 0xd191 - буква ё в UTF-8
myChar = myChar + 48 ;
break;
}
if (myChar != 0 && myChar < 194){loadBufferLong(myChar);
CharRange = 0 ;
}
}
else // английские буквы и прочие символы (0x20 - 0x7f в UTF-8)
{
if (myChar != 0){loadBufferLong(myChar);
CharRange = 0 ;
}
}
counter++;
}
while (myChar != 0);
}
// Load character into scroll buffer
void loadBufferLong(int ascii){
if (ascii >= 0x0020 && ascii <=0x00ff){
for (int a=0;a<8;a++){ // Loop 7 times for a 5x7 font
// Index into character table to get row data
unsigned long c = pgm_read_byte_near(font5x7 + ((ascii - 0x20) * 9) + a);
unsigned long long x = bufferLong [a*2]; // Load current scroll buffer
x = x | c; // OR the new character onto end of current
bufferLong [a*2] = x; // Store in buffer
}
// Index into character table for kerning data
byte count = pgm_read_byte_near(font5x7 +((ascii - 0x20) * 9) + ;
for (byte x=0; x<count;x++){
rotateBufferLong();
printBufferLong();
delay(scrollDelay);
}
}
}
// Rotate the buffer
void rotateBufferLong(){
for (int a=0;a<8;a++){ // Loop 7 times for a 5x7 font
unsigned long long x = bufferLong [a*2]; // Get low buffer entry
byte b = bitRead(x,31); // Copy high order bit that gets lost in rotation
x = x<<1; // Rotate left one bit
bufferLong [a*2] = x; // Store new low buffer
x = bufferLong [a*2+1]; // Get high buffer entry
x = x<<1; // Rotate left one bit
bitWrite(x,0,b); // Store saved bit
bufferLong [a*2+1] = x; // Store new high buffer
}
}
// Display Buffer on LED matrix
void printBufferLong(){
int count[8] { 0, 7, 1, 6, 2, 5, 3, 4 }; // последовательность вывода строк -
for (auto number : count){ // наклон / выпуклость букв
int a = number;
// for (int a=0;a<8;a++){ // Loop 7 times for a 5x7 font
unsigned long long x = bufferLong [a*2+1]; // Get high buffer entry
byte y = x; // Mask off first character
// lc.setRow(7,a,y); // Send row to relevent MAX7219 chip
x = bufferLong [a*2]; // Get low buffer entry
y = (x>>58);
lc.setRow(7,a,y);
y = (x>>50);
lc.setRow(6,a,y);
y = (x>>42);
lc.setRow(5,a,y);
y = (x>>34);
lc.setRow(4,a,y);
y = (x>>26);
lc.setRow(3,a,y);
y = (x>>18);
lc.setRow(2,a,y);
y = (x>>10);
lc.setRow(1,a,y);
y = (x>>2);
lc.setRow(0,a,y);
}
}
Процесс замедлился, поэтому уменьшил задержку до минимума и ещё добавил наклон/выпуклость букв, чтобы их явно не перекашивало в какую-то сторону.
С ардуинозаменителем LGT8F328P бежит в два раза быстрее.
И можно выпуклость убрать:
int count[8] { 7, 6, 5, 4, 3, 2, 1, 0 }; // последовательность вывода строк
Только пины поменял для удобства:
Кто не понимает, как в результате нажимать на кнопку, пока подучите сопромат ... а я пока скетч сочиню ... потом ... может быть ... (лениво)
Последний раз редактировалось Полосатый Пн июл 10, 2023 00:13:02, всего редактировалось 1 раз.
Поясните пожалуйста, что такое "выпуклость"? Я недавно тоже занимался изготовлением бегущей строки на подобных матрицах (3 блока по 4 матрицы каждый). Строки загружаются в порядке сверху вниз. Загрузка текста и управление яркостью и скоростью через специальное Bluetooth приложения для Андроида. Текст и установки сохраняются в энерго-независимой памяти. Пока там использован 6х8 шрифт с одинаковой шириной всех букв, но, глядя на ваши старания, наверное, переделаю на пропорциональный. Писал всё ПО сам, как-то не пришло в голову поискать готовое.
- сначала крайние элементы строк, последние - средние. Скорость вывода у ардуины (работа с матричной библиотекой) ограничена, поэтому средние элементы визуально отставали от крайних. Обычный наклон был большим и некрасивым.
А LGT8F328P работает намного быстрее и обычная последовательность выглядит нормально.
Я тоже не додумался, просто увидел, как буквы наклонены
Теперь хочу записать на флешку набор фраз (строк) - либо в один файл через разделитель, либо каждую в свой файл со своим номером. Чтобы выбирать следующую строку нажатием на кнопку. При этом будет увеличиваться значение счётчика, которое будет записываться в отдельный файл. При включении будет считываться это значение и строка с таким номером. Когда строки закончатся, счётчик обнулится. Как-то так. Но не сейчас Сейчас даже пока не разбирался, почему работают 7,5 матрицы из 8.