Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: затруднение с RS485
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Athlon128
По RS485 объединены мастер и несколько слейвов (все на mega128) мастер с интервалом в 100мс шлёт команду вида: префикс ":", байт - номер команды, байт - id слейва, 2 байта - аргументы для команды, постфикс ";". 1 из слейвов должен ответить что он подключен. Вот фрагмент кода слейва (codevisionAVR):

Код
while (1)
      {
delay_ms(50);

command=0;
number=0;

while (getchar() != ':');

command=getchar();
number=getchar();

if ((command==1)&&(number==id))
{
PORTE.7=1;
printf(":%d online;",id);
PORTE.7=0;
}
// delay_ms(50);

      };
}

на деле отвечает только 1 раз первый запрошенный слейв.
что я делаю неправильно подскажите плз


поигрался интервалом отправки команд с мастера, начали отвечать несколько слейвов smile.gif
DASM
Не понял - это симулятор ? А где код вкл-выключения 485 драйвера на передачу ? И что-то не нравится мне идея готовность выдавать в виде : :%d online . В данном случае девайсы услышат этот отклик, но команда будет равна 32 (код пробела) но зачем их напрягать то... Какая скорость 485 ?
Athlon128
код вкл-выключения 485 драйвера на передачу
Код
PORTE.7=1;
....//передача
PORTE.7=0;

Теперь у меня вопрос: как правильнее синхронизировать передачу команды и ссчитывание из буфера слейвом.
Если ставлю интервал отправки мастером меньше чем интервал ссчитывания из буфера слейвом, то всё работает до переполнения буфера слейва. Сейчас попробую синхронизировать их таймером.
А как выходили из положения вы?
Сорри за сумбур smile.gif
DASM
Ничего не понял. Какого буфера переполнение ? Зачем кстати 50 мс задержка в цикле ? PS после включения драйвера на передачу задржку надо бы на устаканивание переходных процессов в линии
Палыч
ИМХО, слэйв отвечает на команду мастера не дождавшись окончания передачи мастера: передача слэйва начинается. когда получен id слэйва, но мастер еще передаёт 3 байта (аргументы и постфикс)
DASM
Точно smile.gif
alexander55
Цитата(Палыч @ Oct 24 2007, 08:51) *
ИМХО, слэйв отвечает на команду мастера не дождавшись окончания передачи мастера: передача слэйва начинается. когда получен id слэйва, но мастер еще передаёт 3 байта (аргументы и постфикс)

Это самая главная проблема при работе с RS485 для мастера. ЕЕ надо решать корректно.
Athlon128
Цитата(Палыч @ Oct 24 2007, 10:51) *
ИМХО, слэйв отвечает на команду мастера не дождавшись окончания передачи мастера: передача слэйва начинается. когда получен id слэйва, но мастер еще передаёт 3 байта (аргументы и постфикс)


Вы правы.
Поставил задержку перед ответом, все слейвы отвечают нормально
Дальше экспериментирую..
Буду благодарен за фрагмент исходника для слейвов с RS485 или хотябы словесное объяснение алгоритма.
Вечером отпишу что получилось у меня
prm
Работу слейва,как вариант, можно описать следующим образом. Будем считать пакет принятым, если после приема последнего байта пакета истекла пауза равная времени передачи трех байтов, в течение которой не было принято ни одного байта. Если же во время паузы принимаем байт, то считаем его последним и вновь отслеживаем истечение паузы. И так далее пока пауза не истечет и пакет не будет принят. Отслеживанием паузы занимается таймер, в прерывании которого просто устанавливаем какой-либо флаг. К примеру:

//-------------------------------------------------------------------------------------------
unsigned char Read_USART(unsigned char kol) // kol - число байт, которое хотим принять
{
unsigned char i;

for(i=0;i<kol;i++)
{
TimerFlag0=0; //очищаем флаг срабатывания таймера

TCNT0=0xC8; //значение, соответсвующее паузе ~1.75мс
TCCR0=0x04; //запускаем таймер
//ожидаем приема байта
while (!(UCSRA & (1<<RXC)))
{
if(TimerFlag0) //проверка, время ожидания истекло
{
//возвращаем число реально принятых байт
return i;
}
//сбрасываем сторожевой таймер
WDR();
}
//считываем байт
buf[i]=UDR;
TCCR0=0x00;
}
return i;
}

//---------------------------------------------------------------------------------------
//Прерывание от таймера 0, свидетельствует о превышении интервала ожидания для приема байта

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{ TCCR0=0x00; //останавливаем таймер
TimerFlag0=1; //устанавливаем флаг срабатывания
}

В основной программе:
//принимаем пакет
k=Read_USART(IN_BUF_LEN);
//анализируем его
error = AnalizeBuf(k);

smile.gif
Палыч
Цитата(Athlon128 @ Oct 24 2007, 09:21) *
Буду благодарен за фрагмент исходника для слейвов с RS485 или хотябы словесное объяснение алгоритма.


В глаза бросаются недостатки примененного в Вашей работе протокола. Например, префикс и постфикс могут совпадать с другими полями команды (кодом, адресом, аргументами); если они применяются для целей нахождения начала и конца команды, то в этом случае - это будет сделать затруднительно. Да, и проверка "правильности" приема пакета (например, с помощью контрольной суммы) - дело не последнее. Рекомендую ознакомится с тем, как это делают другие. Например, тут http://www.caxapa.ru/lib/wake/ И исходники для AVR приведены...
DASM
В данном случае думаю проще Modbus ASCII использовать, тем более похоже им и навеяно
prm
Либо ModBus RTU, тоже вещь очень хорошая. Я бы даже сказал просто не заменимая в работе Master-Slave систем.
alexander55
Цитата(Палыч @ Oct 24 2007, 11:54) *
В глаза бросаются недостатки примененного в Вашей работе протокола.

Я рекомендую протокол ModBus. Дешево и сердито.
PS. Какой у нас народ шустрый.
DASM
Modbus RTU не люблю по причине определенных сложностей обработки потока на компе (винда не real time, и 3.5 символа паузы определить 100 % проблематично). Лучше действительно wake- подобное, ну или если траффика не жалко ASCII Modbus
prm
Пользую ModBus RTU (вернее ModBus RTU-подобный протокол ). Обычно поступаю следующим образом. В качестве мастера выступает комп, он формирует запросы, анализирует ответы, осуществляет мониторинг, пишет БД и т.д. Обмен информацией организую так:
1. Очищаю приемный и передаваемый буферы драйвера COM - порта;
2. Отправляю запрос слейв устройствам;
3. Делаю маленькую паузу;
4. Жду поступления в приемный буфер данных (проверяю число байт в буфере)
5. Как только в буфере появились байты осуществляю считывание, если данные не идут в течении определенного времени - вываливаюсь по TIMEOUT-у
6. Анализирую принятую инфу
DASM
Цитата
если данные не идут в течении определенного времени
в этот момент играющий на втором WinDVD запросил очередную порцию фильма с винта, винда этим занялась и тут
Цитата
- вываливаюсь по TIMEOUT-у

А Modbus - да фик с ним, с Modbusom
alexander55
Цитата(DASM @ Oct 24 2007, 13:32) *
А Modbus - да фик с ним, с Modbusom

Под вываливаюсь по таймауту подразумевается обработка принятого пакета.
prm
Нет, перед приемом пакета устанавливаю время, в течение которого я жду данные, если это время истекает, а данных нет, генерируется исключение, т.е. данных никаких не пришло. Далее расцениваю это как "модуль не ответил" и реагирую в зависимости от ситуации.
Ну и повторюсь, что пользую ModBus RTU-подобный протокол, заточенный под мои задачи.
А то, что "винда не real time" - это точно smile.gif
DASM
Ну так в любом случае этот ложный таймаут может появиться именно из-за действий винды ! Можно конечно real time приоритет выставить, но это моветон
alexander55
Цитата(prm @ Oct 24 2007, 14:41) *
Нет, перед приемом пакета устанавливаю время, в течение которого я жду данные, если это время истекает, а данных нет, генерируется исключение, т.е. данных никаких не пришло. Далее расцениваю это как "модуль не ответил" и реагирую в зависимости от ситуации.
Ну и повторюсь, что пользую ModBus RTU-подобный протокол, заточенный под мои задачи.
А то, что "винда не real time" - это точно smile.gif

Так, уже интересно.
Вариантов может быть 2 более-менее разных.
1. При приеме очередного символа, таймаут довзводится.
При истечении таймаута анализируется пакет, указатель приемного буфера на начало.
2. При приеме очередного символа, подсчитывается CRC16.
Если СКС16==0 обрабатывается пакет, указатель приемного буфера на начало.
Таймер таймаута используется для еще одной установки указателя приемного буфера на начало.
Что за вариант используется у Вас ?
DASM
Мужики, то, что ложных пакетов таким образом не нахватешь - точно. А вот потерять - запросто
alexander55
Цитата(DASM @ Oct 24 2007, 15:10) *
Мужики, то, что ложных пакетов таким образом не нахватешь - точно. А вот потерять - запросто

2-3 % убитых и раненых на учениях - это нормально. Главное шпионов в плен не брать. smile.gif
defunct
Цитата(DASM @ Oct 24 2007, 12:32) *
А Modbus - да фик с ним, с Modbusom

Так и есть. Потом повтор команды и т.д..

Но на помощь может прийти "умный" конвертер 232<->485.
Который в отличие от тупого, будет знать modbus, и уметь обрамлять/раздевать стаффинги. Пакеты "к компу" обрамлять тагами байт стаффинга, а "в сеть" - снимать таги компа - и слать чистый modbus RTU с требуемыми задержками. Работать не по CRC а по таймаутам, с проверкой CRC после обнаружения таймаута в 4 символа.
DASM
Ну не знаю.. меня системы на жесткой времянке нервируют и раздражают. И по F9 занудно их пошагово трассировать sad.gif

Цитата(defunct @ Oct 24 2007, 15:41) *
Так и есть. Потом повтор команды и т.д..

Но на помощь может прийти "умный" конвертер 232<->485.
Который в отличие от тупого, будет знать modbus, и уметь обрамлять/раздевать стаффинги. Пакеты "к компу" обрамлять тагами байт стаффинга, а "в сеть" - снимать таги компа - и слать чистый modbus RTU с требуемыми задержками. Работать не по CRC а по таймаутам, с проверкой CRC после обнаружения таймаута в 4 символа.

Угу, а CAN еще лучше придет на помощь. По-моему проектировать умный конвертер автору пока не хочется, но можно спросить его smile.gif
alexander55
Цитата(defunct @ Oct 24 2007, 15:41) *
Работать не по CRC а по таймаутам, с проверкой CRC после обнаружения таймаута ...

Этот вариант считается предпочтительным.
defunct
Цитата(DASM @ Oct 24 2007, 14:43) *
Ну не знаю.. меня системы на жесткой времянке нервируют и раздражают. И по F9 занудно их пошагово трассировать sad.gif

Дык, это ж только транспорт на жесткой времянке.. Один раз отладить и все..
DASM
А зачем ? Если есть Wake ? Стаффинг и ноль проблем.
defunct
Цитата(DASM @ Oct 24 2007, 15:04) *
А зачем ? Если есть Wake ? Стаффинг и ноль проблем.

Пригодится. Нынче много готовых слейвов имеется которые понимают Modbus RTU, но не понимают Wake. sad.gif
Да и работает чистый RTU неплохо на самом деле (когда мастер не PC wink.gif )
alexander55
Цитата(defunct @ Oct 24 2007, 16:15) *
Пригодится. Нынче много готовых слейвов имеется которые понимают Modbus RTU, но не понимают Wake. sad.gif
Да и работает чистый RTU неплохо на самом деле (когда мастер не PC wink.gif )

Добавлю, что ModBus RTU является самым распространенным стандартом выполнения RS485.
DASM
RS485 вообще программный уровень не стандартизирует. А с чем доводилось работать - было либо ASCII либо и то и то вместе. А еще чаще просто текстовые строки - любят юзера, чтобы в обычной терминалке можно было бы с прибором поговорить.
alexander55
Цитата(DASM @ Oct 24 2007, 16:35) *
RS485 вообще программный уровень не стандартизирует. А с чем доводилось работать - было либо ASCII либо и то и то вместе. А еще чаще просто текстовые строки - любят юзера, чтобы в обычной терминалке можно было бы с прибором поговорить.

Стандартизация есть для PLC полная. Под SCADы много прибамбасов для ModBus.

Если в терминалке с прибором поговорить, то текстовые сообщения (это понятно).
А если программа пишется для PC, типа прибора, то ModBus RTU.
Если контроллеры объединяются в сеть, то ModBus RTU.
Athlon128
Пытался днём на бумаге прикинуть программу.

В основном коде программы:
Код
while (rx_counter0==0); // ждём когда будет принят байт в буфер
delay_ms(25);
TCCR1B=0x05; // запускаем таймер (период 50мс)


В прерывании по таймеру:
Код
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
if (rx_counter0>0) // если буфер не пуст
{
  while (getchar()!=':'); // считываем по байту пока не попадётся префикс ':'
  command=getchar(); // номер команды
  number=getchar(); // номер слейва

if ((command==1)&&(number==number_temp)) // если была послана команда №1 для текущего слейва
{
  PORTE.7=1; // переключаем max487 на выход
  delay_ms(1);
  printf(":%d online;",number_temp); // ответ
  PORTE.7=0; // переключаем max487 на вход
}
}

TCNT1H=0x00; // обнуляем таймер
TCNT1L=0x00; //
}


Мастер шлёт команды всем по очереди слейвам с периодом 100мс тоже по таймеру.
Идея такая: в момент включения ждём хотябы 1 байт и через 25мс (чтобы обеспечить смещение во время которого смогут быть приняты следующие команды мастера) запускаем таймер (50мс).
Далее каждые 50мс: ищем в буфере префикс ":", читаем № команды и id слейва в команде и отвечаем если команда адресована данному слейву.
Вот такая задумка была.
На деле отвечает только слейв, которому была адресована 1я команда

Завтра попробую другой подход 05.gif
Пошёл читать доки
Прохожий
Цитата(Athlon128 @ Oct 24 2007, 20:22) *
Пытался днём на бумаге прикинуть программу. ...

Завтра попробую другой подход 05.gif

Я одного не пойму. Зачем изобретать велосипед там, где это давно уже сделано? Есть хороший стандарт MODBUS. Задача проста - ознакомиться с документами и сделать так, как там написано. Все преимущества такого подхода справедливо отметил alexander55.
Если нужны бОльшие скорости - для этого существует MODBUS over TCP/IP, что тоже достаточно легко реализуемо в настоящее время. В качестве бонуса - полнейшая совместимость с туевой хучей девайсов.
От себя могу добавить, что изобретать что либо в области RS485-строения в настоящее время уже просто неприлично.
Dog Pawlowa
Цитата(Прохожий @ Oct 24 2007, 20:36) *
От себя могу добавить, что изобретать что либо в области RS485-строения в настоящее время уже просто неприлично.

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


Цитата(DASM @ Oct 24 2007, 16:35) *
RS485 вообще программный уровень не стандартизирует. А с чем доводилось работать - было либо ASCII либо и то и то вместе. А еще чаще просто текстовые строки - любят юзера, чтобы в обычной терминалке можно было бы с прибором поговорить.

Хм, меня юзером назвали! smile.gif
Люблю в терминалке и поговорить, и послушать. А уж лог-файл вообще автоматом получается.
fmdost
hттp://ru.wikipedia.org/wiki/Modbus

Удивительно хорошая статья на русском!
Athlon128
Ладно, всем спасибо, буду читать про modbus
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.