Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: С++, обработчик прерывания как статическая ф-я класса.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
AHTOXA
Пытаюсь запихать. Запихал:
Код
class    TUart1 : public TCustomUart
{
    public:
        TUart1(uint32_t baudrate) {hw_init(baudrate);}
    protected:
        ...
        virtual void hw_init(uint32_t baudrate);
        virtual void write_tx_reg(char ch) { TXBUF0 = ch; }
        static interrupt(UART0RX_VECTOR) usart0_rx(void);
        static interrupt(UART0TX_VECTOR) usart0_tx(void);
};

...

interrupt(UART0TX_VECTOR) TUart1::usart0_tx(void)
{
    OS::TISRW ISR;
    char ch;
    if (Uart1.TxChannel.get_count())
    {
        Uart1.TxChannel.pop(ch);
        TXBUF0 = ch;
    }
    else
    {
        Uart1.tx_active = false;
    }
}


Делаю это для того, чтобы в прерывании обращаться к private-членам класса. Вроде всё получается. Единственное неудобство состоит в том, что пока я не напишу где-нибудь
Код
void TUart1::hw_init(uint32_t baudrate)
{
    typedef void (* Handler)(void);
    volatile Handler ptr;
    ...
    ptr = &usart0_rx;
    ptr = &usart0_tx;
}

, обработчики прерываний не линкуются. Может есть какой-то более цивильный способ?

Ну и вообще, хотелось бы не статическую функцию, а просто функцию классаsmile.gif

ЗЫ. msp-gcc.
Legotron
Цитата(AHTOXA @ Dec 4 2008, 12:35) *
ptr = &usart0_rx;
ptr = &usart0_tx;

А разве здесь нужен знак "&"?
По-моему, название функции является указателем, как с массивами...

По-поводу проблемы: а будет линковаться, если описать тела функций обработчиков внутри класса, не проверяли?
xelax
Цитата(AHTOXA @ Dec 4 2008, 12:35) *
Ну и вообще, хотелось бы не статическую функцию, а просто функцию классаsmile.gif


В нестатичные членах класса всегда передаётся указатель на объект, который их вызвал.
Если сделать прерывания нестатичными, то как и куда им будет передаваться этот указатель??? 07.gif
AHTOXA
Цитата(Legotron @ Dec 4 2008, 14:45) *
А разве здесь нужен знак "&"?
По-моему, название функции является указателем, как с массивами...

Да тут без разницы, нужно просто обращение...
Цитата
По-поводу проблемы: а будет линковаться, если описать тела функций обработчиков внутри класса, не проверяли?

Не, не помогает.
Сергей Борщ
Цитата(AHTOXA @ Dec 4 2008, 11:35) *
Единственное неудобство состоит в том, что пока я не напишу где-нибудь
Код
    ptr = &usart0_rx;
    ptr = &usart0_tx;
}
Фигня какая-то...
Код
class adc_t
{
public:
    typedef uint16_t sample_t;
    static sample_t const MAX_VALUE = 4096;

    template<adc_channel_t channel>
    INLINE inline static sample_t digital();   // adc raw value
    template<adc_channel_t channel>
    INLINE inline static float analog();        // adc result converted to analog
........
private:
    static OS_INTERRUPT void IntHandler();

    static OS::TMutex Locker;
    static OS::TEventFlag Ready;
};


OS_INTERRUPT interrupt(ADC12_VECTOR) adc_t::IntHandler()
{
    OS::TISRW ISRWrapper;
    ADC12IV;
    Ready.SignalISR();
    Locker.UnlockISR();
    ADC12IE = 0;
}
Все линкуется...
AHTOXA
Цитата(Сергей Борщ @ Dec 4 2008, 15:11) *
Фигня какая-то...


Не то словоsmile.gif Похоже мне попалась какая-то неудачная сборка mspgcc:)
Сергей Борщ
Цитата(AHTOXA @ Dec 4 2008, 12:29) *
Не то словоsmile.gif Похоже мне попалась какая-то неудачная сборка mspgcc:)
Возможно. Могу выслать свою или собери из cvs.
Я тут немного подумал, и пришел к выводу, что в исходном коде есть концептуальная ошибка: UARTов может быть несколько и вшивать конкретный вектор в класс неправильно. Там должен быть inline обработчик, который вызывается из реального обработчика. А реальный обработчик будет знать, с каким объектом вызывать. Примерно так:

Код
class uart_t
{
public:
    inline INLINE void init(uint32_t const divider);
    inline INLINE bool hasinput() { return Rx.Buffer.has_data(); }
    bool get(uint8_t &data, timeout_t timeout = 0);
    void put(uint8_t data);
private:
....
    friend void UART0_RxHandler();
    friend void UART0_TxHandler();
    friend void UART1_RxHandler();
    friend void UART1_TxHandler();

    inline INLINE void RxHandler();
    inline INLINE void TxHandler();
};

OS_INTERRUPT interrupt(USCIAB0RX_VECTOR) UART0_RxHandler()
{
    OS::TISRW ISRW;
    UART0.RxHandler();
}

OS_INTERRUPT interrupt(USCIAB0TX_VECTOR) UART0_TxHandler()
{
    OS::TISRW ISRW;
    UART0.TxHandler();
}

OS_INTERRUPT interrupt(USCIAB1RX_VECTOR) UART1_RxHandler()
{
    OS::TISRW ISRW;
    UART1.RxHandler();
}

OS_INTERRUPT interrupt(USCIAB1TX_VECTOR) UART1_TxHandler()
{
    OS::TISRW ISRW;
    UART1.TxHandler();
}
AHTOXA
Цитата(Сергей Борщ @ Dec 4 2008, 17:09) *
Возможно. Могу выслать свою или собери из cvs.

Вышлите пожалуйста, собирать пока не готовsmile.gif
Цитата
UARTов может быть несколько и вшивать конкретный вектор в класс неправильно.

Я немного с другой стороны подхожу. У меня есть базовый TCustomUart, с pure virtual ф-ями доступа к аппаратуре. И от него наследники для каждого физического UARTа, с реализациями этих функций и со статическими обработчиками прерываний.
Цитата
Там должен быть inline обработчик, который вызывается из реального обработчика. А реальный обработчик будет знать, с каким объектом вызывать.

Можно и так, надо будет обмозговатьsmile.gif

Вот кстати тестовый проектик:
Нажмите для просмотра прикрепленного файла
dxp
Цитата(AHTOXA @ Dec 4 2008, 15:35) *
Ну и вообще, хотелось бы не статическую функцию, а просто функцию классаsmile.gif

Этого нельзя. Обработчик прерывания не может быть нестатической функцией-членом класса. При вызове нестатической функции-члена ей всегда неявно передается указатель this (понятно для чего smile.gif ), что легко реализуется при обычном вызове, т.е. когда код выполняется "синхронно". А прерывание - это асинхронное событие, программа (компилятор, процессор) "не знает", когда оно произойдет (и не может знать), поэтому вызов функции с передачей this практически нереализуем - какой this передавать? Ведь нестатическая функция-член всегда вызвается для конкретного экземляра класса (объекта), его адрес четко известен в точке вызова. Чего нельзя сказать про случай с прерыванием - для какого объекта делается вызов?

Поэтому обработчик прерывания - это обычная функция. Либо статическая функция-член класса, которая отличается от обычной только правами доступа к закрытым членам класса и областью видимости (scope). Все, других отличий нет. Именно поэтому чтобы из статической функции-члена класса добраться до представления (потрохов) конкретного объекта, обязательно надо явно сообщать адрес этого конкретного объекта.
AHTOXA
Цитата(dxp @ Dec 4 2008, 17:49) *
Этого нельзя.


Да это понятноsmile.gif Я так, на всякий случай, вдруг наука что-то придумала, а я не в курсе biggrin.gif
AHTOXA
Короче, разобрался я, в чём причина. Всё дело в шаблонахsmile.gif
Базовый класс у меня объявлен как шаблон:
Код
template<uint16_t rx_buf_size, uint16_t tx_buf_size>
class    TCustomUart
{
    public:
        TCustomUart() : RxChannel(), TxChannel(), tx_active(false) { }

        void    putchar(char ch);
        void    puts(char * ch);
        char    getchar(void);
        ...
    protected:
        OS::channel<char, rx_buf_size> RxChannel;
        OS::channel<char, tx_buf_size> TxChannel;

        virtual void disable_tx_interrupt(void) = 0;
        virtual void enable_tx_interrupt(void) = 0;
        virtual void write_tx_reg(char ch) = 0;
        ...
};


соответственно, класс uart1:
Код
template<uint16_t rx_buf_size, uint16_t tx_buf_size>
class    TUart1 : public TCustomUart<rx_buf_size, tx_buf_size>
{
        ...
        static OS_INTERRUPT void usart0_rx(void);
        static OS_INTERRUPT void usart0_tx(void);
};

- тоже шаблон.
Убрав шаблоны, получил нормальную линковку обработчиков прерываний.
Видимо, это так работает механизм шаблонирования - всё, что не вызывается, то не инстанцируется?
vik0
Цитата(AHTOXA @ Dec 4 2008, 17:35) *
Видимо, это так работает механизм шаблонирования - всё, что не вызывается, то не инстанцируется?

Именно.
Можете попробовать явное инстанцирование (explicit instantiation):
Код
// в синтаксисе возможны ошибки - сейчас точный синтаксис не вспомню  :(
template void TUart1<конкретные значения параметров шаблона>::usart0_rx(void);
AHTOXA
Цитата(vik0 @ Dec 5 2008, 00:25) *
Можете попробовать явное инстанцирование (explicit instantiation):


То, что нужно, спасибо!
Vitaliy_ARM
Цитата(AHTOXA @ Dec 5 2008, 00:20) *
То, что нужно, спасибо!


А можно конечный кусок кода увидеть
Сергей Борщ
Цитата(Vitaliy_ARM @ Dec 6 2008, 14:00) *
А можно конечный кусок кода увидеть
Код
template  void TUart1<размер1, размер2>::usart0_rx();
template  void TUart1<размер1, размер2>::usart0_tx();
Страуструп, конец прилдожения B, явное инстанцирование.
koluna
Пытаюсь сделать следующим образом, но выдаются сообщения об ошибках.

h-файл:
Код
class TUSART_Coding : public TUSART
{
    private:
        static OS_INTERRUPT void TXHandler(void); // 39 строка
        static OS_INTERRUPT void RXHandler(void); // 40 строка
...
};


cpp-файл:
Код
OS_INTERRUPT interrupt(USART_RX_vect) TUSART_Coding::RXHandler(void)
{
    OS::TISRW_SS ISRW;
    Read_Next_Byte();
};

OS_INTERRUPT interrupt(USART_TX_vect) TUSART_Coding::TXHandler(void)
{
    OS::TISRW_SS ISRW;
    Write_Next_Byte();
};



39 error: expected unqualified-id before string constant
40 error: expected unqualified-id before string constant


В чём может быть дело?
AHTOXA
Скорее всего нет слова #include <scmRTOS.h> до объявления.
Да и не нужен этот атрибут (OS_INTERRUPT) в объявлении функции (в h-файле). Вот в определении (в cpp) - да, нужен.
koluna
Цитата(AHTOXA @ Jul 31 2009, 20:59) *
Скорее всего нет слова #include <scmRTOS.h> до объявления.


В .h было.
В .cpp не было.

Цитата
Да и не нужен этот атрибут (OS_INTERRUPT) в объявлении функции (в h-файле).


Убрал. Эти ошибки исчезли, но появились новые...
А что это за атрибут? Нашёл в исходниках, но пока не понял для чего он sad.gif

Новые ошибки на код:

Код
OS_INTERRUPT interrupt(USART_RX_vect) TUSART_Coding::RXHandler(void) // Строка №284
{
    OS::TISRW_SS ISRW;
    Read_Next_Byte();
};

OS_INTERRUPT interrupt(USART_TX_vect) TUSART_Coding::TXHandler(void) // Строка №297
{
    OS::TISRW_SS ISRW;
    Write_Next_Byte();
};



TUSART_Coding.cpp|284|error: expected constructor, destructor, or type conversion before '(' token
TUSART_Coding.cpp|297|error: expected constructor, destructor, or type conversion before '(' token


Что это?

Кстати, вот здесь вот OS_INTERRUPT есть в описании:
http://electronix.ru/forum/index.php?showt...st&p=511104
AHTOXA
Цитата(n_bogoyavlensky @ Aug 3 2009, 11:41) *
В .h было.
В .cpp не было.


А .h включен в .cpp? smile.gif

Цитата
Убрал. Эти ошибки исчезли, но появились новые...
А что это за атрибут? Нашёл в исходниках, но пока не понял для чего он sad.gif


Он содержит дополнительные атрибуты для функции-обработчика прерывания. Например, __arm для АРМов. У вас какой проц? Какой компилятор? И как выглядит объявление OS_INTERRUPT?

Цитата
Что это?

такое чувство, что не хватает слова void:
OS_INTERRUPT interrupt(USART_TX_vect) void TUSART_Coding::TXHandler(void) // Строка №297


Цитата
Кстати, вот здесь вот OS_INTERRUPT есть в описании:
http://electronix.ru/forum/index.php?showt...st&p=511104


Оно не мешает, просто там в нём нет нужды (имхо).
koluna
Цитата(AHTOXA @ Aug 3 2009, 10:36) *
А .h включен в .cpp? smile.gif


Конечно включен smile.gif

Цитата
Он содержит дополнительные атрибуты для функции-обработчика прерывания. Например, __arm для АРМов. У вас какой проц? Какой компилятор? И как выглядит объявление OS_INTERRUPT?


По поводу дополнительных атрибутов понятно уже. Хотелось бы узнать что за атрибуты и для чего конкретно smile.gif
Процессор ATmega168.
Компилятор WinAVR20071221.

OS_Target.h:
Код
# define    OS_INTERRUPT    extern "C" __attribute__((__signal__,__INTR_ATTRS))


\avr\interrupt.h:
Код
#  define __INTR_ATTRS used, externally_visible


Цитата
такое чувство, что не хватает слова void:
OS_INTERRUPT interrupt(USART_TX_vect) void TUSART_Coding::TXHandler(void) // Строка №297


С ним тоже самое smile.gif

Цитата
Оно не мешает, просто там в нём нет нужды (имхо).


Получается, что мешает, так как с ним присутствуют ошибки первого типа...
AHTOXA
Цитата(n_bogoyavlensky @ Aug 3 2009, 12:57) *
Процессор ATmega168.
Компилятор WinAVR20071221.


Он просто не знает слова interrupt smile.gif)))
koluna
Цитата(AHTOXA @ Aug 3 2009, 11:16) *
Он просто не знает слова interrupt smile.gif)))


Тааак... и как нам быть? smile.gif
AHTOXA
Цитата(n_bogoyavlensky @ Aug 3 2009, 13:19) *
Тааак... и как нам быть? smile.gif


Я не знаю, как дать имя обработчику прерывания... Надо позвать Редчука, чтоб он сказал smile.gif

Или так:
Код
SIGNAL(SIG_UART_RECV)
{
    OS::TISRW_SS ISRW;
    Usart1.RXHandler();
}
Сергей Борщ
Цитата(n_bogoyavlensky @ Aug 3 2009, 10:19) *
Тааак... и как нам быть? smile.gif
Он знает слово interrupt. Точнее interrupt - это макрос, и содержимое его вы можете легко найти внутри avr/interrupt.h. И то, во что этот макрос разворачивается, делает его несовместимыым с понятием "статическая функция класса". Короче:
Код
.h:
ISR(USART_RXC_vect);
ISR(USART_UDRE_vect);

class uart_t
{
public:
    uart_t() {};
    ...
private:
    friend void USART_RXC_vect();
    friend void USART_UDRE_vect();
    void RXC_Handler();
    void UDRE_Handler();
    ...
}
.cpp:
inline void uart_t::RXC_Handler()
{
    ...
}

OS_INTERRUPT void USART_RXC_vect()
{
    OS::TISRW isr;
    UART.RXC_Handler();
}
AHTOXA
Цитата(Сергей Борщ @ Aug 3 2009, 14:41) *
interrupt - это макрос, и содержимое его вы можете легко найти внутри avr/interrupt.h.


А я что-то не нашёл... Есть только
Код
define ISR_NOBLOCK    __attribute__((interrupt))
Сергей Борщ
Цитата(AHTOXA @ Aug 3 2009, 12:08) *
А я что-то не нашёл...
Ой-ё... С ISR() и SIGNAL() попутал. Откуда же оно появилось в коде у n_bogoyavlensky? Ага, кажется понял: тупой copy-paste из кода от mspgcc, без попытки изучить свой компилятор. В avr-gcc сделать обработчик прерывания статическим членом класса невозможно.
ReAl
Цитата(AHTOXA @ Aug 3 2009, 10:27) *
Я не знаю, как дать имя обработчику прерывания... Надо позвать Редчука, чтоб он сказал smile.gif
А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

Так что
Цитата(Сергей Борщ @ Aug 3 2009, 12:15) *
В avr-gcc сделать обработчик прерывания статическим членом класса невозможно.
приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS)

Код
OS_INTERRUPT void INT0_vect(); // имя INT0_vect и подобные - в точности те, что даются макросу ISR() !!!

class foo
{
    friend void INT0_vect();

...

private:
   inline void isr_handler();
};

foo f;

OS_INTERRUPT  // уже не обязательно, но и не мешает
void INT0_vect()
{
    f.isr_handler();
}
AHTOXA
Цитата(ReAl @ Aug 3 2009, 20:47) *
А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

Да уж. Который раз убеждаюсь, что avr-gcc выделяется на фоне остальных gcc некоей особой "особостью" smile.gif

Цитата(ReAl @ Aug 3 2009, 20:47) *
Так что
приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS)


То есть, OS_INTERRUPT из avr-gcc позволяет если не дать обработчику прерывания своё имя, то хотя бы получить хоть какое-то его имя, чтобы можно его было объявить его friend?
Потому что я не вижу других отличий от
Код
SIGNAL(SIG_UART_RECV)
{
     OS::TISRW_SS ISRW;
     Usart1.RXHandler();
}
ReAl
Цитата(AHTOXA @ Aug 3 2009, 18:27) *
То есть, OS_INTERRUPT из avr-gcc
Из avr-gcc - шного порта scmRTOS. Но это не существенно.
Цитата(AHTOXA @ Aug 3 2009, 18:27) *
позволяет если не дать обработчику прерывания своё имя, то хотя бы получить хоть какое-то его имя, чтобы можно его было объявить его friend?
Потому что я не вижу других отличий от
Код
SIGNAL(SIG_UART_RECV)
{
     OS::TISRW_SS ISRW;
     Usart1.RXHandler();
}
тот #define OS_INTERRUPT просто повторяет все те аттрибуты, которые даёт макрос SIGNAL() (и макрос ISR() по умолчанию), только в форме, которую можно дать префиксом к имени. Имя-то всё равно фиксировано и после подстановки этого SIG_UART_RECV будет превращено в какое-то __vector_XX
Отличия действительно чисто косметические, так как можно вообще так:
Код
// foo.h
#include <avr/io.h>
#include <avr/interrupt.h>

SIGNAL(INT0_vect);
// примитивная наколка - после разворачивания SIGNAL это будет эквивалентно
//   extern "C" void INT0_vect(void) __attribute__ ((signal, __INTR_ATTRS));   void INT0_vect(void);
// второе объявление функции просто ничего не меняет

class foo_t
{
    friend void INT0_vect();
public:
    uint8_t get() { return tick; }
private:
    uint8_t tick;
    inline void isr_handler() { ++tick; }
};

Код
// foo.cpp
#include "foo.h"
foo_t foo;

// а тут наконец-то определяем
SIGNAL(INT0_vect)
{
    foo.isr_handler();
}


Но мне такой вариант не очень понравился. Вопрос вкусовой.
Damon
Доброго времени суток! Позвольте вклиниться в разговор...

Цитата(ReAl @ Aug 3 2009, 18:47) *
А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

Так что
приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS) ...


Вчера назрел подобный вопрос, пришлось заняться "разборками". Как выяснилось, вопрос вполне решабельный, и после оперативно-разыскных мероприятий по всему инету есть что сказать. Начну по порядку.

1. C++ Interrupts
Цитата
Using the gcc "asm" keyword simplifies defining interrupt methods in C++
classes. The asm keyword as it applies to function names is described in
5.37 of the gcc manual and is mentioned in the asm cookbook section of the
avr-libc user manual. It specifies the equivalent assembler name for the
target function name and its use allows the user to define his or her own
names for class interrupt methods.


2. Controlling Names Used in Assembler Code
Цитата
You cannot use asm in this way in a function definition; but you can get the same effect by writing a declaration for the function before its definition and putting asm there, like this:

Код
extern func () asm ("FUNC");

func (x, y)
     int x, y;
...


Изначальный макрос у меня "с пол пинка" не завелся, но после некоторого экспериментирования, пришел к такому коду:
Код
// Timer.h
#include <avr/interrupt.h>
#define    OS_INTERRUPT    extern "C" __attribute__((__signal__,__INTR_ATTRS))

class Timer
{
public:
    Timer( ) { }
    ~Timer( ) { }

    void Dispatch( ) { }
    static void IRQHandler( ) asm( "__vector_10" ); // Или, не 10 ( взято "с потолка" ), в любом случае, меняя нумер можно
                                                                                 //  подставить куда угодно
};


Код
// Timer.cpp
#include "Timer.h"

Timer timer;

//---------------------------------------------------------------
OS_INTERRUPT void Timer::IRQHandler(void)
{
    timer.Dispatch( );
}


Проверяем, что получилось...
Код
$ nm Timer.o
00000150 t _GLOBAL__D_timer
00000138 t _GLOBAL__I_timer
000000d4 t _Z41__static_initialization_and_destruction_0ii
00000054 W _ZN5Timer8DispatchEv
00000000 W _ZN5TimerC1Ev
0000002a W _ZN5TimerD1Ev
0000003e a __SP_H__
0000003d a __SP_L__
0000003f a __SREG__
         U __do_clear_bss
         U __do_copy_data
         U __do_global_ctors
         U __do_global_dtors
00000000 a __tmp_reg__
0000007e T __vector_10       <===== Оно!
00000001 a __zero_reg__
00000000 B timer

Аха-а-а! Наш вектор экспортируется под "правильным" именем!

Теперь глянем на дизассемблированный листинг:
Код
Disassembly of section .text:

00000000 <__vectors>:
   0:   1b c0           rjmp    .+54           ; 0x38 <__dtors_end>
   2:   3f c0           rjmp    .+126          ; 0x82 <__bad_interrupt>
   4:   3e c0           rjmp    .+124          ; 0x82 <__bad_interrupt>
   6:   3d c0           rjmp    .+122          ; 0x82 <__bad_interrupt>
   8:   3c c0           rjmp    .+120          ; 0x82 <__bad_interrupt>
   a:   3b c0           rjmp    .+118          ; 0x82 <__bad_interrupt>
   c:   3a c0           rjmp    .+116          ; 0x82 <__bad_interrupt>
   e:   39 c0           rjmp    .+114          ; 0x82 <__bad_interrupt>
  10:   38 c0           rjmp    .+112          ; 0x82 <__bad_interrupt>
  12:   37 c0           rjmp    .+110          ; 0x82 <__bad_interrupt>
  14:   76 c0           rjmp    .+236          ; 0x102 <__vector_10>         <=== Оно!
  16:   35 c0           rjmp    .+106          ; 0x82 <__bad_interrupt>
  18:   34 c0           rjmp    .+104          ; 0x82 <__bad_interrupt>
  1a:   33 c0           rjmp    .+102          ; 0x82 <__bad_interrupt>
  1c:   32 c0           rjmp    .+100          ; 0x82 <__bad_interrupt>
  1e:   31 c0           rjmp    .+98           ; 0x82 <__bad_interrupt>
  20:   30 c0           rjmp    .+96           ; 0x82 <__bad_interrupt>
  22:   2f c0           rjmp    .+94           ; 0x82 <__bad_interrupt>
  24:   2e c0           rjmp    .+92           ; 0x82 <__bad_interrupt>
  26:   2d c0           rjmp    .+90           ; 0x82 <__bad_interrupt>
  28:   2c c0           rjmp    .+88           ; 0x82 <__bad_interrupt>
  2a:   2b c0           rjmp    .+86           ; 0x82 <__bad_interrupt>
  2c:   2a c0           rjmp    .+84           ; 0x82 <__bad_interrupt>
  2e:   29 c0           rjmp    .+82           ; 0x82 <__bad_interrupt>
  30:   28 c0           rjmp    .+80           ; 0x82 <__bad_interrupt>
  32:   27 c0           rjmp    .+78           ; 0x82 <__bad_interrupt>


PS: Чтоб избежать лишних вопросов о версии gcc, отвечу сразу -- самосборная под линухом, версия 4.2.2. В контроллер не заливал, ограничился (пока) статическим анализом, т.ч. если не будет работать, отпишите, не сочтите за труд.

PPS: Попытавшись реализовать вариацию на тему стратегий от Александреску, обломался. Не так-то легко провернуть подобное в случае шаблонного класса. Если у кого-то есть идеи, как реализовать подобное в шаблонном классе, буду очень признателен за подобное. Вопрос интересует только в контексте полного отсутствия виртуальных методов! С виртуальными методами это тривиально...
klen
мдя... С++ пошел в микроконтроллеры. кчему бы это wink.gif
тенденция однако..... вывод; много лишнего озу и флеша wink.gif

если не использовать "гадости" типа виртуальных функций, RTTI , эксепшены и прочих архитектрных излишестьв то получается удобно и почти бесплатно.
пробывал сделать обертку для FreeRTOS, все задачи наследуются от базового класа в котором все есть - отается переопределить функцию задачи. в резултате кода приложения стало процентов на 90 smile.gif меньше, стало проще читать код. скорость не страдает, размер чуток - небольшие с++ накладные расходы. такчто я думаю что при умном применении с++ польза есть.
MrYuran
Цитата(klen @ May 27 2010, 12:27) *
мдя... С++ пошел в микроконтроллеры. кчему бы это wink.gif
тенденция однако.....

Да уж C# давно пошёл...
Я даже кидал ссылку, для PIC чего-то пытались сваять
Не по теме, конечно, но всё же...
klen
Цитата(MrYuran @ May 27 2010, 12:34) *
Да уж C# давно пошёл...

наш "любимый" мелкомягкй везде свои костыли протолкнуть пытается ... при комунизме такое вот творчество наверно сдохло бы быстро, а вот буржуи молоццы - умеют играть в игу " кто дольше допинает дохлую лошадь в светлое будущее'
Damon
Цитата(klen @ May 27 2010, 12:27) *
если не использовать "гадости" типа виртуальных функций...

Ну Вы зря так про виртуальные ф-ции! Они тянут, конечно, за собой дополнительный код, но иногда без никак!
Как пример, после некоторой адаптации State Machine к (выработанным мною, для себя) требованиям к встраиваемой технике (в частности отказался от динамической памяти и заставил все работать в стеке), я познал дао (или дзен? :-)

Как бы то ни было, предпочитаю статический полиморфизм динамическому (выражаясь словами Дэвида Вандевурда, Николайа М. Джосаттиса). Он меньше места занимает, потому как, оптимизируется лучше.
Сергей Борщ
Цитата(Damon @ May 27 2010, 10:26) *
Код
    static void IRQHandler( ) asm( "__vector_10" ); // Или, не 10 ( взято "с потолка" ), в любом случае, меняя нумер можно
                                                                                 //  подставить куда угодно
};
Вот-вот. 10 надо подставлять вручную, что убивает всю красоту.
Damon
Цитата(Сергей Борщ @ May 27 2010, 14:26) *
Вот-вот. 10 надо подставлять вручную, что убивает всю красоту.

Не обязательно. :-)
В оригинале ( C++ Interrupts ) использовался макрос:
Код
#define CLASS_IRQ(name, vector) \
    static void name(void) asm(__STRINGIFY(vector)) \
    __attribute__ ((signal, __INTR_ATTRS))

Он рабочий, как я понял, только с некоторыми оговорками:
  1. при описании тела ф-ции необходимо добавить перед ней 'extern "C"'
  2. заменить "YYYYYYY_XXX_vect" (например, TIMER0_OVF_vect) на "__vector_XX"

Второй пункт можно реализовать через макросы (что-то навроде #define TIMER0_OVF_vect __vector_XX)

Мой вариант был лишь концептом, специально сделанным максимально прозрачным, для упрощения понимания. Отполировать до блеска его всегда можно, лишь бы рабочим был.

Да и скрыто это будет от енд-юзера... Код получается практически повторно используемым. Фактически, как это нынче модно называть, Framework'ом. Таким образом можно охватить фактически всю перефирию контроллера и код станет вполне повторно используемым. Но здесь есть одна засада! Начну немного издалека.

В Delphi и .NET, компоненты на форме делегируют обработку событий методам формы, что весьма удобно и выглядит красиво.
Хотелось бы реализовать что-то подобное. Т.е. класс таймера, к примеру реагирует на прерывание от него и, например, перезагружает регистр счетчика необходимым значением, на этом его функции обработки прерывания заканчиваются. Сама же обработка события делегируется другому объекту для обработки и следованию общей логики выполнения программы. Сама идея не нова -- паттерн command из книжки GoF. Лично мне очень понравилась реализация этого паттерна от Александреску. После того, как продрался через его описание в книжке. ИМХО, объяснять Александреску нихрена не умеет! Вот только есть нюанс, любые реализации этого паттерна используют виртуальные ф-ции, что тянет за собой доп код и мешает оптимизации. В случае Александреску, получается пара ф-ций "пересылки" аргументов к месту назначения. Даже после оптимизации все равно останется косвенный переход по VTable, т.ч. "сквозной" оптимизации не получится. И если для ARM'ов еще можно махнуть рукой или плюнуть (нужное подчеркнуть), то, например, для ATmega48, плеваться придется много и долго...
Есть вариант решения с использованием шаблонов. Данный пример для "большой" машины и только в целях иллюстрации принципа (не надо мне потом предъявлять по поводу использования std::list на ATmega48! :-).
Код
/*
* Command.h
*
*  Created on: 26.05.2010
*      Author: damon
*/

#ifndef COMMAND_H_
#define COMMAND_H_

#include <iostream>
#include <list>
#include <string>

template< class Handlers >
class Command: public Handlers
{
public:
    Command( ) { }

    void Signal( int sign )
    {
        Handlers::OnSignal( sign );
    }
};

class CommandHandler
{
private:
    std::string str_;

public:
    CommandHandler( char *str )
    {
        str_ = str;
    }

    void Print( int val )
    {
        std::cout << str_ << std::endl << "\t Полученное значение: " << val << std::endl;
    }
};

class CommandSwitcher
{
private:
    std::list< CommandHandler * > handlers_;

public:
    void AddHandler( CommandHandler *handler )
    {
        handlers_.push_back( handler );
    }

    void operator+=( CommandHandler *handler )
    {
        AddHandler( handler );
    }

    void DelHandler( CommandHandler *handler )
    {
        handlers_.remove( handler );
    }

    void operator-=( CommandHandler *handler )
    {
        DelHandler( handler );
    }

    void OnSignal( int sign )
    {
        std::for_each( handlers_.begin( ), handlers_.end( ), bind2nd( mem_fun( &CommandHandler::Print ), sign ) );
    }
};

#endif /* COMMAND_H_ */


Код
//main.cpp
#include "Command.h"

int main()
{
    Command< CommandSwitcher > command;

    CommandHandler firstHandler(  ( char * ) "First handler"  );
    CommandHandler secondHandler( ( char * ) "Second handler" );
    CommandHandler thirdHandler(  ( char * ) "Third handler"  );

    command += &firstHandler;
    command += &secondHandler;
    command += &thirdHandler;

    command.Signal( 10 );

    std::cout << std::endl;

    command -= &firstHandler;

    command.Signal( 1 );

    return 0;
}


Таким образом вся логика "коммутации" сигнала о событии сосредоточена в классе CommandSwitcher, который никоим образом не зависит от класса Command. При этом, при использовании класса Command в другом проекте не понадобится вносит в него никаких изменений! Меняться будет только CommandSwitcher!

При этом виртуальные ф-ции не используются, а поскольку шаблонные методы описываются в хидере, есть надежда на их "сквозную" оптимизацию, что благотворно скажется на размере и скорости прошивки контроллера!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.