Доброго времени суток! Есть отичная тема Связка Mega2560 с p10 led module. Так вот она решила примерно 80% моих проблем и вопросов. У меня только Arduino DUE, и все библиотеки предлагаемые в теме выше да и вообще все что я смог найти в нете не подходят для DUE, так как там архитектура ARM а не AVR, а библиотеки под последнюю как раз и заточены. С темы что написал выше взял код, и не могу разобраться в нем до конца, что бы мог сам кодировать свои изображения, собственно вот код, вопросы потом: Код (Text): // названия пинов такие же, как и на модуле P10 int nOE = 13; int A = 12; int B = 11; int CKL = 10; int SCLK = 9; int R = 8; int vrem=0; //Начало отсчета времени для переключения слов int pa=60; // Интервал переключения unsigned char screen [128]; //Видеопамять // тут зашифрованно изображение, алгоритм данного изображения я не могу понять char sl1 [] = { 255,128,128,128,255,4,96,4,255,0,192,0,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,128,0,14,49,0,0,0,128,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,128,0,31,31,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,255,0,49,14,255,0,128,0,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; char sl2 [] = { 255,128,128,128,255,68,100,132,255,64,192,64,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 130,128,128,129,0,46,49,0,8,128,128,32,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 129,128,128,130,0,31,63,0,16,0,0,16,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,255,128,49,78,255,32,128,128,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; void setup() { pinMode(R, OUTPUT); pinMode(CKL, OUTPUT); pinMode(SCLK, OUTPUT); pinMode(nOE, OUTPUT); pinMode(A, OUTPUT); pinMode(B, OUTPUT); } void loop() { for(byte i=0; i<4 ; i++) { SelectStr(i); // Выбор псевдостроки SendBytes(screen + i*32); // Рисуем псевдостроку /+ i*32 digitalWrite(nOE, HIGH); // Включаем матрицы delayMicroseconds(300); // Пауза 200 digitalWrite(nOE, LOW); // Отключаем матрицы } if (vrem == pa) { for(int i = 0; i < 128; i++) //Заносим в видеопамять первое слово { screen[i] = sl1[i]; }; }; if (vrem == pa*2) { for(int i = 0; i < 128; i++) //Заносим в видеопамять второе слово { screen[i] = sl2[i]; }; vrem=0; }; vrem=vrem+1; // Увеличение отсчета времени } void SelectStr(byte n) // Выбор псевдостроки { if (n & B00000001) digitalWrite(A, LOW); else digitalWrite(A, HIGH); if (n & B00000010) digitalWrite(B, LOW); else digitalWrite(B, HIGH); } // ниже никаких комментариев не было, и тут я ничего не понял void SendBytes(unsigned char* b) // Рисуем псевдостроку { byte i; byte k; for(k = 0; k<16; k++) for(i = 0; i<8; i++) { digitalWrite(CKL, LOW); if((b[k] & (1 << (7-i))) ) { digitalWrite(R, LOW); } else { digitalWrite(R, HIGH); } digitalWrite(CKL, HIGH); } digitalWrite(SCLK, HIGH); digitalWrite(SCLK, LOW); return; }; Вопрос № 1. Можете на пальцах объяснить как примерно понимать что здесь будет отображено, я бы понял если бы там были 1 - горит, 0 не горит. Но эти два массива выводят два кадра по очереди, вот 1 из них. Но как заполнять массив если я хочу придумать свои изображения. Код (Text): char sl1 [] = { 255,128,128,128,255,4,96,4,255,0,192,0,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,128,0,14,49,0,0,0,128,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,128,0,31,31,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,255,0,49,14,255,0,128,0,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; char sl2 [] = { 255,128,128,128,255,68,100,132,255,64,192,64,255,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 130,128,128,129,0,46,49,0,8,128,128,32,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 129,128,128,130,0,31,63,0,16,0,0,16,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 128,128,128,255,128,49,78,255,32,128,128,255,1,1,1,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; Вопрос № 2. В функцию SendBytes передается (screen + i * 32), но screen это же массив символов, что значит(screen + i * 32). Я пытался вывести Serial.begin(String(screen + i * 32)), думал посмотреть что выведет в строку, но вылезает ошибка. Код (Text): unsigned char screen [128]; //Видеопамять ... void loop() { for(byte i=0; i<4 ; i++) { SelectStr(i); // Выбор псевдостроки SendBytes(screen + i*32); // Рисуем псевдостроку /+ i*32 digitalWrite(nOE, HIGH); // Включаем матрицы delayMicroseconds(300); // Пауза 200 digitalWrite(nOE, LOW); // Отключаем матрицы } ... Вопрос № 3. Самый главный. Не могу никак понять алгоритм данной функции. И как понять это условие if((b[k] & (1 << (7-i))) ) ? Там ## между решеток ## в кде вопрос еще один Код (Text): void SendBytes(unsigned char* b) // Рисуем псевдостроку { byte i; byte k; for(k = 0; k<16; k++) for(i = 0; i<8; i++) { digitalWrite(CKL, LOW); if((b[k] & (1 << (7-i))) ) { digitalWrite(R, LOW); #### данное условия никогда не истина и не выполняется, но если убрать то выйдет бардак, ставил туда Serial.begin() и он ниразу не вылез, а ниже отображается #### } else { digitalWrite(R, HIGH); } digitalWrite(CKL, HIGH); } digitalWrite(SCLK, HIGH); digitalWrite(SCLK, LOW); return; }; Массив screen состоит из 128 элементов, который передается в эту функцию, но в цикле проходит всего for(k = 0; k<16; k++) 16 итераций, что я понял не так? P.S. Забыл уточнить, этот код был расчитан на 2 таких панели, т.е. screen как я понял хранит информацию для двух панелей, а мне бы с одной разобраться Собственно как формировать картинку то? Как она преобразуется из моей головы например в массив значений, а потом из этого массива на панель?
Сопоставив размеры экрана (16х32), а также разрядность (char-8 бит) и размерность массива (128) с указанием на то, что код рассчитан на два таких экрана, логично предположить, что каждый байт - это 8 бит, 8 светодиодов. Связь между конкретными светодиодами и байтами навскидку не просматривается. Надо пробовать выдавать нулевой массив с одним взведенным битом в одном из байтов и смотреть, что загорится. И так перебрать все возможные точки. screen+i*32 эквивалентно в данном случае адресу элемента screen [i*32]. Serial.begin(String(screen + i * 32)) при этом выглядит странно. Может быть, Serial.print? Serial.begin вроде как инициализирует последовательный порт с указанием скорости. Это означает, что проверяется бит k-го элемента массива b с номером 7-i (нумерация начинается с 0 с младшего бита). Если бит 1, то условие истинно (результат больше 0) По сути выражение в if обнуляет все биты в байте (символе), являющемся элементом массива, кроме того, что с номером (7-i). И если данный бит не 0, то и результат не ноль. Таким образом проверяются все биты в байте, начиная со старшего. По факту в функцию передается четыре раза (вызывается функция) указатель на элемент массива с номером i*32. Потом в функции отрабатывается 16 байт начиная с указанного таким образом элемента массива (последовательно "закидываются в пин"). Указатель, переданный в качестве параметра сам по себе рассматривается как массив, начинающийся с указанного байта. В результате обрабатываются 16 байт через 16 не обрабатываемых. Четыре итерации проходят таким образом весь массив. Это заставляет полагать, что экран поделен на 4 зоны (псевдостроки), каждая из которых кодируется 16-тью байтами, каждый бит из которых "зажигает" один светодиод. Т.е. на самом деле управляется одна панель. Данные второй, которые вроде как должны присутствовать в массиве судя по размеру, просто пропускаются. Взводить биты в байтах массива. Единственное что придется установить экспериментально - соответствие каждого бита в байте конкретному светодиоду. Смысл примерно такой 255=11111111b - "горят" все светодиоды, соответствующие байту. Такие байты в массиве должны, скорее всего, соответствовать строкам или столбцу с краю экрана, где горят все светодиоды. 128=10000000b - "горит" первый (или последний, смотря как считать) светодиод. 64=01000000b - второй. 32=00100000b - третий. И т.д.
Во всем прав! Просто я не знаю в каком формате P10 принимает данные, т.к. много разных способов видел, этот вариант более менее рабочий, вот и довожу его до ума. Уже есть успехи, как доделаю до конца, выложу всю инфу. Может кому пригодится гайд
модуль принимает данные в обычном формате.. На каждом модуле установлены сдвиговые регистры 74hc595 в количестве 16 штук.. Проще говоря мы должны вдувать на них перед зажиганием каждой строки данные - 0 чтобы зажечь светодиод и 1 чтобы он погас... 255 - эквивалент того, что ни один светодиод не будет включен, 128 = 0b10000000, тобиш будет гореть 7 светодиодов в линии... Далее: из буфера идут вышоды на дешифратор. Дешифратор зажигает через полевики строки. Всего 4 сдвоенных полевика, для управления 16 строчками.. Они запараллелены, иначе говоря зажигатеся одновременно 1,5,9,13 строки. Потом 2,6,10,14.. Смысл поняли в общем) Что нужно сделать: 1.Перевести OE в low. 2. Вдуть на сдвиговые регистры данные 3. при помощи дешифратора зажечь нужную строку (00,01, 10, 11 на выходы АВ) 4. Перевести OE в high. Сдвиговые регистры соединины последовательно, поэтому и изображение в массивах хранится построчно
Благодарю Очень понятно объяснил! Только почему 1 - не горит, 0 горит?? Я привык что 1 - true, 0 - false. Т.е. истина горит, ложь - ничего не происходит Этот вопрос просто из любопытства.
Здесь усе совсем просто.. Полевики у нас коммутируют +5 вольт. То есть, для зажигания строки целиком на нее подается плюс. Для передачи данных для столбцов используется микросхема 74HC595 - на выходе у нее при подаче 1 так же появляется +5вольт. Соответственно, чтобы светодиод, с одной стороны запитанный полевиком к +5, загорелся, на его второй выход необходимо подать логический 0 со сдвигового регистра
Вот вам немножко кода, правда на AVR GCC. Вывод на экран я делаю по второму таймеру.. Код (Text): ISR (TIMER2_COMP_vect) {int i; cnt_reg_tick_2++; if (cnt_reg_tick_2==12) { line++; //переменная, которая переключает строки if (line>3) line=0; //как только прошли четыре строки, возвращаемся на начало switch (line) { case 0x00 : DES_OE_low();//отключаем данные на дешифраторе ST_CP_low(); //отпускаем защелку данных на сдвиговом регистре for (i=0;i<32;i++) //я работаю с двумя модулями, кормлю по 8 бит (0xFF) 32 сдвиговых регистра { output_led_state(screenbuf[line][i]); //здесь мы выводим данные на первую строку } ST_CP_high();//выводим данные на регистр DES_A_low();//выставляем значения для включения первой строки DES_B_low(); DES_OE_high();//включаем полевики разрешив это на дешифраторе //DES_OE_low(); break; case 0x01 : DES_OE_low(); ST_CP_low(); for (i=0;i<32;i++) { output_led_state(screenbuf[line][i]); } ST_CP_high(); DES_A_high(); DES_B_low(); DES_OE_high(); break; case 0x02 : DES_OE_low(); ST_CP_low(); for (i=0;i<32;i++) { output_led_state(screenbuf[line][i]); } ST_CP_high(); DES_A_low(); DES_B_high(); DES_OE_high(); break; case 0x03 : DES_OE_low(); ST_CP_low(); for (i=0;i<32;i++) //for (i=32;i>-1;i--) { output_led_state(screenbuf[line][i]); } ST_CP_high(); DES_A_high(); DES_B_high(); DES_OE_high(); break; } cnt_reg_tick_2=0; // } Инициализация портов Код (Text): void port_init() { //ИНИЦИАЛИЗАЦИЯ ПОРТОВ ДЕШИФРАТОРА //НАСТРОЙКА ПИНОВ НА ВЫХОД DDRD |= 1<<6;//DES_A; DDRD |= 1<<7;//DES_B; DDRC |= 1<<2;//DES_OE; //DDRD |= 1<<5;//PWM; //РЕГУЛИРОВКА ЯРКОСТИ //УСТАНОВКА ПОРТОВ В НУЖНОЕ СОСТОЯНИЕ DES_A_low(); DES_B_low(); DES_OE_high(); //HIGH, АКТИВНЫЙ НОЛЬ // PORTD &= ~_BV(PD5); //HIGH, АКТИВНЫЙ НОЛЬ //КОНЕЦ НАСТРОЙКИ ДЕШИФРАТОРА //НАСТРОЙКА ПОРТОВ РЕГИСТРОВ СДВИГА DDRD |=1<<SH_CP_PIN; DDRB |=1<<DS_PIN; DDRB |=1<<ST_CP_PIN; DS_low(); ST_CP_low(); SH_CP_low(); //Конфигурирование входа радиоканала DDRD &= ~(1<<PD2); PORTD |=_BV(PD2); } Вывод на регистры сдвига Код (Text): void output_led_state(unsigned char __led_state) { SH_CP_low(); for (int i=0;i<8;i++)//пробегаем все 8 бит { if ((__led_state&0x80)==0x00) DS_low(); //проверяем, что выводится - 0 или 1 else DS_high(); SH_CP_high(); //дернем ногу, чтобы сказать SH_CP_low(); //регистру, что передача бита закончена __led_state=__led_state<<1;//сдвигаем данные на 1 бит } } Объявление выводов в хедер файле Код (Text): #define DES_A PORTD6 //порты дешифратора #define DES_B PORTD7 #define DES_OE PORTC2 //макроопределения #define DES_A_low() PORTD&=~_BV(DES_A) #define DES_A_high() PORTD|=_BV(DES_A) #define DES_B_low() PORTD&=~_BV(DES_B) #define DES_B_high() PORTD|=_BV(DES_B) #define DES_OE_low() PORTC&=~_BV(DES_OE) #define DES_OE_high() PORTC|=_BV(DES_OE) //Порты сдвигового регистра #define DS_PORT PORTB //пин на передачу данных #define DS_PIN 5 #define ST_CP_PORT PORTB //пин защелки #define ST_CP_PIN 7 #define SH_CP_PORT PORTD//пин сдвига на 1 бит #define SH_CP_PIN 4 #define DS_low() DS_PORT&=~_BV(DS_PIN) #define DS_high() DS_PORT|=_BV(DS_PIN) #define ST_CP_low() ST_CP_PORT&=~_BV(ST_CP_PIN) #define ST_CP_high() ST_CP_PORT|=_BV(ST_CP_PIN) #define SH_CP_low() SH_CP_PORT&=~_BV(SH_CP_PIN) #define SH_CP_high() SH_CP_PORT|=_BV(SH_CP_PIN)
Доброго времени суток! Подскажите как можно уменьшить расстояние между точками в цифровом секундомере в панели P10 вот куски. 0:00.00 или точи занимают строго размер цифр? #include <SPI.h> //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise) #include <DMD.h> #include <TimerOne.h> //#include "Arial_black_16.h" #include "SystemFont5x7.h" //#include "Small.h" #include <Bounce2.h #define DISPLAYS_ACROSS 3 #define DISPLAYS_DOWN 1 ________________________________________________________________________ //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker. Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI() dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on) // dmd.selectFont(Arial_Black_16); dmd.selectFont(SystemFont5x7); ____________________________________________________________________ void print_time2(unsigned long t_milli) { int days, hours, mins, secs; int fractime; unsigned long inttime; inttime = t_milli / 1000; fractime = t_milli % 100; days = inttime / (24*3600); inttime = inttime % (24*3600); hours = inttime / 3600; inttime = inttime % 3600; mins = inttime / 60; inttime = inttime % 60; secs = inttime; sprintf(buffer2, "%01d:%02d.%02d", mins, secs, fractime); dmd.drawString( 55,8, buffer2, 9, GRAPHICS_NORMAL ); }
Доброго времени суток! Подскажите как модно уменьшить расстояние между точками в цифровом секундомере в панели P10 вот куски. 0:00.00 или точи занимают строго размер цифр? что- бы влезло в 1 панель P10. #include <SPI.h> //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise) #include <DMD.h> #include <TimerOne.h> //#include "Arial_black_16.h" #include "SystemFont5x7.h" //#include "Small.h" #include <Bounce2.h #define DISPLAYS_ACROSS 3 #define DISPLAYS_DOWN 1 ________________________________________________________________________ //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker. Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI() dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on) // dmd.selectFont(Arial_Black_16); dmd.selectFont(SystemFont5x7); ____________________________________________________________________ void print_time2(unsigned long t_milli) { int days, hours, mins, secs; int fractime; unsigned long inttime; inttime = t_milli / 1000; fractime = t_milli % 100; days = inttime / (24*3600); inttime = inttime % (24*3600); hours = inttime / 3600; inttime = inttime % 3600; mins = inttime / 60; inttime = inttime % 60; secs = inttime; sprintf(buffer2, "%01d:%02d.%02d", mins, secs, fractime); dmd.drawString( 55,8, buffer2, 9, GRAPHICS_NORMAL ); }