LED экран, передача данных по COM порту
- Войдите на сайт для отправки комментариев
Здравствуйте.
Делаю себе что-то вроде светодиодного экрана разрешением 32x16 (на основе max7219).
Начало пока более или менее удачное, Arduino самостоятелно уже рисует картинки на этом экране (в черновом варианте). Но у меня в планах управлять этим экраном с компьютера, и вот на этом у меня возникли затруднения, т.к. я пока ещё начинающий в этом деле.
На данный момент что бы прорисовать весь экран нужно 64 байта данных, каждый байт это 1/2 столбца экрана (8 светодиодов)
Эти байты я предоставил в виде массива чисел (0..255)
Вопрос: Как правильно принять эти 64 байта (или массив из 64 цифр) с компьютера, и как правильно их отправит на ардуино желателно при помощи Processing...?
Вот код автономной работы:
#include <SPI.h>
int ic = 8; // количество микросхем
int IC_SELECT = 8;
int icbytes= ic*2;
byte spidata[16];
byte status[64];
//
#define OP_DECODEMODE 9
#define OP_INTENSITY 10
#define OP_SCANLIMIT 11
#define OP_SHUTDOWN 12
#define OP_DISPLAYTEST 15
void setup()
{
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
pinMode(IC_SELECT, OUTPUT);
digitalWrite(IC_SELECT, HIGH); //
Palitra();
for(int chip = 0; chip < ic; chip++) // выбор номера микросхемы
{
IcOff(chip, false); // включение микросхем
Yarkost(chip, 15); // яркость
}
}
void loop()
{
int shim = 15;
for(int i = 0; i < 16; i++)
{
int mass[64] = {143,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,60,199,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,30};
kadr(shim, mass); // передача данных в генератор кадра
delay(70);
int mass0[64] = {60,0,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,143,30,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,199};
kadr(shim, mass0);
delay(70);
int mass1[64] = {241,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,127,120,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,241};
kadr(shim, mass1);
delay(70);
int mass2[64] = {199,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,120,227,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,0,0,128,128,128,128,0,60};
kadr(shim, mass2);
delay(70);
//shim=shim--;
}
}
// ------------ Генератор кадра -----------------------------------
void kadr(int shim, byte byt[64])
{
int data = 0;
int offset;
for(uint8_t chip = 0; chip < ic; chip++) // выбор номера микросхемы
{
offset = chip*8;
for(uint8_t kol = 0; kol < 8; kol++) // выбор номера столбца
{
status[offset+kol]=byt[data];
// Yarkost(chip, shim); //яркость
// SPI_Data(chip, OP_INTENSITY,shim); //яркость напрямую
SPI_Data(chip, kol+1,status[offset+kol]);
data=data++;
}
}
}
// ----------- Подготовительный этап ----------------------------
void Palitra()
{
digitalWrite(IC_SELECT, LOW);
for(int i=0;i<64;i++) status[i]=0x00;
for(int i=0;i<ic;i++)
{
SPI_Data(i,OP_DISPLAYTEST,0);
//максимальное колличество столбцов в сегменте
SPI_Data(i,OP_SCANLIMIT,7);
//
SPI_Data(i,OP_DECODEMODE,0);
clDisplay(i);
//Выключение микросхем
IcOff(i,true);
}
digitalWrite(IC_SELECT, HIGH);
}
//-------------- Включение и выключение микросхемы --------------
void IcOff(int addr, bool b)
{
if(addr<0 || addr>=ic)
return;
if(b)
SPI_Data(addr, OP_SHUTDOWN,0);
else
SPI_Data(addr, OP_SHUTDOWN,1);
}
//------------ Яркость (ШИМ)------------------------------------
void Yarkost(int addr, int shim)
{
if(addr<0 || addr>=ic)
return;
if(shim>=0 || shim<16)
SPI_Data(addr, OP_INTENSITY,shim);
}
//-------------- Очистка микросхемы ------------------------------
void clDisplay(int addr)
{
int offset;
if(addr<0 || addr>=ic)
return;
offset=addr*8;
for(int i=0;i<8;i++) {
status[offset+i]=0;
SPI_Data(addr, i+1,status[offset+i]);
}
}
//------------- Передача данных в микросхему ---------------------
void SPI_Data(int addr, volatile byte opcode, volatile byte data) {
// Создание массива
int offset=addr*2;
for(int i=0;i<icbytes;i++)
spidata[i]=(byte)0;
//
spidata[offset+1]=opcode;
spidata[offset]=data;
// Разрешение записи
digitalWrite(IC_SELECT, LOW);
// в микр.
for(int i=icbytes;i>0;i--)
SPI.transfer(spidata[i-1]);
// Запрет записи
digitalWrite(IC_SELECT, HIGH);
}
А это я пытался принемать данные с терминала, картинка рисуется но не корректно:
...
void setup()
{
Serial.begin(115200);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
pinMode(IC_SELECT, OUTPUT);
digitalWrite(IC_SELECT, HIGH); //
Palitra();
for(int chip = 0; chip < ic; chip++) // выбор номера микросхемы
{
IcOff(chip, false); // включение дисплея
Yarkost(chip, 15); // 15 = яркость
}
}
int mass[64];
void loop()
{
if ( Serial.available() > 0 ) // проверяем, есть ли, что читать
{
for(int i = 0; i < 64; i++)
mass[i] = Serial.read();
}
Serial.flush();
kadr(10, mass);
}
...
Во- первых для экономии ОЗУ нужно обьявлять массивы типа byte, а не int (строки 35, 38, 41, 44) иначе у вас в памяти выделяется 128 байт, а вы используете только 64.
Во-вторых вы читаете из буфера UART данные, которые еще не пришли, то есть читаете мусор. Для того, что бы решить эту проблему, лучше всего дождаться пока все данные окажутся в буфере и после чего разом их считать оттуда
но для этого нужно увеличить размер буфера, здесь где-то недавно обсуждалось как это сделать.
Или можно поставить задержку при чтении данных
if (Serial.available()) { for(byte i = 0; i < 64; i++) { mass[i] = Serial.read(); delayMicroseconds(200); } }maksim, спасибо, у меня уже изменены масивы на тип byte и еще все for циклы имеют uint8_t
переменную.благодорю за коррекию кода... буду искать как увеличить буфер, я по возможности не хочу применять задержки типа delay ...
uint8_t и byte это одно и тоже.
Спасибо за информацию, я примерно так и предпологал, то что uint8_t вроде занимает байт в памяти так же как и Byte. как то раз стал применять uint8_t так до сих пор и пишу так, теперь вы развеили мои сомнения, буду прописывать Byte , так легче и короче...
Сейчас проверил применить задержку при чтении с порта вроде бы корректно воспринемает данные.
В Processing-е на компьютере пока прописал так:
port.write("jfvgfhgofdg ndrhgdhguhgtuhgihfg5tuhety89uhgt85ygtr9ght97hgg5y485");эти байты символов теперь корректно прочитал, до этого картинка могла прорисовыватся с беспорядочно любого места...
Прошу снова помощи и совета.
Пока я "творил" себе программу для управлением этого экрана с ПК, я решил что мне вовсе не нужна эта программа. Зачем мне тратить такое огромное количество ресурсов и электро энергии от ПК?, когда можно к ардуино подключить флешку и читать от туда нужные мне байты.
И следом у меня возник вопрос, хватит ли достаточно производительности микроконтролёру (и флешки) если одновременно к SPI будет подключено и экран и флешка с учетом обновления экрана примерно с периодом 100 милисекунд?
на флешке планирую разместить текстовый файл, а его содержимое будет из большого колличества строк из цифр разделённые запятыми или пробелами, каждая цифра это десятичное представление байта (0-255).
и возможно ли будет читать этот файл по строчно, к примеру прочитал строку - занес её в массив - после этот массив в экран и так по кругу, или нужно будет обязательно прочесть весь файл (на сколько хватит ОЗУ)?
Построчно и надо. Скорости шины хватитю
Правильно я реализовал построчное чтение или можно зделать как-то проще и еффективней? (пока строки вывожу в монитор com порта)
подключена библиотека SD...
int y = 0; void loop() { while (Serial.available()==0); int x = Serial.read() - '0'; if (x == 1) { myFile = SD.open("test.txt"); if (myFile) { myFile.seek(y); while (myFile.available() && myFile.peek() != '\n') { Serial.write(myFile.read()); y= myFile.position() + 1; } if (myFile.available() == 0) y = 0; myFile.close(); } else { Serial.println("errot"); } } }Вот что у меня получилось.
Может конечно многое у меня и не правильно сделано, но моя цель уже реализованна на 99%.
С флешки все читает, экран кадры показывает (даже намного быстрей обновляется чем я расчитывал) да и еще впридачу данные о кадре на COM порт отпровляет.
/* * SD * ** MOSI - pin 11 ** MISO - pin 12 ** CLK - pin 13 ** CS - pin 7 * LED * ** MOSI - pin 11 ** CLK - pin 13 ** CS - pin 8 */ #include <SD.h> #include <SPI.h> byte ic = 8; // количество микросхем byte spidata[16]; byte status[64]; byte SD_SELECT = 7; byte IC_SELECT = 8; byte maxbytes=ic*2; //the opcodes for the MAX7221 and MAX7219 #define OP_DECODEMODE 9 #define OP_INTENSITY 10 #define OP_SCANLIMIT 11 #define OP_SHUTDOWN 12 #define OP_DISPLAYTEST 15 byte error[64] = {0,0,0,0,0,0,0,0,0,0,102,207,219,243,102,0,129,255,255,195,231,126,0,0,0,0,0,0,0,0,0,0,0,60,82,82,76,0,0,126,4,2,2,4,0,126,4,2,2,4,0,0,60,66,66,60,0,0,126,4,2,2,4,0}; byte temp[64]; //= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; char buffer[256] ; File myFile; void setup() { Serial.begin(115200); //--------------------- SPI.begin(); pinMode(IC_SELECT, OUTPUT); digitalWrite(IC_SELECT, HIGH); // Palitra(); for(byte chip = 0; chip < ic; chip++) // выбор номера микросхемы { IcOff(chip, false); // включение дисплея Yarkost(chip, 15); // 15 = яркость } //------------------------------------- // while (!Serial) { } // Serial.print("Initializing SD card..."); //SD init... byte init[64] = {0,0,0,0,0,0,0,0,0,0,102,207,219,243,102,0,129,255,255,195,231,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,122,0,0,126,4,2,2,124,0,0,122,0,0,4,62,68,32,0,0,64,0,0,64,0,0,64,0,0}; kadr(10, init); if (!SD.begin(SD_SELECT)) { //Serial.println("initialization failed!"); kadr(10, error); // SD error delay(10000); for(byte chip = 0; chip < ic; chip++) // выбор номера микросхемы { Yarkost(chip, 1); // 1 = яркость } return; } // Serial.println("initialization done."); } //-------------------------------------------------------------------------------------- int y = 0; void loop() { byte shim = 10; FilStrToDig(); // открытие файла и чтение одной строки с занесением её в массив buffer с последующим её преобразованием в цифры в массив temp delay(40); kadr(shim, temp); // отправка массива temp на экран (кадр) } // ------------ Чтение строки с файла -------------------------------------- void FilStrToDig() { myFile = SD.open("test.txt"); if (myFile) { byte b = 0; myFile.seek(y); while (myFile.available() && myFile.peek() != '\n') { // Serial.write(myFile.read()); buffer[b++] = myFile.read(); } buffer[b++]='k'; y= myFile.position() + 1; if (myFile.available() == 0) y = 0; myFile.close(); } else { // Serial.println("error"); kadr(10, error); } String cifra; int a = 0; for (byte i =0; i < 64; i++) { cifra = ""; while (buffer[a] != ',') { cifra += String(buffer[a++]); } a=a++; temp[i] = cifra.toInt(); Serial.print(temp[i]); Serial.print(" "); } Serial.println(); // Serial.println(buffer); // Serial.println(); } // ------------ Генератор кадра ----------------------------------- void kadr(int shim, byte byt[64]) { int data = 0; int offset; for(byte chip = 0; chip < ic; chip++) // выбор номера микросхемы { offset = chip*8; for(byte kol = 0; kol < 8; kol++) // выбор номера столбца { status[offset+kol]=byt[data]; //Yarkost(chip, shim); //SPI_Data(chip, OP_INTENSITY,shim); SPI_Data(chip, kol+1,status[offset+kol]); //SPI_Data(chip, kol+1,x[data]); //Serial.println(byt[data], DEC); data=data++; } } } // ----------- Подготовительный этап ---------------------------- void Palitra() { digitalWrite(IC_SELECT, LOW); for(byte i=0;i<64;i++) status[i]=0x00; for(byte i=0;i<ic;i++) { SPI_Data(i,OP_DISPLAYTEST,0); //максимальное колличество столбцов в сегменте SPI_Data(i,OP_SCANLIMIT,7); // SPI_Data(i,OP_DECODEMODE,0); clDisplay(i); //Выключение микросхем IcOff(i,true); } digitalWrite(IC_SELECT, HIGH); } //-------------- Включение и выключение микросхемы -------------- void IcOff(byte addr, bool b) { if(addr<0 || addr>=ic) return; if(b) SPI_Data(addr, OP_SHUTDOWN,0); else SPI_Data(addr, OP_SHUTDOWN,1); } //------------ Яркость (ШИМ)------------------------------------ void Yarkost(byte addr, byte shim) { if(addr<0 || addr>=ic) return; if(shim>=0 || shim<16) SPI_Data(addr, OP_INTENSITY,shim); } //-------------- Очистка микросхемы ------------------------------ void clDisplay(byte addr) { int offset; if(addr<0 || addr>=ic) return; offset=addr*8; for(byte i=0;i<8;i++) { status[offset+i]=0; SPI_Data(addr, i+1,status[offset+i]); } } //------------- Передача данных в микросхему --------------------- void SPI_Data(byte addr, volatile byte opcode, volatile byte data) { byte offset=addr*2; for(byte i=0;i<maxbytes;i++) spidata[i]=(byte)0; spidata[offset+1]=opcode; spidata[offset]=data; digitalWrite(IC_SELECT, LOW); for(byte i=maxbytes;i>0;i--) //shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); SPI.transfer(spidata[i-1]); digitalWrite(IC_SELECT, HIGH); }Еще постараюсь что-нибудь оптимизировать, если соображу.
Спасибо огромное данному сайту и участникам форума за помощь в реализации моего проекта.
Если у кого есть желание покритиковать данный код, с удовольствием послушаю, и приму во внимание на будущее, хоть я и не программист, но есть желание хоть что-то освоить...
//------------- Передача данных в микросхему --------------------- void SPI_Data(byte addr, volatile byte opcode, volatile byte data) { byte offset=addr*2; for(byte i=0;i<maxbytes;i++) spidata[i]=(byte)0; spidata[offset+1]=opcode; spidata[offset]=data; digitalWrite(IC_SELECT, LOW); for(byte i=maxbytes;i>0;i--) //shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); SPI.transfer(spidata[i-1]); digitalWrite(IC_SELECT, HIGH); }Здравствуйте! Пытаюсь сделать что-то наподобие того что написано в этой теме, и пробую разобрать в коде последнего поста, вроде коекак понял что чего делает, вот только не понятно что происходит в строчке:
spidata[i]=(byte)0; почему и зачем перед нулём в скобках byte ?
spidata[i]=(byte)0; почему и зачем перед нулём в скобках byte ?
Явно указан тип.
Это как правило хорошего тона.
Можно в данном случае и просто писать spidata[i] = 0;
Спасибо. Вчера пол ночи спаивал микросхемы, только у меня их 4, а у автора помоему 8 штук, будет ли корректно работать данный код в таком случае? У меня после прошивки ардуинки данным скетчем на первом модуле max7219 ничего нет на в тором и третьем написано "SD" (только эти буквы у меня получились лёжа на спине, наверное придётся светодиоды перепаивать) и с определённой переодичностью меняется яркость.
И ещё мне не совсем понятно что именно нужно писать в текстовом файле?
Спасибо. Вчера пол ночи спаивал микросхемы, только у меня их 4, а у автора помоему 8 штук, будет ли корректно работать данный код в таком случае? У меня после прошивки ардуинки данным скетчем на первом модуле max7219 ничего нет на в тором и третьем написано "SD" (только эти буквы у меня получились лёжа на спине, наверное придётся светодиоды перепаивать) и с определённой переодичностью меняется яркость.
И ещё мне не совсем понятно что именно нужно писать в текстовом файле?
Работать на 4 микросхемах будет, но без незначительной корректировки кода не совсем правильно... То, что на экране написано SD - это часть текста (SD init... и SD error) просто на 4 модулях весь текст не умещается. А если у Вас SD постоянно на экране видно значит, есть какие-то проблемы с флэш картой. В текстовом файле нужно прописать строки такого формата: 0,128,256,...,1 - в вашем случае 32 цифры (в моём 64) разделённой запятой, одна строка = один кадр. Каждая цифра это байт данных в десятичном виде на один столбец светодиодов. Писать их в ручную это очень муторное дело, для создания файла эффектов у меня отдельно написана программа под Windows. После написания мною здесь последнего сообщения код программы уже не раз редактировался и добавлялось много дополнительных функций, мог бы разместить его здесь но увы, не смог найти у себя его, может уже и нет, т.к. данный проект у меня уже не на основе Arduino...
Спасибо большое
Долго мучался с текствым файлом, а оказывается у меня была не правильно подключена флешка, теперь всё получилось, перепаял светодиоды. Теперь подумываю докупить ещё 4 микросхемы - драйвера, на 4х както мало чего нарисуешь.