А не проще взять MODBUS и ничего ждать и парсить не придётся. Данные по приходу сами будут складываться в нужные ячейки памяти? Заодно имеем проверку на целостность пакета. Да и посылать можно адресно, например по одному значению. Порог входа в MODBUS на ардуино достаточно низок.
Входите в луп, смотрите сколько символов пришло. Допустим прийти успело 26 (один ещё не успел). Поскольку их не 27, Вы выбрасываете их и "делаете всё как раньше". При следующем лупе приходит не успевший в прошлый раз 27-ой символ. Поскольку символов опять не 27, а один, Вы и его выбрасываете и "делаете всё как раньше".
Правильно, Вам так надо?
Вот что значит профи! Три слова, и "мысь по древу" сформулирована! Спасибо, именно это мне и было надо. Понял сразу всё. Буду думать дальше. Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь). Наконец добрался до платы. Поковыряюсь, думаю большая часть вопросов отвалится на практике. Что останется - приду снова сюда.
Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь).
нет, так не надо делать. Лови. Сообщение применяются такого вида:
AA 55 XX байты полезной нагрузки CS
где АА и 55 старт байты, XX - байт длины сообщения, CS - контрольная сумма (простое сложение, для увеличения надёжности можно взять далласовский CRC)
#define BUS Serial // UART на котором висит наша шина
byte meSS[] = {1,2,3,4,5,1,8,9,0,0,0,0,123,123,156,255}; // сообщение для примера
const bool echo = 0; // делаем тут 1 , если шина имеет эхо (когда отправленные байты сразу появляются в приёмнике, например к-лайн)
const byte bufsize = 150; // размер буфера принятого сообщения
static byte buf [bufsize] = {0}; // буфер принятого сообщения
uint32_t currmillis = 0; // таймер системного времени
void setup()
{
BUS.begin(9600);
sendMessage (meSS, sizeof(meSS)); // отправляем сообщение в шину для примера
pinMode (13, OUTPUT);
}
void loop()
{
currmillis = millis(); // снимок системного времени
BUSread(); // читаем шину
digitalWrite(13, buf[3]); // например из байта буфера принятого сообщения рулим диодом
}
void messageOKreceived()
{
// ТУТ ДЕЛАЕМ ЧТО-ТО НУЖНОЕ, например только когда СООБЩЕНИЕ УСПЕШНО ПРИНЯТО!
}
void sendMessage(const byte *payload, const size_t size)
{
const byte siZe = size+4;
byte Mes[siZe];
byte Checksum = 0;
for(byte i=0; i<siZe; i++)
{
if (i==0) {Mes[i] = 0xAA;}
if (i==1) {Mes[i] = 0x55;}
if (i==2) {Mes[i]=size;}
if (i==3)
{
for (byte t=0; t<size; t++ )
{
Mes[i]=payload[t]; Checksum+=Mes[i]; BUS.write (Mes[i]);
if (echo) BUS.read();
i++;
}
}
if (i!=siZe-1) Checksum+=Mes[i];
else Mes[i] = Checksum;
BUS.write (Mes[i]); if (echo) BUS.read();
}
}
void BUSread()
{
static byte header = 0; // состояние заголовка
static byte message_size = 0; // размер тела принимаемого сообщения, кол-во байт
static byte j = 3; // инкремент
static byte checksum = 0; // контрольная сумма входящего сообщения
static uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
static bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
if (BUS.available()){
// первый старт байт
if (header == 0)
{
buf[0]=BUS.read();
if (buf[0] == 0xAA){header = 1; RESETheader_timer=1; prevRESETheader = currmillis; }
}
// второй старт байт
else if (header == 1)
{
buf[1]=BUS.read();
if (buf[1]==0x55){ header = 2;} else {header = 0; RESETheader_timer=0;}
}
// третий старт байт
else if (header == 2)
{
buf[2]=BUS.read();
message_size = buf[2];
header = 4; checksum = 0;
if (message_size>bufsize){header = 0; RESETheader_timer=0;}
}
// пишем тело сообщения
else if (header == 4 && j< message_size+4)
{
buf[j] = BUS.read();
if (j<message_size+3) checksum+= buf[j]; // подсчёт КС
if (j==message_size+3) header = 5;
j++;
}
} // end of BUS.available()
// сообщение приняли, действуем
if (header == 5)
{
for(byte i = 0; i<3; i++) checksum+=buf[i]; // прибавляем к контрольной сумме старт байты
// если контрольная сумма верна:
if (buf[message_size+3] == checksum)
{
// распечатаем сообщение в отладку
for (int g = 0; g < message_size+4; g++) {BUS.print(buf[g], HEX); BUS.print(F(" "));}
BUS.println();
messageOKreceived(); // ТУТ ДЕЛАЕМ ЧТО-ТО НУЖНОЕ, ПОТОМУ ЧТО СООБЩЕНИЕ УСПЕШНО ПРИНЯТО!
}
// если контрольная сумма не совпала:
else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer=0; j=3; checksum = 0;
}
// таймер сброса сборки пакета, если данные перестали поступать более чем полсекунды
if (RESETheader_timer && currmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}
}
Sonologist пишет:
........ просто проверять Serial.avalable () на наличие чего-то в порту, и если есть - выполнять программу с новыми параметрами, а если нет - продолжать это делать со старыми. ........
вот и выполняйте свою программу с параметрами, которые будут поступать от ПК в созданный буфер buf . Если с ПК пришло сообщение, этот buf уже будет "с новыми параметрами", если не пришло - будет "продолжать это делать со старыми". Только само собой на ПК нужно упаковывать данные по тем же правилам.
А не проще взять MODBUS и ничего ждать и парсить не придётся. Данные по приходу сами будут складываться в нужные ячейки памяти? Заодно имеем проверку на целостность пакета. Да и посылать можно адресно, например по одному значению. Порог входа в MODBUS на ардуино достаточно низок.
Входите в луп, смотрите сколько символов пришло. Допустим прийти успело 26 (один ещё не успел). Поскольку их не 27, Вы выбрасываете их и "делаете всё как раньше". При следующем лупе приходит не успевший в прошлый раз 27-ой символ. Поскольку символов опять не 27, а один, Вы и его выбрасываете и "делаете всё как раньше".
Правильно, Вам так надо?
Вот что значит профи! Три слова, и "мысь по древу" сформулирована! Спасибо, именно это мне и было надо. Понял сразу всё. Буду думать дальше. Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь). Наконец добрался до платы. Поковыряюсь, думаю большая часть вопросов отвалится на практике. Что останется - приду снова сюда.
Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь).
нет, так не надо делать. Лови. Сообщение применяются такого вида:
AA 55 XX байты полезной нагрузки CS
где АА и 55 старт байты, XX - байт длины сообщения, CS - контрольная сумма (простое сложение, для увеличения надёжности можно взять далласовский CRC)
вот и выполняйте свою программу с параметрами, которые будут поступать от ПК в созданный буфер buf . Если с ПК пришло сообщение, этот buf уже будет "с новыми параметрами", если не пришло - будет "продолжать это делать со старыми". Только само собой на ПК нужно упаковывать данные по тем же правилам.
Премного благодарен. Записал себе в анналы. Сразу понять все не смог (низкая квалификация), но полноценные комменты помогут. Буду разбираться.
Вот полезная для тебя функция
http://arduino.ru/Reference/Serial/Peek
Спасибо, до ПИКа еще не добрался :) Изучу.