Перейти к содержанию
    

Здравия желаю всем !

 

Делаю устройство на Mega162 с двумя протоколами modbus.

USART0 - master, посылает всего 11 разных запросов. USART1 - slave, отвечает на эти 11 запросов с некоторыми корректировками. То есть устройство устанавливается между master и slave и общается с ними с нужными мне исправлениями.

 

В общем, сделал отдельно master и slave - работает, но когда все в целом, то работает только slave, а master зацикливается на 1-й посылке, иногда 2-я проскакивает.

 

Вроде проблема с прерываниями, т.к. slave постоянно принимает и отвечает, и не дает master работать. Игрался с запретом прерываний, но ничего не помогло.

 

Также делал чтобы slave принял, ответил, а потом master послал, принял, поочередно, но так теряется слейвом фреймы.

 

У кого могут быть какие идеи? Такое устройство возможно ли вообще?

 

Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

У кого могут быть какие идеи? Такое устройство возможно ли вообще?

...

Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кода вообще много... Постараюсь основное. Сильно не пинайте, т.к. учусь уму разуму...

Это один из вариантов. Но не один из них корректно не работает

 

 

void StartTrans0(void)                                
{
 DisableReceive0;                                       
 SetBit(PORTA,1);                                    
 TrCount0=0;                                            
 GoTrans0;
}                                                                

void StartTrans1(void)                                   
{
 SetBit(PORTA,0);                                      
 TrCount1=0;                                               
 GoTrans1;                                               
}                                                                 


interrupt [uSART0_DRE] void usart0_udre_isr(void) 
{
if (TrCount0<cNumTrByte0-1)
       {
       UDR0=cmTrBuf0[TrCount0];
       TrCount0++;
       }
 else
       {  
       UDR0=cmTrBuf0[cNumTrByte0-1];
       StopTrans0;
       TrCount0=0;
       FinTrans=1;        
       }
}

interrupt [uSART0_TXC] void usart0_tx_isr(void)
{
if (TrCount0<cNumTrByte0-1)
         {
          StopTrans0;
          FinTrans=1;
          ClrBit(PORTA,1);                      
          EnableReceive0;                      
}  

interrupt [uSART0_RXC] void usart0_rx_isr(void) // USART0 I?a?uaaiea i?eaiieea IANOA?A
{
char status;
status=UCSR0A;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
         {
         if (StartRec0==0)
               {
                StartRec0=1;                            
                RcCount0=0;                             
                cmRcBuf0[RcCount0++]=UDR0;   
                TCCR1B=0x05;                             
                TCNT1H=0xFF;
                TCNT1L=0xEA;                             
               }
         else
               {
                cmRcBuf0[RcCount0++]=UDR0;    
                TCNT1H=0xFF;
                TCNT1L=0xEA;                            
               }
         }
}

interrupt [uSART1_RXC] void usart1_rx_isr(void) 
{
char status,data;
status=UCSR1A;
data=UDR1;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
  {
 if (StartRec1==0)                                                                     
       {                       
       StartRec1=1;                                                                     
       RcCount1=0;                                                                       
       cmRcBuf1[RcCount1++]=data;                                              
       TCNT0=0xE9;                                                                      
       TCCR0=0x05;                                                                      
       }                                                                                          
 else
       {
               if (RcCount1<MaxLenghtRecBuf1)
                       {
                       cmRcBuf1[RcCount1++]=data;
                       }
               else
                       {
                       cmRcBuf1[MaxLenghtRecBuf1-1]=data;
                       }
       TCNT0=0xE9; 
       }
  }  
}

interrupt [uSART1_DRE] void usart1_udre_isr(void) // USART1 I?a?uaaiea ia?aaao?eea IIA?EIAIIIAI
{
 if (TrCount1<cNumTrByte1+1)
       {
       UDR1=cmTrBuf1[TrCount1];
       TrCount1++;
       }
 else
       {                                    
       StopTrans1;
       //ClrBit(DDRA,0);
       ClrBit(PORTA,0); //PA0 a 0 - ?aaioa a?aeaa?a 485 ia i?eai
       //EnableReceive1;
       TrCount1=0;
       }
}

interrupt [TIM0_OVF] void timer0_ovf_isr(void)                 
{

if (StartRec1==1)               
       {
       StartRec1=0;            
       cNumRcByte1=RcCount1;   
       bModBus1=1;             
       TCCR0=0;                
       }
}

char ModBus0 (void)              
         {
         int TempI;
         if (cmRcBuf0[0]==0x01 && cmRcBuf0[1]==0x03 && cmRcBuf0[2]==0x02)
               {
               ...
	    }
         }

char ModBus2 (void)             
         {
         switch (ModFlag)
               {
               case (1):              
                    {
                    ...
                    }
               }
         }


interrupt [TIM1_OVF] void timer1_ovf_isr(void)                
{
           if (StartRec0==1)
                {
                 StartRec0=0;
                 cNumRcByte0=RcCount0;
                 bModBus0=1;
                 TCCR1B=0x00;
                 DisableReceive0;
                }
          else
                {
                 TCCR1B=0x00;      
                 TCNT2=0x00;       
                 TCCR2=0x07;
                 DisableReceive0;
                }            
}

interrupt [TIM2_OVF] void timer2_ovf_isr(void)                
{
           TrCount0=0;
           cNumTrByte0=ModBus2();                        
           StartTrans0();                                          
           TCCR2=0x00;
}

char ModBus1 (char NumByte) 
       {
	...        
       }
}


void main(void)
{
 Setup();                                                       
 StartUART0();                                              
 StartUART1();                                              
 SetBit(DDRD,0);SetBit(PORTD,0);                     
 ClrBit(DDRD,1);ClrBit(PORTD,1);                       
 SetBit(PORTA,1);
 ClrBit(DDRB,2);ClrBit(PORTB,2);                      
 SetBit(DDRB,3);SetBit(PORTB,3);                
 EnableReceive1;                                         
 ClrBit(PORTA,0);
 TCCR2=0x07; 
 TCNT2=0x00;
 #asm("sei")
while (1)
     { 
          #asm("cli") 
           if (bModBus0==1)
             {
              ModBus0();                                                          
              bModBus0=0;
              TCNT2=0x00;
              TCCR2=0x07;
             }
           if (bModBus1==1)                                                  
              {
               cNumTrByte1=ModBus1(cNumRcByte1);       
               if (cNumTrByte1!=0) StartTrans1();                 
               bModBus1=0;
              }                                                                    
         #asm("sei")
      }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию!

Буфферизация приемника слейва, думАю, не поможет, т.к. мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа, а обработку тоже старался сделать быструю с минимумом подсчетов...

Может проще все это сделать на 2х мегах8 и соединить их через spi? Не будет ли оно также конфликтовать?

Если в коде не понятны фукции какие-то, пишите..расскажу

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не разбирался, но взглянул. Заметил такое: выключение передачи - StopTrans1- делается не по TXC, следовательно может подрезать последний байт (стоп-бит). Проверить подручными средствами этот момент проще, если убрать 485 и подключить UART-ы напрямую, но, ИМХО, и так видно. Не думаю, что это единственная проблемка.

мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа
это чего-то надуманное - минимальная пауза нужна как маркер пакета, а реально пауза может достигать сотен миллисекунд и более. В продвинутых реализация даже поддерживается ответ слейва типа "я занят, пинай позже"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) С работой слейва проблем не возникало. Смотрю модбас монитором. Но впринципе, спасибо, можно подправить...

2) Вопрос с 3.5 задержкой связан с готовым устройством (мастером), который при отсутствии ответа генерит ошибки в своей программе...На 2-й запрос - точно... Для "моего" то мастера можно и больше задержки делать..

Изменено пользователем vetalxh

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вроде проблема с прерываниями, т.к. slave постоянно принимает и отвечает, и не дает master работать. Игрался с запретом прерываний, но ничего не помогло.

Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера.

А вообще, если включить телепатию, я думаю, у вас грабли. Предположительно нет запрета прерываний от передатчика после того, как данные для передачи закончились.

 

Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...

Так поднимимите кварц, раза в четыре. Хотя на 2400 нагрузка небольшая.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос с 3.5 задержкой связан с готовым устройством (мастером)

По спецификации Modbus_over_serial_line время 3.5 Тсимвола (точнее параметр описан там же) не задержка на начало ответа, а МИНИМАЛЬНАЯ ПАУЗА, позволяющая определить конец пакета

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

sensor_ua, спасибо, буду думать...

А можно по-подробнее про "Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера" ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Организуйте прерывание от таймера и проверяйте в нем готовность приемника и передатчика, наличие данных и места в буфере. Только так сможете управлять последовательностью обработки и приоритетами уартов. Кроме того, это позволит исключить затраты на вызовы уартовских прерываний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Организуйте прерывание от таймера и проверяйте в нем готовность приемника и передатчика, наличие данных и места в буфере. Только так сможете управлять последовательностью обработки и приоритетами уартов. Кроме того, это позволит исключить затраты на вызовы уартовских прерываний.

Спасибо...Подумаю над этим тоже

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма? Если отказаться от прерываний уартов, то как данные попадут в буфер? Что-то туговато...А кусочком кода никто не поделится? Или алгоритмом хотябы...Спасибо

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма?

Так там же буферизированный приемник, если TXC не установился - значит нет данных, если установился - значит есть, если при этом DOR сброшен, значит данные валидны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Короче, думал-думал...Решил обойти все это еще одним способом.

 

1. Разрешаю прием Slave.

2. Slave получил, обработал, ответил.

3. Slave опять получил, обработал, ответил

...

Так раза 3-4...

6. Запрещаю прием Slave и разрешаю посылку Master.

7. Master послал, принял, обработал.

И опять в начало "Разрешаю прием Slave"

 

В принципе, такое тоже должно меня устроить, но после того, как запретил прием Slave

 

UCSR1B&=~(1<<4); UCSR1B&=~(1<<7)

 

не могу заново разрешить его разрешить... :help:

Делаю так

 

UCSR1B|=(1<<4); UCSR1B|=(1<<7)

 

Может нога RX повисла в левом состоянии.. Но я включал подтяжку для нее в начале программы (вместе для мастера и слейва)

 

void Setup(void)
{
PORTB=0x04;
DDRB=0x00;
PORTD=0x01;
DDRD=0x00;
}

 

И еще...Может ли камень уходить в рестарт?? Иногда модбас монитором замечаю, что идет цикл программы, а потом Мастер начинает посылку с 1й...По ходу выполнения программы такое не возможно, т.е. имхо или сброс, или хз что...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У кого могут быть какие идеи? Такое устройство возможно ли вообще?

А какие проблемы? далаете нормальный протоколо-независимый драйвер UART'а c буферизированным приемом и передачей.

Пишете две функции-задачи по очереди вызываемые в основном цикле программы, одна для обслуживания мастера, вторая для слейва. Никаких Delay_ms и прочий хлам не использовать!! Если слейв требует какого-то реалтайма для выдержки 3.5 символьного интервала, что организуется одним из таймеров, то modbus мастер - это совершенно неприхотливая задача. Выплевывать данные в UART и забирать ответ через скажем 100ms. Вот и вся ее суть.

 

Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...

Какой смысл ставить такой медленный кварц, и пользовать только ~20% производительности МК?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...