ADM485 время задержки

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

ADM485 время задержки

Сообщение krik_nk »

Всем привет. Пишу программку, которая передает сообщения с ATMEGA32 на RS485. Имеется кварц с частотой 14745600. Использую модуль http://www.mikroe.com/add-on-boards/communication/rs485/ фирмы микроэлектроника для передачи данных. В данном модуле используется ADM485. Так вот у меня вопрос. При отправке байтов через USART я пишу байты в UDR, при этом конечно же должен быть включен режим передачи. Так вот если просто передать байты в UDR, то данные не пересылаются или пересылаются не полностью. Для того, чтобы передать байт я выдерживаю задержку Delay_ms(32), которая была подобрана методом "тыка". Меня интересует вопрос, как вычислить или где посмотреть время данной задержки? В течении кода, выставлено несколько задержек, но такое ощущение, что это все не совсем правильно. Ведь если потом поменять кварц, либо скорость передачи данных, не уверен что все дальше будет правильно работать. Подскажите как сделать правильно! Опыта с данными модулями совсем нет :?

Вот части моего кода:

Функция инициализации:

Код: Выделить всё

void USART_Init(void){
  // Baudrate calculation
  DATA_BAUDRATE = DATA_BAUDRATE*16;
  DATA_UBRR = (_DATA_CLOCK/DATA_BAUDRATE)-1;
  /*Set baud rate */
  UBRRH = Hi(DATA_UBRR);
  UBRRL = Lo(DATA_UBRR);

  DATA_TX_INDEX = 0;
  DDRD &=~(1<<0); // set PORTD.0 as input for ADM485 (RX)
  DDRD |= (1<<1); // set PORTD.1 as output for ADM485 (TX)
  DDRD |= (1<<3); // set PORTD.3 as output for ADM485 (transmit-recieve mode)

  // Normal BaudRate (if U2X == 1 then x2 BaudRate)
  UCSRA &=~ (1 << U2X);
  // RXCIE interrupt, RX enable
  UCSRB |= (1 << RXCIE)|(1 << RXEN)|(1 << TXEN);
  // URSEL -> 8 bit - one word; (1 stop bit)
  UCSRC |= (1 << URSEL)|(1 << UCSZ1)|(1 << UCSZ0);
}


Функция по которой принимается байт:

Код: Выделить всё

void interrupt_USART_RXC_vect() org IVT_ADDR_USART__RXC {
  DATA_RX = UDR;
}


Функция по которой отправляется массив байт:

Код: Выделить всё

void interrupt_USART_UDRE_vect() org IVT_ADDR_USART__UDRE {
  if(DATA_TX_INDEX < (_DATA_TX_COUNT)){
    UDR = DATA_TX[DATA_TX_INDEX];
    Delay_ms(40);
    // next element in array
    DATA_TX_INDEX = DATA_TX_INDEX + 1;
  }
  else{
    DATA_TX_INDEX = 0;
    // Exit vector
    UCSRB &=~ (1 << UDRIE);
    // Recive mode ON
    UCSRB |= (1 << RXEN);
    // Low level control pin
    PORTD &=~ (1 << 5);
    // delay of changing mode (to recive messages)
    Delay_ms(32);
  }
}


Собственно использование в главном цикле:

Код: Выделить всё

    // ---------- RS485 ----------
    if(DATA_RX == _DATA_REQUEST){
      DATA_RX = 0;
      // Recive mode OFF
      UCSRB &=~ (1 << RXEN);
      // High level control pin
      PORTD |= (1 << 5);
      // delay of changing mode (to trancive messages)
      Delay_ms(32);
      // Calculation CRC-16
      DATA_TX_CRC = CRC16(&DATA_TX,8);
      DATA_TX[8] = Hi(DATA_TX_CRC);
      DATA_TX[9] = Lo(DATA_TX_CRC);
      // entrance vector
      UCSRB |= (1 << UDRIE);
    }

    // ----------
    asm nop;
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ADM485 время задержки

Сообщение akl »

А вообще без задержки работать пробовали?
СпойлерИзображение
ADM485_RE_DE.GIF

Можно перевести ADM485 в режим мониторинга линии (RE<--- GND, DE<--- +5V) и посмотреть что там творится.
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ADM485 время задержки

Сообщение Jack_A »

Задержки в цикле не нужны, тем более такие громадные . Каждый последующий байт закидывается в UDR после того, как проверкой бита UDRE убедимся в том, что буфер пуст. Передав последний байт, дожидаемся установки бита TxC, свидетельствующего об окончании передачи, и можем снимать бит режима передачи в МАХ485 .
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

akl, Если убрать все задержки, то вообще ничего не пересылает.

Jack_A, А переход в вектор прерывания void interrupt_USART_UDRE_vect() org IVT_ADDR_USART__UDRE разве не свидетельствует о том, что буфер пуст?
Убрал все задержки, вставил после вызова прерывания после последнего отправленного байта.

Код: Выделить всё

while (!(UCSRA & 1<<TXC0));  
asm nop;


Однако отправляется заместо 10 байт всего лишь 6 :(
Чтобы отправить все 10 байт, опять же методом тыка, получилось только, если добавить задержку в 10 мс... Почему 10 мс, то ??? Или нужно что-то по другому сделать?

Код: Выделить всё

void interrupt_USART_UDRE_vect() org IVT_ADDR_USART__UDRE {
  if(DATA_TX_INDEX < (_DATA_TX_COUNT)){
    UDR = DATA_TX[DATA_TX_INDEX];
    //Delay_ms(40);
    // next element in array
    DATA_TX_INDEX = DATA_TX_INDEX + 1;
    while (!(UCSRA & 1<<TXC0));
     asm nop;
    Delay_ms(10);
  }
  else{
    while (!(UCSRA & 1<<TXC0));
     asm nop;
    DATA_TX_INDEX = 0;
    // Exit vector
    UCSRB &=~ (1 << UDRIE);
    // Recive mode ON
    UCSRB |= (1 << RXEN);
    // Low level control pin
    PORTD &=~ (1 << 3);
    // delay of changing mode (to recive messages)
    //Delay_ms(32);
  }
}
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ADM485 время задержки

Сообщение Jack_A »

Я для AVRок Си не использовал, поэтому мне трудно судить и в Сишном коде разбираться лениво. У меня проекты все были на асме, и с обменом по 485-му не было вопросов типа какой код взбредет на ум сгенерить компилятору.
Это не очередной виток Си vs Asm! - просто что было, то и описываю.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Да я не противник ASM. Просто тут нужно именно на СИ сделать. Принципе в теории разобрался, но вот на практике оказались эти самые задержки. Понятно, что они нужны какие-то, но когда в даташите написаны наносекунды, задаешься вопросом, а правильно ли я все делаю?
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ADM485 время задержки

Сообщение Jack_A »

Есть возможность взять осцилл и посмотреть ? А откуда известно, что не все байты уходят - по реакции приемника ? А если в нем косяк ?
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: ADM485 время задержки

Сообщение YS »

А переход в вектор прерывания void interrupt_USART_UDRE_vect() org IVT_ADDR_USART__UDRE разве не свидетельствует о том, что буфер пуст?


То, что буфер UDR пуст, не означает, что передача закончена!

События UDRE и TXC - разные. UDRE означает только то, что данные из UDR были переданы в скрытый сдвиговый регистр и начали передаваться, а в UDR можно записать еще байт.

Даташит, страница 147:

A data transmission is initiated by loading the transmit buffer with the data to be transmitted. The
CPU can load the transmit buffer by writing to the UDR I/O location. The buffered data in the
transmit buffer will be moved to the Shift Register when the Shift Register is ready to send a new
frame. The Shift Register is loaded with new data if it is in idle state (no ongoing transmission) or
immediately after the last stop bit of the previous frame is transmitted. When the Shift Register is
loaded with new data, it will transfer one complete frame at the rate given by the Baud Register,
U2X bit or by XCK depending on mode of operation.


TXC означает, что данные реально передались. По очевидным причинам переключать режим трансивера можно только после окончания реальной передачи данных. Потому вместо задержки вам надо вставить ожидание TXC. Например,

Код: Выделить всё

while (!(UCSRA & _BV(TXC)))
{
}
Разница между теорией и практикой на практике гораздо больше, чем в теории.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Думал тоже про приемник, но приемник у меня такой же микроконтроллер, с похожим модулем. Данные вывожу на LCD. Раз в 5 секунд опрашиваю и вывожу ответ. Пробовал использовать много вариантов, крутил вертел код, в итоге на задержки эти вышел. Нашел кстати информацию http://radiokot.ru/forum/viewtopic.php?f=20&t=32791&view=print. Там тоже проблема с задержкой была:
Было:
Код:

Код: Выделить всё

      USART_SendChar('O'); //отвечаем компу "Ok "
      USART_SendChar('k');
      LED_PORT=LED_PORT & ~(1<<send);
      LED_PORT=LED_PORT & ~(1<<LED2);
      LED_PORT=LED_PORT & ~(1<<LED1);
      __delay_cycles(10000000);


А надо:
Код:

Код: Выделить всё

      USART_SendChar('O'); //отвечаем компу "Ok "
      USART_SendChar('k');
      __delay_cycles(10000000);
      LED_PORT=LED_PORT & ~(1<<send);
      LED_PORT=LED_PORT & ~(1<<LED2);
      LED_PORT=LED_PORT & ~(1<<LED1);


Во втором косяке передатчик ADM'a отключался раньше, чем отправлялись данные запиханные в буфер USART'a.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ADM485 время задержки

Сообщение akl »

YS писал(а):...TXC означает, что данные реально передались. По очевидным причинам переключать режим трансивера можно только после окончания реальной передачи данных. Потому вместо задержки вам надо вставить ожидание TXC.
Добавлю к сказанному, что флаг TxC аппаратно очищается только в соответствующем обработчике прерывания. Т.к. это прерывание не разрешено, то флаг TxC должен чиститься программно записью 1 в UCSRA. Например для ATmega64 по каналу USART0.

Код: Выделить всё

   LDI   R17,1<<TxEN0
   OUT   UCSR0B,R17

   SBI   PORTE,2            ; RS485 на передачу в линию

   LDI   YH,HIGH(RAM_FRAME_BEG)
   LDI   YL,LOW(RAM_FRAME_BEG)
   LDI   ZH,HIGH(RAM_FRAME_END)
   LDI   ZL,LOW(RAM_FRAME_END)
GO_TxD_RS:
   RCALL   TXD
   CP   YL,ZL
   CPC   YH,ZH
   BRLO   GO_TxD_RS

   СBI   PORTE,2            ; RS485 на приём с линии

   RJMP   GO
;*************************************************
TXD:
   LD      R0,Y+
   OUT      UDR0,R0
WAIT_TXC:
   SBIS   UCSR0A,TxC0
   RJMP   WAIT_TXC

   SBI      UCSR0A,TxC0   ; очистить установленный бит TxC0

   RET
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6307
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ADM485 время задержки

Сообщение Jack_A »

Ну раз есть приемник, задача диагностики облегчактся : первые байты передаются правильно, дальше молчание, или через байт, или вообще битый пакет приходит? Скорости и остальные параметры передачи совпадает на прд. и прм. ? И насчет бита TxC очень правильно YS обратил внимание.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: ADM485 время задержки

Сообщение YS »

О, кстати, в даташите на стр. 149 как раз про RS-485 пишут. :)

The Transmit Complete (TXC) Flag bit is set one when the entire frame in the transmit Shift
Register has been shifted out and there are no new data currently present in the transmit buffer.
The TXC Flag bit is automatically cleared when a transmit complete interrupt is executed, or it
can be cleared by writing a one to its bit location. The TXC Flag is useful in half-duplex
communication interfaces (like the RS485 standard), where a transmitting application must enter
receive mode and free the communication bus immediately after completing the transmission.


Т.к. это прерывание не разрешено, то флаг TxC должен чиститься программно записью 1 в UCSRA.


Уточню - чиститься непосредственно перед тем, как положить байт в UDR.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

В понедельник на работе попробую еще, отпишусь.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Все таки решил воспользоваться вектором прерывания по отправке. Реально избавился от многих задержек. Но одну так победить и не получается. Задержка включения режима отправки ADM485 delay_ms(2). Без данной задержки приходят все байты неправильно.

В главном цикле проверяю пришел ли нужный запрос, если да, то отправляю пакет байтов:

Код: Выделить всё

    
if(DATA_RX == _DATA_REQUEST){
      DATA_RX = 0;
      // Recive mode OFF
      UCSRB &=~ (1 << RXEN);
      // High level control pin
      PORTD |= (1 << 3);
      delay_ms(2); // <<-------- DELAY
      USART_SendPacket();
    }


Отправка первого байта:

Код: Выделить всё

void USART_SendPacket(void)
{
  // Wait for empty transmit buffer
  while (!( UCSRA & (1<<UDRE)));
  // Put data into buffer, sends the data
  UDR = DATA_TX[0];
}


Отправка последующих байт, с проверкой окончания данных:

Код: Выделить всё

void interrupt_USART_TXC_vect() org IVT_ADDR_USART__TXC {
  if(DATA_TX_INDEX < (_DATA_TX_COUNT)){
    UDR = DATA_TX[DATA_TX_INDEX];
    // next element in array
    DATA_TX_INDEX = DATA_TX_INDEX + 1;
  }
  else{
    DATA_TX_INDEX = 1;
    // Recive mode ON
    UCSRB |= (1 << RXEN);
    // Low level control pin
    PORTD &=~ (1 << 3);
  }
}


Прием запроса, тоже вектор прерывания:

Код: Выделить всё

void interrupt_USART_RXC_vect() org IVT_ADDR_USART__RXC {
  DATA_RX = UDR;
}
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: ADM485 время задержки

Сообщение YS »

while (!( UCSRA & (1<<UDRE)));


:facepalm:

Я же советовал заменить все ожидания UDRE на ожидание TXC. :idea:
Разница между теорией и практикой на практике гораздо больше, чем в теории.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Пробовал, не помогает...
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Провел опыты и заметил, что в зависимости от скорости USART'а меняется и время необходимой задержки включения порта. К примеру:
100 baud = 16 ms,
150 baud = 4 ms,
200 baud = 3 ms,
400 baud = 2 ms,
1200 baud = 1 ms,
4800 baud = 0 ms,
9600 baud = 0 ms

С учетом того, что мне данные скорости нужны, как-то не очень получается.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: ADM485 время задержки

Сообщение YS »

Посмотрел код.

UCSRB &=~ (1 << RXEN);


Зачем вы дергаете сам UART? В этом нет необходимости. В даташит я не вчитывался, но, возможно, время тратится на инициализацию внутреннего конечного автомата, что-то там такое вроде было.

Просто включите приемник, включите передатичик, а дальше переключайте только ADM485.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
krik_nk
Первый раз сказал Мяу!
Сообщения: 39
Зарегистрирован: Пн июл 01, 2013 11:59:25

Re: ADM485 время задержки

Сообщение krik_nk »

Спасибо за совет. Это убрал. И правда дергать думаю не за чем. А вот на счет этой задержки автомата, то в даташите вообще все характеристики в нс указанны, непонятно откуда мс вылезают.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: ADM485 время задержки

Сообщение YS »

Я имел в виду конечный автомат UART'а. В ADM никакого конечного автомата нет (ну, почти), это обычная логика. :)

Гм. А физически никакого конденсатора, например, на этой линии не висит?

Если есть возможность, снимите, пожалуйста, осциллограммы на входах переключения ADM и на линии данных (на двухканальном осциллографе, в одной сетке по времени).
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Ответить

Вернуться в «Периферия»