Помгите принять данные через COM порт

Тема в разделе "Микроконтроллеры AVR", создана пользователем Максим B, 26 июл 2015.

  1. Максим B

    Максим B Гуру

    Всем привет. Ну вот почтьи доделал софтину по управлению кубом. Осталось только правильно принять данные. В общем формируется строка из 64 элементов и передается в com порт. В сериал -мониторе данные появляются. На стороне ардуино принимаю таким образов в массив
    Код (Text):

    void loop()
    {
     
     int i = 0;
        while (Serial.available())            //если есть что читать
        {
            delay(1);
            films[i] = Serial.read();     //читаем символ в массив
                                              //если считали символ переноса каретки (строка закончилась)
            i++;
        }
       
        for (f=0; f<cadr; f++){
        for (x=0; x<=63; x++){
       MyMassive[x]=films[x+f*64];
       //  Serial.println(films[x]);
    }
       
       for (s=0; s<=slow; s++)
       {
       myMultiplyFunction();
     }
    }
    }
     
    Но не загораются светодиоды - что не так?
     
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    Этот кусок вообще непонятно что должен делать. Сформулируйте сперва задачу, тогда и разберемся.
     
  3. Максим B

    Максим B Гуру

    Я могу выложить полностью код. Здесь формируется массив "кадров" для отображения светодиодов в кубе + заполнение массива films[x+f*64]; - координаты (значениями вида 0x80, 0x80 0x... и т.д. )
     
  4. Максим B

    Максим B Гуру

    Код (Text):

    //Пин подключен к ST_CP входу 74HC595
    int latchPin = 3;
    //Пин подключен к SH_CP входу 74HC595
    int clockPin = 2;
    //Пин подключен к DS входу 74HC595
    int dataPin = 4;

    const int cadr=41;
    const int speeds=100;
    const int slow=0; // минимально 0

    int s;

    int myPins[] = {6, 7, 8, 9, 10, 11, 12, 13};   //массив пинов - выходы для строк

    byte MyMassive[64];  //массив диодов
    byte Massive[8]={1,2,4,8,16,32,64,128};
    const byte films[] PROGMEM={
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,    //block
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    ...................

     };

    int i,j,x,y,z,f,ff,fff;
    byte a,aa,bb,b,ab,c,cc;
     
    void setup() {
     
    //    Serial.begin(9600);
        a,aa,b,bb=0;
      //устанавливаем режим OUTPUT
      pinMode(latchPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      pinMode(dataPin, OUTPUT);
       
      for (i = 0; i <=7; i++) {   //столбы
      pinMode(myPins[i],OUTPUT);
     
       digitalWrite(latchPin, LOW);
        // передаем последовательно на dataPin
       
         }
     }

    void loop()
    {
      for (f=0; f<cadr; f++){
        for (x=0; x<=63; x++){
       MyMassive[x]=pgm_read_byte_near(&films[x+f*64]);
       //  Serial.println(films[x]);
    }
       
       for (s=0; s<=slow; s++)
       {
       myMultiplyFunction();
     }
    }
    }


    byte myMultiplyFunction(){
      // устанавливаем синхронизацию "защелки" на LOW
           
         for(j=0; j<=7; j++)
         {   //этаж
           for(z=0; z<=7; z++)
           {
                shiftOut(dataPin, clockPin, MSBFIRST, MyMassive[z+(j*8)]);
           //       shiftOut(dataPin, clockPin, MSBFIRST, (z+(j*8)));
            //    Serial.println (MyMassive[z+(j*8)]);
                        //"защелкиваем" регистр, тем самым устанавливая значения на выходах
           }
         
        digitalWrite(latchPin, HIGH);
        // пауза перед следующей итерацией
      //  delay(1);
        digitalWrite(latchPin, LOW);
        // передаем последовательно на dataPin
       
        digitalWrite(myPins[j], HIGH);
        delay(speeds);               // wait for a second
        digitalWrite(myPins[j], LOW);    // turn the LED off by making the voltage LOW
     //   delay(1000);        
       
         }
    }


     
    Таким образом хочу формировать заполнение массива на ПК - т.е. сразу передавать значения байтов в ардуино.
     
  5. geher

    geher Гуру

    1. А разве в PROGMEM можно просто так писать? Там и чтение только специальными функциями pgm_read_...
    А запись вроде вообще только из загрузчика (бутлоадер) доступна.
    2. Недавно сам наступил на эти грабли.
    Если очень быстро что-то пытаться передать через последовательный порт, то буфер может просто переполниться, и часть данных в таком случае пропадает.
     
  6. Максим B

    Максим B Гуру

    А как же тогда реализовать загрузку данных в arduino uno с отображением ?? Я формирую последовательно на ПК, а туда загружать допустим массив байт по 64. В исходнике у меня в progmem заранее все готово, но я это хочу занести наоборот во внешнюю программу.
     
  7. Alex19

    Alex19 Гуру

    Вот Ваш код, но с отступами, Вы зря недооцениваете их мощь.

    Код (Text):

    //Пин подключен к ST_CP входу 74HC595
    int latchPin = 3;
    //Пин подключен к SH_CP входу 74HC595
    int clockPin = 2;
    //Пин подключен к DS входу 74HC595
    int dataPin = 4;

    const int cadr=41;
    const int speeds=100;
    const int slow=0; // минимально 0

    int s;

    int myPins[] = {6, 7, 8, 9, 10, 11, 12, 13};   //массив пинов - выходы для строк

    byte MyMassive[64];  //массив диодов
    byte Massive[8]={1,2,4,8,16,32,64,128};
    const byte films[] PROGMEM={
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,    //block
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
    };

    int i,j,x,y,z,f,ff,fff;
    byte a,aa,bb,b,ab,c,cc;

    void setup() {

        //    Serial.begin(9600);
        a,aa,b,bb=0;
        //устанавливаем режим OUTPUT
        pinMode(latchPin, OUTPUT);
        pinMode(clockPin, OUTPUT);
        pinMode(dataPin, OUTPUT);

        for (i = 0; i <=7; i++) //столбы
        {
            pinMode(myPins[i],OUTPUT);

            digitalWrite(latchPin, LOW);
            // передаем последовательно на dataPin

        }
    }

    void loop()
    {
        for (f=0; f<cadr; f++)
        {
            for (x=0; x<=63; x++)
            {
                MyMassive[x]=pgm_read_byte_near(&films[x+f*64]);
                //  Serial.println(films[x]);
            }

            for (s=0; s<=slow; s++)
            {
                myMultiplyFunction();
            }
        }
    }


    byte myMultiplyFunction(){
        // устанавливаем синхронизацию "защелки" на LOW

        for(j=0; j<=7; j++)
        {   //этаж
            for(z=0; z<=7; z++)
            {
                shiftOut(dataPin, clockPin, MSBFIRST, MyMassive[z+(j*8)]);
                //       shiftOut(dataPin, clockPin, MSBFIRST, (z+(j*8)));
                //    Serial.println (MyMassive[z+(j*8)]);
                //"защелкиваем" регистр, тем самым устанавливая значения на выходах
            }

            digitalWrite(latchPin, HIGH);
            // пауза перед следующей итерацией
            //  delay(1);
            digitalWrite(latchPin, LOW);
            // передаем последовательно на dataPin

            digitalWrite(myPins[j], HIGH);
            delay(speeds);               // wait for a second
            digitalWrite(myPins[j], LOW);    // turn the LED off by making the voltage LOW
            //   delay(1000);  

        }
    }
     
    И так функция loop, в ней for (f=0; f<cadr; f++), card равна 41, будет 41 цикл, от 0 до 40.
    Внутри идет for (x=0; x<=63; x++), тут будет 64 цикла, от 0 до 63.

    А в ней, интересная строка
    Код (Text):
    MyMassive[x]=pgm_read_byte_near(&films[x+f*64]);
    Значение x+f*64 будет равно от 0 до 2623. А сколько элементов содержит films?

    У Вас
    Код (Text):
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

        ...................
    Эти многоточия, что это, ошибка вставки или Вы опустили часть кода?

    Ну и конечно отладка, закомментируйте ее, оставив часть, проверьте (с помощью того же Serial), раскомментируйте еще часть и т.д.

    Прием и отправка данных, уже сплю и не понимаю проблемы, примеров тьма, вот еще 1 в копилку
    Код (Text):

    #define speedSerial 115200

    #define newLine '\n'

    #define clearChar '\0'

    boolean finishReceiveData = false;

    int indexCharInArray;

    #define receiveSizeArrayCOM 65

    char receiveCharArrayCOM[receiveSizeArrayCOM];

    void setup ()
    {
        Serial.begin(speedSerial);

    }

    void loop()
    {
        GetReceiveDataFromSerial();

        // Завершено ли получения данных
        if (finishReceiveData)
        {
            // Парсинг полученных данных
            //ParseReceiveData();

            Serial.println(receiveCharArrayCOM);

            ClearReceiveDataVariable();
        }
    }

    void GetReceiveDataFromSerial()
    {
        while(Serial.available())
        {
            char incomingChar = (char)Serial.read();

            if(incomingChar != newLine &&
                incomingChar != clearChar)
            {
                receiveCharArrayCOM[indexCharInArray] = incomingChar;
                indexCharInArray++;
            }
            else
            {
                receiveCharArrayCOM[indexCharInArray] = clearChar;

                finishReceiveData = true;
            }
        }
    }

    void ClearReceiveDataVariable()
    {
        indexCharInArray = 0;
        memset(receiveCharArrayCOM,clearChar,receiveSizeArrayCOM);
        finishReceiveData = false;
    }
     
    Требует в конце сообщения символ новой строки. В Arduino IDE, в мониторе порта, справа внизу, перед указанием скорости укажите - Новая строка (NL).

    В своей программе просто добавляйте в конец сообщения '/n'.

    Вопрос как часто Вы хотите отправлять этот массив.
     
    Последнее редактирование: 27 июл 2015
    Максим B нравится это.
  8. geher

    geher Гуру

    1. Я вижу решением запись массива на SD карту и подгрузку его с SD карты при отображении.

    Второе решение существенно сложнее - модифицировать боотлоадер таким образом, чтобы из него можно было вызывать функцию записи в progmem (или найти способ вызвать существующую, ведь в боотлоадере уже есть механизм записи скетча, полученного по последовательному порту?). .Если не ошибаюсь, при этом надо учитывать, что запись там идет не байтами, а страницами в некоторое количество байт. Т.е. при изменении байта придется считывать всю страницу, изменять в ней байт, стирать страницу и записывать обратно.

    2. Через последовательный порт следует отправлять небольшими порциями, делая паузу либо на некоторое количество миллисекунд (в зависимости от выставленной скорости порта и размера порции: количество байт в порции *15*1000/скорость), либо до получения квитанции о полном приеме порции.
     
    Максим B нравится это.
  9. Максим B

    Максим B Гуру

    Многоточия это я убрал часть кода конечно же )))
     
  10. Megakoteyka

    Megakoteyka Оракул Модератор

    Можно еще увеличить размер приемного буфера для порта, если память позволяет.
     
  11. geher

    geher Гуру

    Увеличенный буфер тоже переполнить можно. Увеличение буфера позволит лишь увеличить размер блока (порции), передаваемого за один раз.
    И не стоит забывать, что буфер, который можно переполнить, есть с обеих сторон, как с передающей, так и с принимающей.
     
  12. Megakoteyka

    Megakoteyka Оракул Модератор

    Со стороны ПК переполнить сложно. Просто функция отправки будет ждать до тех пор, пока все данные не уйдут, да и буферы со стороны ПК имеют размер побольше, чем в ардуино.
    А со стороны приема можно увеличить размер буфера до размеров пакета передаваемых данных (если пакет не сильно большой) и на приеме ждать, пока available() не вернет размер пакета.
    Конечно правильнее принимать мелкими пачками до накопления пакета, но если память позволяет и лень отлаживать прием, то увеличение размера буфера тоже вполне вариант.
     
  13. Максим B

    Максим B Гуру



    Так правильно поправил код в моем случае?
    Код (Text):

    void loop()
    {
     
       GetReceiveDataFromSerial();

        // Завершено ли получения данных
        if (finishReceiveData)
        {
            for (i=0; i<=64; i++)
            {
              films[i]=receiveCharArrayCOM[receiveSizeArrayCOM];
            }
           
            for (f=0; f<cadr; f++){
            for (x=0; x<=63; x++){
            MyMassive[x]=films[x+f*64];

           // Serial.println(receiveCharArrayCOM);

            ClearReceiveDataVariable();
        }
       }
    }
     
     
  14. Максим B

    Максим B Гуру

    Вот собственно код отправки байт на delphi - sdpo -сторонняя библиотека по работе с ком-портом
    Код (Text):

    procedure TForm1.Button1Click(Sender: TObject);
    var
    i,j:integer;
    str: string;
    buf: integer;
    begin
      if RadioButton1.Checked=true then SdpoSerial1.BaudRate:=br__9600;
      if RadioButton2.Checked=true then SdpoSerial1.BaudRate:=br115200;


      SdpoSerial1.Device:=ComboBox1.Text;
      SdpoSerial1.Active:=true;

      SdpoSerial1.Open;

      for i:=0 to 7 do
      for j:=0 to 7 do
      begin
          buf:=StrToInt('$'+StringGrid25.Cells[j,i]);
          SdpoSerial1.WriteData(IntToStr(buf));
      end;
          SdpoSerial1.Active:=false;

      end;
                 
     
     
  15. Alex19

    Alex19 Гуру

    Да, после finishReceiveData можно обрабатывать данные.

    Но у Вас ошибка.
    receiveSizeArrayCOM равен 65, у receiveCharArrayCOM размерность 65, от 0 до 64.

    Да и просто не понятно, что Вы делаете. Всем films от 0 до 65 будет присвоен один и тот же элемент.

    Теперь, что такое films, если const byte films[] PROGMEM, то и тут будет ошибка, во первых константы, а во вторых еще и PROGMEM.

    К тому же, я до конца не понимаю, что Вы делаете. Если управление с компьютера Led, это одно. Если Вы просто программируете Led 1 раз и потом отключаете, а дальше он живет своей жизнью, это совсем другое (тогда мой вариант не подходит).
     
    Последнее редактирование: 28 июл 2015
  16. Максим B

    Максим B Гуру

    Это светодиодный куб размерной 8х8х8. Т.е. я генерирую последовательность байт на пк и заливаю в arduino. C Progmem - все хорошо, но количество эффектов может быть в разы больше чем размер этого progmem. Моя идея и заклюдчалась в заполнении массива films через com порт по 64 байта. Начало кадра имеет байт F2
     
    Последнее редактирование: 28 июл 2015
  17. Alex19

    Alex19 Гуру

    Это я понимаю, просто не правильно выразился, назвав это LED.

    Получается вариант 1, управлением через com порт поведением куба.

    Заполнить массив, не проблема. Просто в цикле for скопировать receiveCharArrayCOM в другой, как у Вас в коде.
    А вот заполнить и менять массив констант - const byte films[] PROGMEM, не представляю как. Константы менять нельзя, да и PROGMEM нужно объявлять заранее, чтобы на этапе компиляции ардуино знала куда сохранять константы. О чем уже сказал geher.

    Раз Вы работаете с байтами, то лучше приводить не к char (как у меня в коде), а к byte. Речь об этом
    Код (Text):
    char incomingChar = (char)Serial.read();
    Так же подумайте, как часто Вы будете посылать данные. Если очень часто, то может необходимо будет выставить временной интервал или отправлять после получения данных сообщение о принятии пакета.

    На Делфи ни когда не писал.
    На C# делал, посмотрю в архивах, если найду опубликую.
     
    Последнее редактирование: 28 июл 2015
  18. Максим B

    Максим B Гуру

    Да сам progmem можно не использовать - я в него просто загрузил почти 1500 байтов заранее сгенеренного кода. Сейчас я наоборот хочу от него уйти - ПК это и есть progmem )) Ардуино получает байты, заполняет массив по 64 байта , может даже лучше по 128 (2 кадра, так сказать) и зажигать светодиоды. Может я и ошибась в неиспользовании progmem -в интернет пока инфы не нашел толковой
     
  19. Alex19

    Alex19 Гуру

    Использовать progmem Вы не сможете.

    Можно почитать.
    Оф. - https://www.arduino.cc/en/Reference/PROGMEM
    По русски - http://mk90.org/wiki/index.php/PROGMEM
    В контексте AVR - http://microsin.net/programming/AVR/avrstudio-gcc-progmem.html

    Я не представляю изменение памяти программы на лету.
     
    Максим B нравится это.