Modbus протокол и порт AVR scmRTOS

Modbus протокол на AVR микроконтроллереModbus протокол на AVR микроконтроллере организовать несложно. Достаточно сконфигурировать соответствующим образом USART, сформировать Modbus запрос, полученный ответ загрузить в буфер и дальше с ним выполнять все необходимые действия. Но если, допустим, стоит задача не только в формировании Modbus запроса, получении и обработке ответа от какого- либо устройства, но и формирование специфичесокого протокола передачи обработанных даных по USATR в другое устройство, то тут на помощь приходит операционная система реального времени для микроконтроллеров.

Что касается AVR микроконтроллеров то наиболее оптимальным вариантом для них на мой взгляд является операционная система реального времени scmRTOS. На ней вполне можно создать несколько процессов каждый из которых будет выполнять свою конкретную задачу. В данном посте представлен один из возможных вариантов организации обмена по протоколу Modbus между AVR мироконтроллером и датчиком давления 'Сапфир-22МП-ВН', с последуующей обработкой данных для передачи их в другй модуль или прибор.

Один из возможных вариантов решения задачки - AVR порт scmRTOS версии 310 + IDE IAR. Не будем останавливаться на процессе установки scmRTOS на AVR микроконтроллер поскольку все можно проследить на готовом проекте организации обмена по Modbus под IarAvr v5.

Прием данных Modbus организован по прерываниям USART1. Чтобы максимально облегчить режим приема данные по прерыванию на прием USART1 просто записываются в отдельный буфер побайтно, контролируя приход завершающего байта 0x0a.


//---------------------------------------------------------------------------
// Прием по Modbus (USART1)  
#pragma vector=USART1_RXC_vect
OS_INTERRUPT void Usart1_rxc_ISR()
{
  // Сброс сторожевого таймера
  __watchdog_reset();
  PORTC |= (1 << 7);
  
  OS::TISRW_SS ISRW;
  
//    ENABLE_NESTED_INTERRUPTS();
  // Визуализация приемов 
  PORTC &= ~(1 << 4);
  PORTC |= (1 << 4);
  __delay_cycles(10);                
  PORTC &= ~(1 << 4);
  
  // Чтение UDR1 в буфер (одновременно сброс RXC1)
  cRxBuf[cRxBufCount] = UDR1;
  // Регистрация конечного символа 
  if(cRxBuf[cRxBufCount] == 0x0a)
  {
    // Обнулить счетчик приемов     
    cRxBufCount = 0;
    // Просигналить в TProc3 когда принят последний символ
    Usart1_rxc.SignalISR();
  }
  else    
    cRxBufCount++; 
}
//---------------------------------------------------------------------------

По его приходу вызывается другой процесс который начинает обработку накопленных в буфере данных.Процесс обработки данных защелкивается Mutex.Lock(). Снимается защелка через Mutex.Unlock().


// Обработка данных принятых по Modbus  
template<> void TProc3::Exec()
{
  unsigned char n, Ks, KsReal;
  unsigned long lDataPressure;

  for(;;)
  {
    Sleep(1);
    
    // Визуализация процесса 
    PORTC &= ~(1 << 5);
    PORTC |= (1 << 5);
    __delay_cycles(50);                
    PORTC &= ~(1 << 5);
    
    Usart1_rxc.Wait();
    // Защелка для обработки и переброски данных 
    Mutex.Lock();

    // Подсчет контрольной суммы принятых данных 
    for(n = 1; n < cRxBufCount - 4; n++)
      Ks += cRxBuf[n];

    // Обнулить предыдущее давление     
    lDataPressure = 0;
      
    // Преобразование давления в норм. вид
    for(n = 5; n < 11; n++)
    {
      if(n < 10)
      {
        if((cRxBuf[n] & 0xf0) == 0x30)
          lDataPressure = (lDataPressure | (cRxBuf[n] & 0x0f)) << 4;
        else if((cRxBuf[n] & 0xf0) == 0x40)
          lDataPressure = (lDataPressure | ((cRxBuf[n] & 0x0f) + 9)) << 4;
      }
      // Последний не сдвигать
      else if (n == 10)
      {
        if((cRxBuf[n] & 0xf0) == 0x30)
          lDataPressure = (lDataPressure | (cRxBuf[n] & 0x0f));
        else if((cRxBuf[n] & 0xf0) == 0x40)
          lDataPressure = (lDataPressure | ((cRxBuf[n] & 0x0f) + 9));
      }
      // Определение контрольной суммы
      if(n == 11)
      {
        if((cRxBuf[n] & 0xf0) == 0x30)
          KsReal = (KsReal | (cRxBuf[n] & 0x0f)) << 4;
        else if((cRxBuf[n] & 0xf0) == 0x40)
          KsReal = (KsReal | ((cRxBuf[n] & 0x0f) + 9)) << 4;
      }
      // Последний не сдвигать
      else if (n == 12)
      {
        if((cRxBuf[n] & 0xf0) == 0x30)
          KsReal = (KsReal | (cRxBuf[n] & 0x0f));
        else if((cRxBuf[n] & 0xf0) == 0x40)
          KsReal = (KsReal | ((cRxBuf[n] & 0x0f) + 9));
      }
    }
    
    Mutex.Unlock();
  }
}

После этого можно использовать подготовленные данные в следующем процессе для их дальнейшей передачи в другой модуль. Вобщем както так. Код функции main снабжен обильными комментами. У кого встанет задача организации обмена по Modbus на AVR + scmRTOS представленный проект будет полезен. Замечания и комменты по ссылке ниже по тексту.

Top.Mail.Ru