Всем привет. Ну вот почтьи доделал софтину по управлению кубом. Осталось только правильно принять данные. В общем формируется строка из 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(); } } } Но не загораются светодиоды - что не так?
Я могу выложить полностью код. Здесь формируется массив "кадров" для отображения светодиодов в кубе + заполнение массива films[x+f*64]; - координаты (значениями вида 0x80, 0x80 0x... и т.д. )
Код (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); } } Таким образом хочу формировать заполнение массива на ПК - т.е. сразу передавать значения байтов в ардуино.
1. А разве в PROGMEM можно просто так писать? Там и чтение только специальными функциями pgm_read_... А запись вроде вообще только из загрузчика (бутлоадер) доступна. 2. Недавно сам наступил на эти грабли. Если очень быстро что-то пытаться передать через последовательный порт, то буфер может просто переполниться, и часть данных в таком случае пропадает.
А как же тогда реализовать загрузку данных в arduino uno с отображением ?? Я формирую последовательно на ПК, а туда загружать допустим массив байт по 64. В исходнике у меня в progmem заранее все готово, но я это хочу занести наоборот во внешнюю программу.
Вот Ваш код, но с отступами, Вы зря недооцениваете их мощь. Код (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'. Вопрос как часто Вы хотите отправлять этот массив.
1. Я вижу решением запись массива на SD карту и подгрузку его с SD карты при отображении. Второе решение существенно сложнее - модифицировать боотлоадер таким образом, чтобы из него можно было вызывать функцию записи в progmem (или найти способ вызвать существующую, ведь в боотлоадере уже есть механизм записи скетча, полученного по последовательному порту?). .Если не ошибаюсь, при этом надо учитывать, что запись там идет не байтами, а страницами в некоторое количество байт. Т.е. при изменении байта придется считывать всю страницу, изменять в ней байт, стирать страницу и записывать обратно. 2. Через последовательный порт следует отправлять небольшими порциями, делая паузу либо на некоторое количество миллисекунд (в зависимости от выставленной скорости порта и размера порции: количество байт в порции *15*1000/скорость), либо до получения квитанции о полном приеме порции.
Увеличенный буфер тоже переполнить можно. Увеличение буфера позволит лишь увеличить размер блока (порции), передаваемого за один раз. И не стоит забывать, что буфер, который можно переполнить, есть с обеих сторон, как с передающей, так и с принимающей.
Со стороны ПК переполнить сложно. Просто функция отправки будет ждать до тех пор, пока все данные не уйдут, да и буферы со стороны ПК имеют размер побольше, чем в ардуино. А со стороны приема можно увеличить размер буфера до размеров пакета передаваемых данных (если пакет не сильно большой) и на приеме ждать, пока available() не вернет размер пакета. Конечно правильнее принимать мелкими пачками до накопления пакета, но если память позволяет и лень отлаживать прием, то увеличение размера буфера тоже вполне вариант.
Так правильно поправил код в моем случае? Код (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(); } } }
Вот собственно код отправки байт на 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;
Да, после finishReceiveData можно обрабатывать данные. Но у Вас ошибка. receiveSizeArrayCOM равен 65, у receiveCharArrayCOM размерность 65, от 0 до 64. Да и просто не понятно, что Вы делаете. Всем films от 0 до 65 будет присвоен один и тот же элемент. Теперь, что такое films, если const byte films[] PROGMEM, то и тут будет ошибка, во первых константы, а во вторых еще и PROGMEM. К тому же, я до конца не понимаю, что Вы делаете. Если управление с компьютера Led, это одно. Если Вы просто программируете Led 1 раз и потом отключаете, а дальше он живет своей жизнью, это совсем другое (тогда мой вариант не подходит).
Это светодиодный куб размерной 8х8х8. Т.е. я генерирую последовательность байт на пк и заливаю в arduino. C Progmem - все хорошо, но количество эффектов может быть в разы больше чем размер этого progmem. Моя идея и заклюдчалась в заполнении массива films через com порт по 64 байта. Начало кадра имеет байт F2
Это я понимаю, просто не правильно выразился, назвав это LED. Получается вариант 1, управлением через com порт поведением куба. Заполнить массив, не проблема. Просто в цикле for скопировать receiveCharArrayCOM в другой, как у Вас в коде. А вот заполнить и менять массив констант - const byte films[] PROGMEM, не представляю как. Константы менять нельзя, да и PROGMEM нужно объявлять заранее, чтобы на этапе компиляции ардуино знала куда сохранять константы. О чем уже сказал geher. Раз Вы работаете с байтами, то лучше приводить не к char (как у меня в коде), а к byte. Речь об этом Код (Text): char incomingChar = (char)Serial.read(); Так же подумайте, как часто Вы будете посылать данные. Если очень часто, то может необходимо будет выставить временной интервал или отправлять после получения данных сообщение о принятии пакета. На Делфи ни когда не писал. На C# делал, посмотрю в архивах, если найду опубликую.
Да сам progmem можно не использовать - я в него просто загрузил почти 1500 байтов заранее сгенеренного кода. Сейчас я наоборот хочу от него уйти - ПК это и есть progmem )) Ардуино получает байты, заполняет массив по 64 байта , может даже лучше по 128 (2 кадра, так сказать) и зажигать светодиоды. Может я и ошибась в неиспользовании progmem -в интернет пока инфы не нашел толковой
Использовать 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 Я не представляю изменение памяти программы на лету.