LED экран, передача данных по COM порту

led
Offline
Зарегистрирован: 04.11.2012

Здравствуйте.

Делаю себе что-то вроде светодиодного экрана разрешением 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);
}

      ...

 

maksim
Offline
Зарегистрирован: 12.02.2012

Во- первых для экономии ОЗУ нужно обьявлять массивы типа byte, а не int (строки 35, 38, 41, 44) иначе у вас в памяти выделяется 128 байт, а вы используете только 64.

Во-вторых вы читаете из буфера UART данные, которые еще не пришли, то есть читаете мусор. Для того, что бы решить эту проблему, лучше всего дождаться пока все данные окажутся в буфере и после чего разом их считать оттуда

if (Serial.available()  > 63) // проверяем, накопились ли 64 байта

но для этого нужно увеличить размер буфера, здесь где-то недавно обсуждалось как это сделать.
Или можно поставить задержку при чтении данных

 if (Serial.available())  {
        for(byte i = 0; i < 64; i++) {
           mass[i] = Serial.read();
           delayMicroseconds(200);
        }
   }

 

led
Offline
Зарегистрирован: 04.11.2012

maksim,  спасибо,  у меня уже изменены масивы на тип byte и еще все for циклы имеют uint8_t переменную.

благодорю за коррекию кода... буду искать как увеличить буфер, я по возможности не хочу применять задержки типа delay ...

maksim
Offline
Зарегистрирован: 12.02.2012
led
Offline
Зарегистрирован: 04.11.2012

Спасибо за информацию, я примерно так и предпологал, то что uint8_t вроде занимает байт в памяти так же как и Byte. как то раз стал применять uint8_t так до сих пор и пишу так, теперь вы развеили мои сомнения, буду прописывать Byte , так легче и короче...

Сейчас проверил применить задержку при чтении с порта вроде бы корректно воспринемает данные.

В Processing-е на компьютере пока прописал так:

port.write("jfvgfhgofdg ndrhgdhguhgtuhgihfg5tuhety89uhgt85ygtr9ght97hgg5y485");

эти байты символов теперь корректно прочитал, до этого картинка могла прорисовыватся с беспорядочно любого места...

led
Offline
Зарегистрирован: 04.11.2012

Прошу снова помощи и совета.

Пока я "творил" себе программу для управлением этого экрана с ПК, я решил что мне вовсе не нужна эта программа. Зачем мне тратить такое огромное количество ресурсов и электро энергии от ПК?, когда можно к ардуино подключить флешку и читать от туда нужные мне байты.

И следом у меня возник вопрос, хватит ли достаточно производительности микроконтролёру (и флешки) если одновременно к SPI будет подключено и экран и флешка с учетом обновления экрана примерно с периодом 100 милисекунд?

на флешке планирую разместить текстовый файл, а его содержимое будет из большого колличества строк из цифр разделённые запятыми или пробелами, каждая цифра это десятичное представление байта (0-255).

и возможно ли будет читать этот файл по строчно, к примеру прочитал строку - занес её в массив - после этот массив в экран и так по кругу, или нужно будет обязательно прочесть весь файл (на сколько хватит ОЗУ)?

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Построчно и надо. Скорости шины хватитю

led
Offline
Зарегистрирован: 04.11.2012

Правильно я реализовал построчное чтение или можно зделать как-то проще и еффективней? (пока строки вывожу в монитор 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");
     }
  } 

}

 

led
Offline
Зарегистрирован: 04.11.2012

Вот что у меня получилось.

Может конечно многое у меня и не правильно сделано, но моя цель уже реализованна на 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);
 }  

Еще постараюсь что-нибудь оптимизировать, если соображу.

Спасибо огромное данному сайту и участникам форума за помощь в реализации моего проекта.

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

ardunchik
Offline
Зарегистрирован: 01.11.2013

	 //------------- Передача данных в микросхему ---------------------
	 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 ?

Looka
Offline
Зарегистрирован: 24.04.2012

ardunchik пишет:

spidata[i]=(byte)0; почему и зачем перед нулём в скобках byte ?

 

Явно указан тип.    
Это как правило хорошего тона. 

Можно в данном случае  и просто писать spidata[i] = 0;   

ardunchik
Offline
Зарегистрирован: 01.11.2013

Спасибо. Вчера пол ночи спаивал микросхемы, только у меня их 4, а у автора помоему 8 штук, будет ли корректно работать данный код в таком случае? У меня после прошивки ардуинки данным скетчем на первом модуле max7219 ничего нет на в тором и третьем написано "SD" (только эти буквы у меня получились лёжа на спине, наверное придётся светодиоды перепаивать) и с определённой переодичностью меняется яркость.

И ещё мне не совсем понятно что именно нужно писать в текстовом файле?

led
Offline
Зарегистрирован: 04.11.2012

ardunchik пишет:

Спасибо. Вчера пол ночи спаивал микросхемы, только у меня их 4, а у автора помоему 8 штук, будет ли корректно работать данный код в таком случае? У меня после прошивки ардуинки данным скетчем на первом модуле max7219 ничего нет на в тором и третьем написано "SD" (только эти буквы у меня получились лёжа на спине, наверное придётся светодиоды перепаивать) и с определённой переодичностью меняется яркость.

И ещё мне не совсем понятно что именно нужно писать в текстовом файле?

Работать на 4 микросхемах будет, но без незначительной корректировки кода не совсем правильно... То, что на экране написано SD - это часть текста (SD init... и SD error) просто на 4 модулях весь текст не умещается. А если у Вас SD постоянно на экране видно значит, есть какие-то проблемы с флэш картой. В текстовом файле нужно прописать строки такого формата: 0,128,256,...,1 - в вашем случае 32 цифры (в моём 64) разделённой запятой, одна строка = один кадр. Каждая цифра это байт данных в десятичном виде на один столбец светодиодов. Писать их в ручную это очень муторное дело, для создания файла эффектов у меня отдельно написана программа под Windows. После написания мною здесь последнего сообщения код программы уже не раз редактировался и добавлялось много дополнительных функций, мог бы разместить его здесь но увы, не смог найти у себя его, может уже и нет, т.к. данный проект у меня уже не на основе Arduino...

ardunchik
Offline
Зарегистрирован: 01.11.2013

Спасибо большое

Долго мучался с текствым файлом, а оказывается у меня  была не правильно подключена флешка, теперь всё получилось, перепаял светодиоды. Теперь подумываю докупить ещё 4 микросхемы - драйвера, на 4х както мало чего нарисуешь.