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

в sys_mbox_post() убрал цикл, заменил portMAX_DELAY на 1000(т.е. на 1 секунду). Ethernet перестал отваливаться, обнаружил, что функция xQueueSendToBack возвращает ошибку errQUEUE_FULL.

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


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

обнаружил, что структура pxQueue не подгружалась при работе с модбасом

у меня еще не пришло полное понимание & и *, поэтому решил поиграться с ними в порте freemodbus (portevent.c)

sys_mbox_post( xMailBox, &eMailBoxEvent );

заменил на

sys_mbox_post( &xMailBox, &eMailBoxEvent );

структура подгрузилась и функция xQueueSendToBack перестала выдавать ошибку errQUEUE_FULL, но что-то я сильно сомневаюсь, что в порте была ошибка

 

Больше не сомневаюсь, это реально ошибка в порте, изменил на &xMailBox во всех функциях portevent.c и freemodbus заработал. Большое спасибо разработчикам freemodbus, так и без работы можно оставить, яж на испытательном сроке еще:) но все равно им спасибо за труд:)

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

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


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

Помогите реализовать Modbus-slave на базе Atmega32A. Условие: применяемый на freemodbus 16-разрядный таймер1 использовать нельзя - он нужен мне для реализации 16-разрядного аппаратного ШИМа.

 

Что уже сделано:

1) Материалы на freemodbus.org изучил (хотя и не во всем разобрался).

2) Нашел http://forum.easyelectronics.ru/viewtopic....mp;hilit=modbus - во втором посте выложено решение для 168й атмеги по замене таймера 1 на таймер 0. Скачал, собрал в свой проект, откомпилировал для 168й атмеги.

2) Заменил ссылки на таймер 0А (для 168й меги) на таймер 0 для 32й меги.

3) 2) Заменил ссылки на таймер 0В (для 168й меги) на таймер 2 для 32й меги.

4) Откомпилировал в AtmelStudio6 без ошибок.

5) Подключил контроллер через мах485 и конвертер i-7561 (485/usb) к компьютеру.

6) ОРС-сервером Lectus отправляю запрос 01 03 00 01 00 01 D5 CA, осциллографом наблюдаю соответствующую последовательность на ножке микроконтроллера, НО сам контроллер молчит и в ответ никаких сообщений не выдает.

 

Предполагаю два варианта проблемы:

1) Простая замена таймеров оказалась некорректной.

2) Неверно "привязаны" регистры usRegInputBuf и usRegHoldingBuf.

 

Помогите пожалуйста разобраться

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


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

Помогите пожалуйста разобраться

Для начала, RTFM - Related Pages -> Porting for RTU/ASCII

 

Ну а дальше тщательная трассировка.

Самое простое, это банальный бит четности (проверка на четность по стандарту Modbus RTU/ASCII).

Если прерывания ловятся и пакет принимается, должен выставляться эвент и функция поллинга перенаправляет в нужный коллбэк.

Дальше убеждаемся, что формируется ответный пакет, и вот тут может всплыть 485-й с переключением потока.

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


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

А может слейв адрес не тот?

 

Спасибо. С принципом работы самого модбаса рту мне все ясно. Проблема возникла с его конкретной реализацией. В частности с заменой таймера в стандарном "австрийском" варианте.

 

Адрес тот, регистры те...

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


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

Спасибо. С принципом работы самого модбаса рту мне все ясно. Проблема возникла с его конкретной реализацией. В частности с заменой таймера в стандарном "австрийском" варианте.

Я с AVR не работал, но думаю если вы выложите свои исходники из /port то знающие люди помогут. А последовательность действий при отладке очень хорошо описал MrYuran.

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


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

Помогите пожалуйста разобраться

Дык покажите свой porttimer.c и portserial.c и еще чего там меняли по сравнению с базовой демкой. Там же всё элементарно... :laughing:

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


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

Дык покажите свой porttimer.c и portserial.c и еще чего там меняли по сравнению с базовой демкой. Там же всё элементарно... :laughing:

 

файл добавить не получается, поэтому пишу сам листинг. Примечание: исходные строчки не удалены, а закомментированы. Следом идут мои.

 

/*

* FreeModbus Libary: ATMega168 Port

* Copyright © 2006 Christian Walter <[email protected]>

* Modified in 2010 by drvlas:

* Only RTU mode.

* Use T0 instead of T1. Implemented only on ATmega168

*/

 

/* ----------------------- AVR includes -------------------------------------*/

#include <avr/io.h>

#include <avr/interrupt.h>

//#include <avr/signal.h>

 

/* ----------------------- Platform includes --------------------------------*/

#include "../include/port.h"

 

/* ----------------------- Modbus includes ----------------------------------*/

#include "../include/mb.h"

#include "../include/mbport.h"

 

/* ----------------------- Defines ------------------------------------------*/

#define MB_TIMER_PRESCALER ( 1024UL )

#define MB_TIMER_TICKS ( F_CPU / MB_TIMER_PRESCALER )

#define MB_50US_TICKS ( 20000UL )

 

/* ----------------------- Static variables ---------------------------------*/

static USHORT usTimerOCRADelta;

//static USHORT usTimerOCRBDelta;

 

/* ----------------------- Start implementation -----------------------------*/

BOOL

xMBPortTimersInit( USHORT usTimerout50us )

{

/* Calculate overflow counter an OCR values for Timer0. */

usTimerOCRADelta =

( MB_TIMER_TICKS * usTimerout50us ) / ( MB_50US_TICKS );

if( usTimerOCRADelta > 255) return FALSE;

 

//TCCR0A = 0x00; // Normal Mode + Output Compare interrupt

TCCR0 = 0x00; // Normal Mode + Output Compare interrupt

//TCCR0B = 0x00;

TCCR2 = 0x00;

 

 

// TCCR1C = 0x00;

 

vMBPortTimersDisable( );

 

return TRUE;

}

 

 

inline void

vMBPortTimersEnable( )

{

TCNT0 = 0x0000;

if( usTimerOCRADelta > 0 )

{

//TIMSK0 |= _BV( OCIE0A );

TIMSK |= _BV( OCIE0 );

//OCR0A = usTimerOCRADelta; // MUST be < 256

OCR0 = usTimerOCRADelta; // MUST be < 256

}

 

//TCCR0B |= _BV( CS12 ) | _BV( CS10 ); // Fosc/1024

TCCR2 |= _BV( CS12 ) | _BV( CS10 ); // Fosc/1024

}

 

inline void

vMBPortTimersDisable( )

{

/* Disable the timer. */

//TCCR0B &= ~( _BV( CS12 ) | _BV( CS10 ) );

TCCR2 &= ~( _BV( CS12 ) | _BV( CS10 ) );

/* Disable the output compare interrupts for channel A */

//TIMSK0 &= ~( _BV( OCIE0A ) );

TIMSK &= ~( _BV( OCIE0 ) );

/* Clear output compare flags for channel A/B. */

//TIFR0 |= _BV( OCF0A ) ;

TIFR |= _BV( OCF0 ) ;

}

 

//SIGNAL( SIG_OUTPUT_COMPARE0A )

SIGNAL( SIG_OUTPUT_COMPARE0 )

{

( void )pxMBPortCBTimerExpired( );

}

 

 

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


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

Помогать так уж буквально не буду. Почитайте стр.84 даташита

Ошибки:

1. TCCR2 тут никаким боком. Работаем с TCCR0. Это в тексте vMBPortTimersEnable( )

2. Стесняюсь спросить, чему у Вас равно F_CPU ?Очень может быть, тик 100мкс неправильно посчитан.

--

Вообще, при наличии протеуса хоть 7.8 - такие ошибки симулем выловить как два пальца. Даже рисовать ничего не надо - поставили МК, питания и виртуал терминал, настроили - и поехали. Имхо получше чем студия.

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


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

Помогать так уж буквально не буду. Почитайте стр.84 даташита

Ошибки:

1. TCCR2 тут никаким боком. Работаем с TCCR0. Это в тексте vMBPortTimersEnable( )

2. Стесняюсь спросить, чему у Вас равно F_CPU ?Очень может быть, тик 100мкс неправильно посчитан.

--

Вообще, при наличии протеуса хоть 7.8 - такие ошибки симулем выловить как два пальца. Даже рисовать ничего не надо - поставили МК, питания и виртуал терминал, настроили - и поехали. Имхо получше чем студия.

 

Да, наверное Вы правы,- попробую разобраться с Протеусом.

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


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

Ребят удалось портировать? Никак не могу разобраться как прерывание описать надо, чтобы либа поняла, что прерыание случилось (прерывание по приему я имею ввиду). Что нужно засунуть в обработчик прерывания, какую функцию либы? Вот тут что то вообще непонятное:

static void prvvUARTTxReadyISR( void )
{
    CHAR cByte;
    ( void )xMBPortSerialGetByte( &cByte );
    /* Now cByte should contain the character received. */
}

 

Я пишу порт на IAR для at90can32. Перерыл весь manual, сказано надо описать прерывание, а что туда писать непонятно. Подскажите будьте добры

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


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

Вообщем портировать удалось, кажется все по правилам, но пока ничего не заработало. Буду крайне признателен, если поможете. Написал portserial.c и porttimer.c. Объявил eMBRegHoldingCB(), eMBRegCoilsCB(), eMBRegDiscreteCB(), eMBRegInputCB(). Компилю, зашиваю, запускаю и наблюдаю следующее: при запросе от мастера read holding register (0x03) вызывается функция eMBRegHoldingCB(), и после ее отработки стек перестает работать (в ответ мастер не получает ни ответа ни привета), прерывания по приему после этого перестают срабатывать (хотя первые 8 байт из первого запроса прерывание вызывают). Но проц не зависает, все продолжает крутиться, ошибок никаких eMBPoll() не возвращает. Я уже кажется перечитал все форумы и темы, чего то похоже не понимаю.

Запрос от мастера:

01 03 03 E9 00 04 95 B9

portserial.c

porttimer.c

main.c

 

Сам проект, если что-то непонятно. Вот, надеюсь на вашу помощь...

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


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

Люди, я может чего не понимаю, но получается следующее: отправкой исходящих пакетов занимается функция pxMBFrameCBTransmitterEmpty(), которая по-сути переадресована в случае с протоколом modbus RTU на функцию xMBRTUTransmitFSM(). А поскольку эта функция вызывается из прерывания по окончанию отправки, то выходит, чтобы стек ответил на входящий запрос от мастера, нужно после того как входящий запрос был распарсен, нужно "пинуть" стек и один раз вызвать xMBRTUTransmitFSM(). Я добавил этот вызов в функции eMBRTUSend() в файле mbrtu.c. Когда я так сделал стек заработал.

eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{
   eMBErrorCode    eStatus = MB_ENOERR;
   USHORT          usCRC16;

   ENTER_CRITICAL_SECTION(  );

   /* Check if the receiver is still in idle state. If not we where to
    * slow with processing the received frame and the master sent another
    * frame on the network. We have to abort sending the frame.
    */
   if( eRcvState == STATE_RX_IDLE )
   {
       /* First byte before the Modbus-PDU is the slave address. */
       pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
       usSndBufferCount = 1;

       /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
       pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
       usSndBufferCount += usLength;

       /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
       usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
       ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
       ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );

       /* Activate the transmitter. */
       eSndState = STATE_TX_XMIT;
       vMBPortSerialEnable( FALSE, TRUE );
       fledGreen();


/**
*           ВОТ ЭТО Я ДОБАВИЛ, ЧТОБЫ ПИНУТЬ СТЕК !
*/

       xMBRTUTransmitFSM();   





   }
   else
   {
       eStatus = MB_EIO;
   }
   EXIT_CRITICAL_SECTION(  );
   return eStatus;
}

 

Почему он сразу не работает?!!

P.S: В указанных выше исходниках у меня НЕ включено прерывание по отправке, сейчас это исправлено.

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


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

Доброго всем дня. Портирую freemodbus на stm32. Holding регистры читаются и записываются нормально, но вот Discrete читаются только 8 бит. В чем может быть проблема?

 

#define REG_DISCRETE_START 1
#define REG_DISC_SIZE      24

unsigned char ucRegDiscBuf[REG_DISC_SIZE / 8];

eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    short           iNDiscrete = ( short )usNDiscrete;
    unsigned short  usBitOffset = 0;

    if( ( usAddress >= REG_DISCRETE_START ) &&
        ( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISC_SIZE ) )
    {
        usBitOffset = ( unsigned short )( usAddress - REG_DISCRETE_START );
        while( iNDiscrete > 0 )
        {
            *pucRegBuffer++ =
                xMBUtilGetBits( ucRegDiscBuf, usBitOffset,
                                ( unsigned char )( iNDiscrete >
                                                   8 ? 8 : iNDiscrete ) );
            iNDiscrete -= 8;
            usBitOffset += 8;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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