UART + ПРЕРЫВАНИЯ
- Войдите на сайт для отправки комментариев
Втр, 29/10/2013 - 13:53
Всем доброго дня!
Вопрос такой:
Есть две ардуины соединенные по UART, одна раз в 5 сек. передает 10 переменных, другая по событию кнопки. У меня это реализовано просто через Serial.print(p1); где р1 переменная (ее значения 1 или 0).
Т.е. отправка выглядит так:
if (событие) {
Serial.print(p1);
Serial.print(p2);
Serial.print(p3);
........................
Serial.print(p9);
Serial.print(p10);
}
Но это не работает потому что через некоторо время получается каша и значения не соответствуют переменным. Передачу нужно делать с помощь прерываний.
Помогите разобраться как работать с прерываниями и стабильно передавать данные по UART пожалуйста.
Передачу нужно делать с помощь прерываний.
То что у вас выше работает, а то что не работает вы не показали. Что вам нужно конкретно вы тоже не написали.
Вставка программного кода в тему/комментарий
Прием переменных выглядит так:
if (Serial.available() == 10 ) { while(command < 10 ) { commands[command] = Serial.read(); command++; } command=0; }Сейчас ардуина постоянно проверяет буфер UART. А если происходит сбой то значения переменных сдвигаются.
Например, если в буфере по какой то причине остались 2 байта (2 значения) от старой передачи и туда записались 10 новых байт (значений) то мы считаем 2 старых + 8 новых и в итоге вся передача сдвинется на 2 значения.
Как сделать так что бы данные из буфера забирались в тот момент когда они поступили, что бы забирать именно 10 последних записанных байт?
Зачем ждать, пока в буфере накопится 10 байт? Забирайте сразу же, как только они поступили
а если боитесь, что произойдет сбой - заведите специальный 11-тый символ, как конец последовательности. или наоборот, начало.
Ждать для того, что бы получив 10 байт сразу присвоить их 10ти переменным.
Я думал на тему спец символа, но 11 символ не решает проблему потери. Поясню, например, мы передаем ~1234567890 10 переменных где значение соответствует номеру переменной. И вдруг мы потеряли пятый байт, значение которого 5. Теперь на 5ом месте шестой байт значение которого 6, соответственно пятой переменной присвоится значени 6, шестой 7 и т.д.
Получается передавать надо пакетом и если потерян хотя бы 1 байт пакета, то в помойку весь пакет, но в этом случае надо повторно запрашивать потеряный пакет =(
А что если сразу после отправки вызывать внешнее прерывание на получающей ардуне, которое сразу считает данные из буфера? Чем может быть плох такой способ?
А с чего вдруг должен потеряться байт? Я вам могу и за платно написать 100% стабильную передачу данных, но как только вы засуните мой код в свой у вас опять начнутся потери. Так что не надо тут каких то кусков кода с вашими обьяснениями, просто покажите ВЕСЬ под приемника и ВЕСЬ код передатчика.
Байт может потеряться по причине плохого соединения, временного отсутствия питания на одном конце и т.д.
И прерывания не решат эту проблему.
Другое дело, если отправлять структуры вида (номер, данные). В этом случае отсутствие пакета сразу будет заметно.
Вот это ближе к делу, Dimsan прав, ведь даже скачок напряжения может привести к потере байта.
Так из вышенаписанного получается, что невозможно реализовать стабильную передачу отправляя последовательно байты в UART?
Вот ВЕСЬ код как сказали.
Код одной
char commands[10]; int command = 0; unsigned long sec = 0; int switch31Pin = 31; int ledPin = 13; boolean lastButton = LOW; //последний boolean currentButton = LOW; //текущий boolean ledOn = false; boolean ignor = false; char c = 0; void setup() { Serial.begin(9600); Serial3.begin(9600); pinMode(switch31Pin, INPUT); pinMode(ledPin, OUTPUT); } void loop() { currentButton = debounce(lastButton); if (lastButton != currentButton)//(lastButton == LOW && currentButton ==HIGH) { ledOn = !ledOn; ignor = true; } lastButton = currentButton; digitalWrite(ledPin, ledOn); if (sec == 110000) { if (ignor == true) { Serial3.print(ledOn); Serial3.print("2"); Serial3.print("3"); Serial3.print("4"); Serial3.print("5"); Serial3.print("6"); Serial3.print("7"); Serial3.print("8"); Serial3.print("9"); Serial3.print("0"); } if (Serial3.available() > 1 ) // Если в буфере 5 байт { while(command < 10 ) { commands[command] = Serial3.read(); Serial.print(commands[command]); command++; } Serial.println(); command=0; if ( ignor == false ) { ExecuteCommands(); } } ignor = false; sec=0; } sec++; } void ExecuteCommands() { if(commands[0] == '1' ) { ledOn = true; } else if(commands[0] == '0') { ledOn = false; } } boolean debounce(boolean last) { boolean current = digitalRead(switch31Pin); //+++ if (last !=current) { delay(5); current = digitalRead(switch31Pin); } return current; }Код другой
#include <SPI.h> #include <Ethernet.h> byte mac[] = { 0xC8, 0x60, 0x00, 0xCB, 0x57, 0x43 }; // задаеи MAC char serverName[] = "google.com"; EthernetClient client; int command = 0; // для перебора переменных char commands[10]; // для хранени 5 значений String id = String(1); // ID идентификатор unsigned long sec = 0; // переменная таймера boolean port = false; void setup() { Serial.begin(9600); Ethernet.begin(mac); delay(1000); Serial.print("test"); } void loop() { if (Serial.available() == 10 ) { while( command < 5 ) { commands[command] = Serial.read(); command++; } command=0; port = true; } if (sec == 110000) { if (client.connect(serverName, 80)) { if (port == true) { client.println("GET /index.php?id=" +id+ "&v1=" + commands[0] + " HTTP/1.0"); client.println(); port = false; } else { client.println("GET /index.php?id=" +id+ " HTTP/1.0"); client.println(); } } delay(100); if (client.available() > 1) { char c = client.read(); if(c != '@') { while(c != '@') { c = client.read(); } } for (commands[command] = client.read(); command < 5; command++) { commands[command] = client.read(); Serial.print(commands[command]); } } client.stop(); sec=0; command = 0; } sec++; }Код одной, с 35 по 44 передача с 46 по 53 прием.
Код другой с 21 по 27 прием с 59 по 63 передача.
В прерываниях всё прекрасно работает, за исключением обрыва линии или
потери питания. МК соединяются по схеме Master-Slave.
Master периодически, по таймеру, передаёт данные и опрашивает
Slave. В конце каждого пакета передаётся контрольная сумма,
если не совпадает то пакет не принимается во внимание и приёмный буфер
очищается. Slave в ответ передаёт либо свой статус, либо данные.
У меня так работают Master и 6 Slave.
В общем так и не ясно сколько же байт вы хотите передать ,толи 10 толи 5, по коду этого определить не получается.
Делаете так и будет вам стабильность
if (Serial.available() >= 10 ) { while( command < 10 ) { commands[command] = Serial.read(); command++; } ...... } ......МК соединяются по схеме Master-Slave.
Если не секрет это как?
alex_r61, у вас на аппаратных прерываниях это реализовано?
И видите, в чем дело, я еще не дорос до понимания "контрольная сумма"
Как Master опрашивает Slave?
Каим образом очищается буфер, я такой команды не нашел?
Можно посмотреть ваши коды, мне будет очень полезно!
maksim я выложил коды как вы просили =) что скажете?
Я соединял через RS-485 трансиверы, а два можно напрямую.
Я соединял через RS-485 трансиверы, а два можно напрямую.
maksim я выложил коды как вы просили =) что скажете?
Что вам еще сказать? #10
Понятно, сами не знаете как. Открою вам секрет UART это не есть RS-485. UART не имеет ни мастера ни слейва.
Rs-485 это стандарт физического уровня, т.е. железо. А реализация Master-Slave
это програмный уровень, можете хоть ModBus прилепить. И держите свой секрет в
большом секрете.
А, программно.... Я просто еще разок вас процитирую.
МК соединяются по схеме Master-Slave.
А программно.... Я просто еще разок вас процитирую.
МК соединяются по схеме Master-Slave.
Я имел в виду именно программное подключение.
qwedhinet задайте в поисковике "сrс8 для arduino".
Программное подключение по программной схеме программными проводами.
В общем, ладно, разговор ни о чем. Нет такого подключения.
Контрольную сумму в вашем случае передаете одиннадцатым байтом.
При приеме также ее считаете и сравниваете с тем же 11-м байтом
Что-то вы тут много всего написали, только запутали человека. Он использует UART, нет тут ни master, ни slave.
Я предложил решение. CRC конечно хорошо, не спорю, но что будет если, например, 11-й байт (контрольная сумма) придёт 10-м? Приёмник будет долго ждать последний 11-й байт, по ка не дождётся начала следующих 11 байт.
CRC конечно хорошо, не спорю, но что будет если, например, 11-й байт (контрольная сумма) придёт 10-м? Приёмник будет долго ждать последний 11-й байт, по ка не дождётся начала следующих 11 байт.
Ожидание нужно ограничить. Если, после начала приёма, в течении определённого
времени не получено определённого количества байт выходить по TimeOut с флагом
ошибки.
Правильно.
На этот случай есть функция Serial.readBytes(buffer, length) - http://arduino.cc/en/Serial/ReadBytes. Принимает массив байт с учётом таймаута. Если вдруг что-то потеряется, то можно смело кричать: "Плохи дела, давай ещё раз!"
А что если, а что если....
Вы предложили увеличить размер данных в два раза. А что если под одним и тем же номером прийдут разные значения? Не надо здесь ни конторольной суммы, ни номеров. Есть проблемы с соединением - устраните проблему с соединением. Есть проблемы с питанием устраните проблему с питанием, так как это не шина и не сеть коллизии исключены, а значит данные просто так пропасть не могут.
Не спорю.
А что скажете на счёт 24-го сообщения?
У этой функции (метода) есть один минус - она блокирующая. Если так уж надо то можно обьявить переменную, в которой сохранять значение millis() как только пришел первый байт пакета и сбрасывать ее в 0 когда получили последний байт.
qwedhinet, а что за опасные условия, если не секрет, где работает эта неустойчивая конструкция - то провод оборвут, то питание пропадет, то байт сам по себе испарится? просто интересно.....