|
IAR AVR C++ class и прерывание |
|
|
|
Oct 2 2009, 20:21
|

Местный
  
Группа: Свой
Сообщений: 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
|
|
|
|
|
Oct 3 2009, 11:22
|

Местный
  
Группа: Свой
Сообщений: 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(); .... .... ....}
|
|
|
|
|
Oct 3 2009, 13:30
|

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(), как функция класса, тоже имеет доступ к представлению класса  А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд. Цитата(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(); то не работает, что-ли? Что не работает в этом случае? Не собирается проект? Или в железе не работает?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Oct 3 2009, 14:42
|

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

|
Цитата(dxp @ Oct 3 2009, 19:30)  А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд. Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса. Типа, Код uart.rxbuf[uart.rxpos++] = U0RXBUF; uart.rxpos &= uart.rxsize; И к тому же, такой подход не везде работает. Например, в avr-gcc нельзя сделать обработчик прерывания функцией класса. А вообще - да, согласен, дело вкуса
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Oct 5 2009, 07:47
|

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

|
Цитата(AHTOXA @ Oct 3 2009, 21:42)  Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса. Типа, Код uart.rxbuf[uart.rxpos++] = U0RXBUF; uart.rxpos &= uart.rxsize; Это всяко.  Но по сути там и не может быть экземпляров - ведь работа же идет с конкретным аппаратным ресурсом, который в системе один, и регистры управления которым, как и вектор прерывания, жестко заданы. Поэтому и остальные ресурсы (типа буферов, индексов и т.п.) тоже существуют в единственном экземпляре и их тоже бы надо бы объявить как static. Экземпляры нужны, например, если на один вектор прерывания забиндено несколько (хотя бы два) UART'ов. Тогда да - тут появляются отдельные объекты класса. Но и в этом случае статическая функция класса рулит - она одна на все объекты класса, и является корневой для процесса обработки прерывания - прерывание вызывает ее, а уж внутри нее и выясняется (например, по соответствующим битам в регистре статуса/управления, от какого именно UART'а возникло прерывание), какому объекту (экземпляру) передать управление. Хотя я не сталкивался на практике с платформами, где на одном прерывании сидело два UART'а.  Точнее, такое у нас есть, но UART'ы живут в ПЛИСке, и на этом прерывании много чего еще сидит. Т.е. это не готовая аппаратная платформа.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Dec 4 2009, 07:18
|
Частый гость
 
Группа: Свой
Сообщений: 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 одна на оба экземпляра! В чем тут причина я так-же не смог понять.
|
|
|
|
|
Dec 4 2009, 08:14
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Dec 4 2009, 08:24
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата(Сергей Борщ @ Dec 4 2009, 11:14)  вот и не понимаю как. Для начала - как задать компилятору вектор прерывания? В нутри класса есть аргумент, определяющий A или B таймер. Вне класса - как определить, с каким таймером работаем? Вернее понимаю как на этапе создания класса, когда уже известно какой таймер будем использовать. Я же хочу сделать универсальный класс (ну вернее шаблон) - что бы подключил h файл и вообще не открывать его (для правки). Цитата Простите, а зачем вы пишете static в объявлении переменной, если не понимаете, зачем он нужен? Пишу для того, что бы она была доступна из обработчика прерывания. Ясно что в данном случае весь класс статический - т.е. более одного экземпляра существовать не может. насчет одной переменной на оба класса: я все-таки недопонимаю тогда шаблоны: ведь компилятор создает ДВА никак не связанных между собой класса, и поэтому как может получиться одна переменная на оба класса.
|
|
|
|
|
Dec 4 2009, 09:23
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
У меня есть БОЛЬШИЕ сомнения по поводу допустимости такой записи Код #pragma vector = (Timer == TIMER_A) ? (TIMERA1_VECTOR) : (TIMERB1_VECTOR) сдается мне, что эта прагма будет проигнорированна. Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса Еще замечание - использование огмоного количества констант, выбираемых по параметру шаблона, не есть гуд  Лучше сделать так: Код 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; } ... };
|
|
|
|
|
Dec 4 2009, 09:44
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса Делал - говорю-ж - криво выходит. Во первых обработчики всегда будут существовать - т.е. при попытке задействовать другой обработчик линковщик ругается на два определения обработчика. Во вторых - изначально собирался ввести еще один аргумент шаблона: "функцию" таймера - выставление флага (SIGNAL_TIMER) или вызов процедуры (PROC_TIMER). А это уже другие действия в обработчике. Т.е. уже четыре обработчика. А тут уже никак. Через один универсальный шаблон все очень компактно и красиво получилось. Кроме того, что обработчиков прерываний в коде нет  Цитата Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить  в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать. Цитата Еще замечание - использование огмоного количества констант, выбираемых по параметру шаблона, не есть гуд  А почему? Компилироваться долго будет?
|
|
|
|
|
Dec 4 2009, 09:50
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата(Alechin @ Dec 4 2009, 12:44)  А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить  в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать. Ну и задать эту связку где нибудь в том же hardware.cpp Проблема в том, что обработчик привязывается с помощью #pragma, а это не языковая конструкция. Т.е. никакие template'ы к ней привязать нельзя. Цитата А почему? Компилироваться долго будет? Некрасиво. Масса констант для обоих таймеров вместе с if'ами равномерно размазанных по всему телу шаблонного класса.  Лучше эти константы собрать в одном месте (и отдельно для каждого таймера) с помощью классов TIMER_?, а в самом TTimer<> уже использовать имена, независящие от конкретного типа таймера
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|