WinAVR, c++ и прерывания

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
apwork
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Ср май 11, 2011 12:24:54
Откуда: Лисичанск

WinAVR, c++ и прерывания

Сообщение apwork »

Подскажите как прикрутить обработчик прерывания к классу c++.
Компилятор - avr-gcc из WinAVR.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение avreal »

Обработчик прерывания в любом случае должен быть статической функцией (если это функция класса), так как некому ему передать this.

У avr-gcc проблема в декораци имён функций классов в С++ и в способе задания обработчиков с фиксироанными именами __vector_NUMBER. Что-то пробовали сделать, чтобы можно было обработчик в классе делать, но, вроде бы, в релизах это так и не работает.

Надёжно -- только как дружественную фцнкцию. Тогда она и будет статическая и с нужными атрибутами и именем, а «классовый» обработчик может уже быть каким нужно.

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

#include <avr/interrupt.h>

ISR(TIMER0_OVF_vect);

class Foo {
    ...
private:
    friend void TIMER0_OVF_vect();
    inline void Isr();

    uint8_t cnt;
};

Foo foo;

void Foo::Isr() { ++cnt; }

void TIMER0_OVF_vect()
{
    foo.Isr();
}
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
apwork
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Ср май 11, 2011 12:24:54
Откуда: Лисичанск

Re: WinAVR, c++ и прерывания

Сообщение apwork »

Спасибо за информацию. Буду пробовать. Хотя со статичной функцией класса было бы интереснее.
Мастер Ломастер
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение Мастер Ломастер »

а в чем смысл впихивания обработчика в класс?
битва с дураками проиграна, победители торжествуют. слава победителям!
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение avreal »

apwork писал(а):Спасибо за информацию. Буду пробовать. Хотя со статичной функцией класса было бы интереснее.
На avrfreaks поищите C++ interrupt, там несколько тем было год-два назад.
Что-то я пробовал, но у меня толи не пошло, толи выглядело не ровнее дружественных функций.

Если нароете что-то свежее-рабочее, отпишитесь тут :-)
Последний раз редактировалось avreal Чт май 12, 2011 10:33:03, всего редактировалось 1 раз.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение avreal »

Мастер Ломастер писал(а):а в чем смысл впихивания обработчика в класс?
В том же в чём и впихивание всего остального -- «приватизация» того, что не должно быть видно снаружи при сохранении быстрого доступа, некоторое разделение интерфейса и реализации, ...
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Мастер Ломастер
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение Мастер Ломастер »

разделение - самоцель? всегда считал, что ООП имеет цель упрощение построения сложных проектов, в которых одновременное существование нескольких экземпляров одного и того же класса является непременным условием... или проект состоит из хитрой иерархии классов для обеспечения некоей "стройности" кода...
существование двух экземпляров класса со встроенными обработчиками одного и того же прерывания в AVR я не представляю... выглядит это, как костыли... стройности программе тоже вряд ли прибавляет...
получается, смысл только в загонянии части переменных под private ? оно того на самом деле стоит?
битва с дураками проиграна, победители торжествуют. слава победителям!
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение avreal »

А в С -- если какой-то модуль выделяется в отдельный файл со спрятанными там (через static) переменными и функциями внутреннего употребления -- тоже «непременным условием» будет применение в программе двух экземпляров этого модуля? Иначе программа «нестройная», выделение модуля было «самоцелью» ?

На мой взгляд, класс, от которого в программе существует в принципе единственный экземпляр -- вполне нормальное явление.

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

У меня сейчас в меге64 подобным образом работает 5-канальный приёмник пакетов (односторонняя передача, эта штука только принимает, анализирует и в UART на комп). Впрочем, там вместе с float-статистикой, fprintf, кучей текстовых строк -- килов 7 кода. Было бы у меги168 нужное количество COMPARE, в ней бы и было сделано. Да и платки с мегой64 завалялись.

Каждый канал - единственный экземпляр «себя» с двумя собственными обработчиками прерываний (внешнее прерывание и таймерное COMPARE). Но все одни -- потомки общего PaсketReceiver и уровнем выше все думают, что вот в этом массиве -- указатели именно на задействованные PacketReceiver, а не на те, нарушающие «непременное условие», единственные экземпляры производных классов.
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Мастер Ломастер
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение Мастер Ломастер »

avreal писал(а):Каждый канал - единственный экземпляр «себя» с двумя собственными обработчиками прерываний (внешнее прерывание и таймерное COMPARE). Но все одни -- потомки общего PaсketReceiver и уровнем выше все думают, что вот в этом массиве -- указатели именно на задействованные PacketReceiver, а не на те, нарушающие «непременное условие», единственные экземпляры производных классов.
возможно, пока я корректировал свое сообщение - вы как раз отвечали :) ибо я добавил в свой текст упоминание об улучшении стройности программы за счет иерархии классов - это как раз ваш случай. это я понимаю и могу с этим согласиться без возражений.

меня смутил единственный экземпляр единственного класса с обработчиком прерываний - по сравнению с отдельным модулем никаких преимуществ не имееющий, как мне кажется, но требующий перехода на заведомо более сложный инструмент С++. т.е. налицо возрастание сложности решения без заметной выгоды...
битва с дураками проиграна, победители торжествуют. слава победителям!
Аватара пользователя
avreal
Опытный кот
Сообщения: 842
Зарегистрирован: Чт дек 31, 2009 19:27:45
Откуда: Бровари, Україна
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение avreal »

Мастер Ломастер писал(а):упоминание об улучшении стройности программы за счет иерархии классов - это как раз ваш случай. это я понимаю и могу с этим согласиться без возражений.
Но каждый «листовой» класс при этом имеет единственный экземпляр, а топикстартер не упоминал, его классы самостоятельные, или чьи-то потомки :-)

Мастер Ломастер писал(а):меня смутил единственный экземпляр единственного класса с обработчиком прерываний - по сравнению с отдельным модулем никаких преимуществ не имееющий, как мне кажется, но требующий перехода на заведомо более сложный инструмент С++. т.е. налицо возрастание сложности решения без заметной выгоды...
Если остальная программа и так на плюсах (а это отдельный разговор, который шире обсуждения одного какого-то модуля-класса), то никакого специального перехода не будет.
Пусть нужен UART (в упомянутом выше приёмнике-анализаторе пакетов) или там I2C -- если не в микроконтроллере, то в программе вполне может быть в единственном экземпляре.
В программе, использующей scmRTOS, оформление «драйвера I2C» в виде модуля С-стиля только сделает программу «неоднородной», проще она точно от этого не станет.

А класс один без иерархии (ОП, а не ООП, если я правильно терминологию понимаю) и с единственным экземпляром -- вполне ляжет в стиль. Всякие там mutex-ы с event-ами будут не отдельно стоящими статическими объектами в отдельном файле, а полями (возможно, тоже статическими) класса «драйвера», конструкторы вызовутся, то-сё. Где тут усложнение -- уже не видно. Да и вообще не видно, после того, как инструмент освоен. А применять удобно.

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

fprintf_P( uart, ...... );
И по барабану, что этот uart -- единственный экземпляр единственного класса.
Он имеет operator FILE* () специально для этого случая, а внутри и экземпляр класса очереди, и разные сервисы scmRTOS использует. Поток просто уснёт (а не будет в цикле поллить флаги UART), если в очереди места нет, будет разбужен, когда появится.
Выписать тот же функционал в чисто С-шном стиле через

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

FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, ...);
#define uart (&uart_file)
и что спрятать в модуле в static, что описать как uart_lock() вместо uart.lock() -- проще не будет, пользоваться тоже проще не будет.
Зато inline-доступ к приватным полям будет быстр, а для использования такого же доступа к «приватным» переменным С-шного модуля придётся таки делать их глобальными, а не в файловой области видимости прятать.
Просто в h-файле не описывать на верхнем уровне, а прятать внутрь функций, чтобы скрыть их существование и не дать туда что-то записать минуя опубликованный интерфейс модуля:

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

static inline unsigned GetSystemTimer()
{
        extern volatile unsigned sys_timer;
        return sys_timer;
}
Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Аватара пользователя
apwork
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Ср май 11, 2011 12:24:54
Откуда: Лисичанск

Re: WinAVR, c++ и прерывания

Сообщение apwork »

На avrfreaks и подобных сайтах все рекомендации сводятся к применению friend функций-прерываний. Объясняют это ограничениями и недостатками avr-gcc. Все надеются, что в будущем будет что-то придумано.
Попробую поискать еще, иначе буду лепить friend'a :)
Аватара пользователя
apwork
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Ср май 11, 2011 12:24:54
Откуда: Лисичанск

Re: WinAVR, c++ и прерывания

Сообщение apwork »

Такое еще нарыл ( пост от Ron Kreymborg на [avr-chat] ) :

Он предлагает с помощью директивы asm сделать так:
1. Объявить макрос

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

#define CLASS_IRQ(name, vector) \
    static void name(void) asm(__STRINGIFY(vector)) \
    __attribute__ ((signal, __INTR_ATTRS))

2. Объявить класс прерывания

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

class CTimer0Interrupt
{
public:
    CTimer0Interrupt();
    ~CTimer0Interrupt();
private:
    CLASS_IRQ(OverflowInterrupt, TIMER0_OVF_vect);
};

Макрос объявляет обработчик прерывания статическим.
Далее приводится текст файла с имплементацией класса прерывания:

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

//***************************************************************
// Timer0Interrupt.cpp
//
#include "Timer0.h"
#include "Timer0Interrupt.h"

extern CTimer0 Timer0;

//----------
CTimer0Interrupt::CTimer0Interrupt()
{
    TCNT0 = TIMER0_TIMEOUT;
    TCCR0 = 0x04;
    TIMSK |= (1<<TOIE0);        // enable overflow interrupts
}

//----------
CTimer0Interrupt::~CTimer0Interrupt()
{
    TIMSK &= ~(1<<TOIE0);       // disable Timer0 timeout interrupt
}

//----------
void CTimer0Interrupt::OverflowInterrupt(void)
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.SetOverflowFlag();   // tell our friend of the event
}

А вот и класс устройства ( в данном случае это таймер )

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

class CTimer0
{
    friend class CTimer0Interrupt;
public:
    CTimer0();
    ~CTimer0();
    int GetTimer0Flags(void);
private:
    void SetOverflowFlag(void);
private:
    volatile int        mTimer0Flags;
    CTimer0Interrupt    mTimer0Interrupt;
};

void CTimer0Interrupt::OverflowInterrupt(void)
{
    TCNT0 = TIMER0_TIMEOUT;     // restart the timeout
    Timer0.mTimer0Flags |= TIMER0_OVERFLOW;
}

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

Re: WinAVR, c++ и прерывания

Сообщение YS »

а в чем смысл впихивания обработчика в класс?


Даже шире: в чем смысл применения ООП при создании firmware?

На мой взгляд, класс, от которого в программе существует в принципе единственный экземпляр -- вполне нормальное явление.


Ну, не все так однозначно. Например, мне это кажется жутким извращением. :)
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
apwork
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Ср май 11, 2011 12:24:54
Откуда: Лисичанск

Re: WinAVR, c++ и прерывания

Сообщение apwork »

Э-э-э... товарищи, давайте не устраивать холивар. Личные предубеждения оставляем при себе и оперируем фактами. Есть проблема - ищем решение! Не надо говорить, что проблема плохая - находим себе "хорошую" проблему и решаем в свое удовольствие!
neiver
Родился
Сообщения: 4
Зарегистрирован: Пн апр 25, 2011 15:39:38

Re: WinAVR, c++ и прерывания

Сообщение neiver »

Я предпочитаю обработчики прерываний делать обычными статическими функциями-членами. Причем встраиваемыми для эффективности. И вызывать их из обычным образом написанного обработчика.

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

class Usart
{
...
static void RxHandler()
{
char byte = UDR;
...
}
...
};
...
ISR(USART_RXC_vect)
{
        Usart::RxHandler();
}

Это более гибкий и переносимый подход. Подробнее можно почитать тут:
http://we.easyelectronics.ru/Soft/kolcevoy-bufer-na-s-dlya-mk.html
Аватара пользователя
BCluster
Собутыльник Кота
Сообщения: 2512
Зарегистрирован: Пн апр 06, 2009 19:33:29
Откуда: Молдова, Кишинев
Контактная информация:

Re: WinAVR, c++ и прерывания

Сообщение BCluster »

Не люблю плюсы. Да и необходимость использования ООП на авр весьма сомнительна. Программы не настолько сложны. Ну эт ИМХО все канечно :)
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»