реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> IAR AVR C++ class и прерывание
west329_
сообщение Oct 2 2009, 20:21
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 378
Регистрация: 10-09-07
Из: UKR/Voz
Пользователь №: 30 423



Подскажите как правильно описать прерывание от uart0 для функции которая определяется в класе на уровень выше, так сказать пртоколе верхнего уровня cHuProt.

Сам клас
Код
#include "com0.h"

class cHuProt:public cUsart0 {
  protected:  
              void    HU_Rx_Byte(void);
  public:
              ui8     Recive_Pack_HU(void);
              ui8     Recive_Pack_HU_End(void);
              ui8     Init_HU(void);
              ui8     Reset_Recive_HU(void);
              ui8     Expect_new_HU(void);
              ui8     ECM_HU_len(void);
              ui8*    Get_Point_to_ECM_HU_data(void);
              ui8*    Get_Point_to_HU_S(void);
              ui8*    Get_Point_to_HU_C(void);
              ui8*    Get_Point_to_HU_I(void);
              ui8     DW_HU_Transmit(ui8 *pData);
              
  //cHumaxProt();
  //~cHumaxProt();
};


В клас cUsart0 я записал все низкоуровневые функции работы с железом uart
Код
class cUsart0 {
  protected:
              ui8 Usart0_Tx_Raw(ui8 tx_char);
              ui8 Usart0_RX_Raw(void);
  public:
              ui8 Usart0_Init(ui16 ubrr);
              ui8 Usart0_Tx_Data(ui8 *pData, ui8 len_data);
              ui8 Usart0_Tx_Char(ui8 tx_char);
              
  //Usart0();
  //~Usart0();
};

/////////////////////////////////////////////////////////////////////////////
// Реализация класса cUsart0
/////////////////////////////////////////////////////////////////////////////
....
....
....



Сама функция Usart0_Init использует прерывание при получении символа с uart.

Очень хочется вызывать функцию Usart0_RX_Raw(void); когда приходит символ, тоесть както так описать метод в протоколе
Код
#pragma vector = USART0_RXC_vect
__interrupt void cHuProt::HU_Rx_Byte(void) {
      temp=ui8 Usart0_RX_Raw();
      ......
      ......
}


но увы получаю ошибки
Цитата
Error[Ta022]: Interrupt functions cannot take any parameters. D:\Main_prj\tutor\MainTestCPP\hu.h 19
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 2 2009, 20:33
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Функции класса передаётся неявный параметр this. Объявите функцию static. Хотя это практически ничем не лучше, чем отдельный обработчик прерывания с вызовом в нём uart.HUMAX_Rx_Byte();

И вот тут почитайте.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 3 2009, 01:54
Сообщение #3


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(AHTOXA @ Oct 3 2009, 03:33) *
Функции класса передаётся неявный параметр this. Объявите функцию static. Хотя это практически ничем не лучше, чем отдельный обработчик прерывания с вызовом в нём uart.HUMAX_Rx_Byte();

Оно все же получше тем, что имеет доступ к представлению своего класса. Ну, и тем, что не загромождает глобальное пространство имен. smile.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 3 2009, 07:10
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Что значит "к представлению"? К приватным членам? Если так, то вызываемая uart.HUMAX_Rx_Byte(), как функция класса, тоже имеет доступ к представлению классаsmile.gif

Так что, имхо, единственное преимущество -
Цитата(dxp @ Oct 3 2009, 07:54) *
что не загромождает глобальное пространство имен. smile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
west329_
сообщение Oct 3 2009, 11:22
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 378
Регистрация: 10-09-07
Из: UKR/Voz
Пользователь №: 30 423



Вобщем как я не пытался так и не получилось у меня повесит напрямую прерывание на метод класса.
Пошол по другому пути, создал обычную процедуру повесил на неё прерывание а из него уже вызываю метод класса, незнаю можна так делать или нельзя, код проверял работает нормально.
Код
#pragma vector = USART0_RXC_vect
__interrupt void Recive_Byte_from_tu(void) {
   ui8 Rx_Ch = Tu.HU_Rx_Byte();
....
....
....}
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 3 2009, 13:30
Сообщение #6


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(AHTOXA @ Oct 3 2009, 14:10) *
Что значит "к представлению"? К приватным членам?

Да, к закрытой части класса.

Цитата(AHTOXA @ Oct 3 2009, 14:10) *
Если так, то вызываемая uart.HUMAX_Rx_Byte(), как функция класса, тоже имеет доступ к представлению классаsmile.gif

А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд.

Цитата(west329_ @ Oct 3 2009, 18:22) *
Вобщем как я не пытался так и не получилось у меня повесит напрямую прерывание на метод класса.
Пошол по другому пути, создал обычную процедуру повесил на неё прерывание а из него уже вызываю метод класса, незнаю можна так делать или нельзя, код проверял работает нормально.
Код
#pragma vector = USART0_RXC_vect
__interrupt void Recive_Byte_from_tu(void) {
   ui8 Rx_Ch = Tu.HU_Rx_Byte();
....
....
....}

А если в классе объявить:

__interrupt static void Receive_Byte_from_tu();

то не работает, что-ли? Что не работает в этом случае? Не собирается проект? Или в железе не работает?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 3 2009, 14:42
Сообщение #7


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(dxp @ Oct 3 2009, 19:30) *
А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд.


Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса.
Типа,
Код
  uart.rxbuf[uart.rxpos++] = U0RXBUF;
  uart.rxpos &= uart.rxsize;


И к тому же, такой подход не везде работает. Например, в avr-gcc нельзя сделать обработчик прерывания функцией класса.

А вообще - да, согласен, дело вкусаsmile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
dxp
сообщение Oct 5 2009, 07:47
Сообщение #8


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(AHTOXA @ Oct 3 2009, 21:42) *
Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса.
Типа,
Код
  uart.rxbuf[uart.rxpos++] = U0RXBUF;
  uart.rxpos &= uart.rxsize;

Это всяко. smile.gif Но по сути там и не может быть экземпляров - ведь работа же идет с конкретным аппаратным ресурсом, который в системе один, и регистры управления которым, как и вектор прерывания, жестко заданы. Поэтому и остальные ресурсы (типа буферов, индексов и т.п.) тоже существуют в единственном экземпляре и их тоже бы надо бы объявить как static.

Экземпляры нужны, например, если на один вектор прерывания забиндено несколько (хотя бы два) UART'ов. Тогда да - тут появляются отдельные объекты класса. Но и в этом случае статическая функция класса рулит - она одна на все объекты класса, и является корневой для процесса обработки прерывания - прерывание вызывает ее, а уж внутри нее и выясняется (например, по соответствующим битам в регистре статуса/управления, от какого именно UART'а возникло прерывание), какому объекту (экземпляру) передать управление. Хотя я не сталкивался на практике с платформами, где на одном прерывании сидело два UART'а. smile.gifТочнее, такое у нас есть, но UART'ы живут в ПЛИСке, и на этом прерывании много чего еще сидит. Т.е. это не готовая аппаратная платформа.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
singlskv
сообщение Oct 5 2009, 22:09
Сообщение #9


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(dxp @ Oct 5 2009, 11:47) *
Но и в этом случае статическая функция класса рулит - она одна на все объекты класса, и является корневой для процесса обработки прерывания - прерывание вызывает ее, а уж внутри нее и выясняется (например, по соответствующим битам в регистре статуса/управления, от какого именно UART'а возникло прерывание), какому объекту (экземпляру) передать управление. Хотя я не сталкивался на практике с платформами, где на одном прерывании сидело два UART'а. smile.gif

На ARM это как раз делаеться легко, просто один и тот же адрес обработчика подсовываете при инициализации
а дальше разбор в обработчике по номеру переферийного блока в котором возникло прерывание.
Go to the top of the page
 
+Quote Post
Alechin
сообщение Dec 4 2009, 07:18
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334



а если я хочу созать шаблон класса с обработчиком внутри - компилятор не вставляет код обработчика. Мелькало где-то в обсуждениях, что для шаблонов именно так. Я обойти эту ситуацию не смог. Вот пример:
хочу создать шаблон класса таймеров. Аргумент шаблона - используемый таймер А или B (это MSP430, но принцип должен быть один)
Код
#define MODULES_IN_TIMER_A      2
#define MODULES_IN_TIMER_B      6
#define TIMER_A                'A'
#define TIMER_B                'B'
template <char Timer> class TTimers
{
  protected:
    static const BYTE nModules = (Timer == TIMER_A) ? (MODULES_IN_TIMER_A) : (MODULES_IN_TIMER_B);
    // Флаги состояния модулей захвата/сравнения.
    static volatile bool run[nModules];
    // Старший байт счетчика времени работы таймера.
    static volatile WORD hi_Word_of_Tick_Cntr;
  public:
    // Конструктор класса.
    inline TTimers()
      {
        // Обнулим счетчик времени работы таймера.
        hi_Word_of_Tick_Cntr = 0;
        // Выключим все модули захвата/сравнения.
        for(register IDX i = 0; i < nModules; i++) { Dis(i); Reset(i); }
        // Программируем таймер:
        // синхронизация от ACLK, счетчик 16 бит, режим непрерывного счета,
        // прерывание по переполнению запрещено, все таймеры независимы.
        (Timer == TIMER_A) ? (TACTL = TASSEL0 + MC1 + TACLR) : (TBCTL = TBSSEL0 + MC1 + TBCLR);
      }

    // Методы управления прерываниями от модулей захвата/сравнения.
    static inline void Ena(IDX i) { *(&((Timer == TIMER_A) ? (TACCTL1) : (TBCCTL1)) + i) = CCIE; }
    static inline void Dis(IDX i) { *(&((Timer == TIMER_A) ? (TACCTL1) : (TBCCTL1)) + i) = 0x00; }

    // Методы загрузки значения в регистр сравнения.
    static inline WORD Remained(IDX i)          { return *(&((Timer == TIMER_A) ? (TACCR1) : (TBCCR1)) + i) - ((Timer == TIMER_A) ? (TAR) : (TBR)); }
    static inline void Load(IDX i, WORD val)    { *(&((Timer == TIMER_A) ? (TACCR1) : (TBCCR1)) + i) = ((Timer == TIMER_A) ? (TAR) : (TBR)) + val;  }

    // Методы проверки/сброса/установки флага срабатывания таймера.
    static inline bool is_Setting(IDX i)       { return run[i] == true; }
    static inline void Reset(IDX i)            { run[i] = false;        }
    static inline void Set(IDX i)              { run[i] = true;         }

    // Обработчик прерывания.
    #pragma vector = (Timer == TIMER_A) ? (TIMERA1_VECTOR) : (TIMERB1_VECTOR)
    static __interrupt void Timer_IRQ(void)
      {
        IDX i = (Timer == TIMER_A) ? (TAIV) : (TBIV);
        if(i == ((Timer == TIMER_A) ? (0x0a) : (0x0e)))
          {
            // Прерывание по переполнению.
            // Инкрементируем старший байт счетчика работы таймера.
            hi_Word_of_Tick_Cntr++;
          }
        else
          {
            // Прерывание от модулей захвата/сравнения.
            i = (i >> 2) - 1;
            Dis(i);                           // Запрещаем прерывания от модуля захвата/сравнения.
            Set(i);                           // Выставляем признак завершения счета.
            __low_power_mode_off_on_exit();   // Выходим из режима пониженного потребления.
          }
      }
};


в итоге в коде нет обработчиков. Как в этой ситуации поступить?
и еще: если создать два экземпляра класса (ну конечно для А и B таймеров) - переменные run у каждого экземпляра свои, а hi_Word_of_Tick_Cntr одна на оба экземпляра! В чем тут причина я так-же не смог понять.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 4 2009, 08:14
Сообщение #11


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Alechin @ Dec 4 2009, 09:18) *
в итоге в коде нет обработчиков. Как в этой ситуации поступить?
Инстанцировать их явно.

Цитата(Alechin @ Dec 4 2009, 09:18) *
а hi_Word_of_Tick_Cntr одна на оба экземпляра! В чем тут причина я так-же не смог понять.
Простите, а зачем вы пишете static в объявлении переменной, если не понимаете, зачем он нужен?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Alechin
сообщение Dec 4 2009, 08:24
Сообщение #12


Частый гость
**

Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334



Цитата(Сергей Борщ @ Dec 4 2009, 11:14) *

вот и не понимаю как. Для начала - как задать компилятору вектор прерывания? В нутри класса есть аргумент, определяющий A или B таймер. Вне класса - как определить, с каким таймером работаем?
Вернее понимаю как на этапе создания класса, когда уже известно какой таймер будем использовать. Я же хочу сделать универсальный класс (ну вернее шаблон) - что бы подключил h файл и вообще не открывать его (для правки).

Цитата
Простите, а зачем вы пишете static в объявлении переменной, если не понимаете, зачем он нужен?

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

насчет одной переменной на оба класса: я все-таки недопонимаю тогда шаблоны: ведь компилятор создает ДВА никак не связанных между собой класса, и поэтому как может получиться одна переменная на оба класса.
Go to the top of the page
 
+Quote Post
XVR
сообщение Dec 4 2009, 09:23
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



У меня есть БОЛЬШИЕ сомнения по поводу допустимости такой записи
Код
#pragma vector = (Timer == TIMER_A) ? (TIMERA1_VECTOR) : (TIMERB1_VECTOR)

сдается мне, что эта прагма будет проигнорированна.
Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса

Еще замечание - использование огмоного количества констант, выбираемых по параметру шаблона, не есть гуд sad.gif
Лучше сделать так:
Код
struct TIMER_A {
enum Consts {
   nModules = 2,
   TxCTLImg = TASSEL0 + MC1 + TACLR,
   ...
};
BYTE& TxCTL() {return TACTL;}
...
};

// Для TIMER_B аналогично

template <class Timer> class TTimers : private Timer
{
  protected:
    static volatile bool run[nModules];
    // Старший байт счетчика времени работы таймера.
    static volatile WORD hi_Word_of_Tick_Cntr;
  public:
    // Конструктор класса.
    inline TTimers()
      {
        // Обнулим счетчик времени работы таймера.
        hi_Word_of_Tick_Cntr = 0;
        // Выключим все модули захвата/сравнения.
        for(register IDX i = 0; i < nModules; i++) { Dis(i); Reset(i); }
        // Программируем таймер:
        // синхронизация от ACLK, счетчик 16 бит, режим непрерывного счета,
        // прерывание по переполнению запрещено, все таймеры независимы.
        TxCTL() = TxCTLImg;
      }
...
};
Go to the top of the page
 
+Quote Post
Alechin
сообщение Dec 4 2009, 09:44
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334



Цитата
Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса

Делал - говорю-ж - криво выходит. Во первых обработчики всегда будут существовать - т.е. при попытке задействовать другой обработчик линковщик ругается на два определения обработчика.
Во вторых - изначально собирался ввести еще один аргумент шаблона: "функцию" таймера - выставление флага (SIGNAL_TIMER) или вызов процедуры (PROC_TIMER). А это уже другие действия в обработчике. Т.е. уже четыре обработчика. А тут уже никак. Через один универсальный шаблон все очень компактно и красиво получилось. Кроме того, что обработчиков прерываний в коде нет sad.gif

Цитата
Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса

А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить sad.gif в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать.

Цитата
Еще замечание - использование огмоного количества констант, выбираемых по параметру шаблона, не есть гуд sad.gif

А почему? Компилироваться долго будет?
Go to the top of the page
 
+Quote Post
XVR
сообщение Dec 4 2009, 09:50
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(Alechin @ Dec 4 2009, 12:44) *
А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить sad.gif в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать.
Ну и задать эту связку где нибудь в том же hardware.cpp
Проблема в том, что обработчик привязывается с помощью #pragma, а это не языковая конструкция. Т.е. никакие template'ы к ней привязать нельзя.

Цитата
А почему? Компилироваться долго будет?
Некрасиво. Масса констант для обоих таймеров вместе с if'ами равномерно размазанных по всему телу шаблонного класса. cranky.gif Лучше эти константы собрать в одном месте (и отдельно для каждого таймера) с помощью классов TIMER_?, а в самом TTimer<> уже использовать имена, независящие от конкретного типа таймера
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 06:17
Рейтинг@Mail.ru


Страница сгенерированна за 0.01548 секунд с 7
ELECTRONIX ©2004-2016