west329 0 2 октября, 2009 Опубликовано 2 октября, 2009 · Жалоба Подскажите как правильно описать прерывание от 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 2 октября, 2009 Опубликовано 2 октября, 2009 · Жалоба Функции класса передаётся неявный параметр this. Объявите функцию static. Хотя это практически ничем не лучше, чем отдельный обработчик прерывания с вызовом в нём uart.HUMAX_Rx_Byte(); И вот тут почитайте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 3 октября, 2009 Опубликовано 3 октября, 2009 · Жалоба Функции класса передаётся неявный параметр this. Объявите функцию static. Хотя это практически ничем не лучше, чем отдельный обработчик прерывания с вызовом в нём uart.HUMAX_Rx_Byte(); Оно все же получше тем, что имеет доступ к представлению своего класса. Ну, и тем, что не загромождает глобальное пространство имен. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 3 октября, 2009 Опубликовано 3 октября, 2009 · Жалоба Что значит "к представлению"? К приватным членам? Если так, то вызываемая uart.HUMAX_Rx_Byte(), как функция класса, тоже имеет доступ к представлению класса:) Так что, имхо, единственное преимущество - что не загромождает глобальное пространство имен. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
west329 0 3 октября, 2009 Опубликовано 3 октября, 2009 · Жалоба Вобщем как я не пытался так и не получилось у меня повесит напрямую прерывание на метод класса. Пошол по другому пути, создал обычную процедуру повесил на неё прерывание а из него уже вызываю метод класса, незнаю можна так делать или нельзя, код проверял работает нормально. #pragma vector = USART0_RXC_vect __interrupt void Recive_Byte_from_tu(void) { ui8 Rx_Ch = Tu.HU_Rx_Byte(); .... .... ....} Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 3 октября, 2009 Опубликовано 3 октября, 2009 · Жалоба Что значит "к представлению"? К приватным членам? Да, к закрытой части класса. Если так, то вызываемая uart.HUMAX_Rx_Byte(), как функция класса, тоже имеет доступ к представлению класса:) А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд. Вобщем как я не пытался так и не получилось у меня повесит напрямую прерывание на метод класса. Пошол по другому пути, создал обычную процедуру повесил на неё прерывание а из него уже вызываю метод класса, незнаю можна так делать или нельзя, код проверял работает нормально. #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(); то не работает, что-ли? Что не работает в этом случае? Не собирается проект? Или в железе не работает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 3 октября, 2009 Опубликовано 3 октября, 2009 · Жалоба А так и функцию дополнительную городить не надо - сразу в этой все и пишешь. В общем, как делать - вопрос вкусовых предпочтений, по большей части. Но если есть возможность не плодить лишние сущности, то это есть гуд. Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса. Типа, uart.rxbuf[uart.rxpos++] = U0RXBUF; uart.rxpos &= uart.rxsize; И к тому же, такой подход не везде работает. Например, в avr-gcc нельзя сделать обработчик прерывания функцией класса. А вообще - да, согласен, дело вкуса:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 5 октября, 2009 Опубликовано 5 октября, 2009 · Жалоба Зато в этой функции придётся обращаться к членам класса с указанием экземпляра класса. Типа, uart.rxbuf[uart.rxpos++] = U0RXBUF; uart.rxpos &= uart.rxsize; Это всяко. :) Но по сути там и не может быть экземпляров - ведь работа же идет с конкретным аппаратным ресурсом, который в системе один, и регистры управления которым, как и вектор прерывания, жестко заданы. Поэтому и остальные ресурсы (типа буферов, индексов и т.п.) тоже существуют в единственном экземпляре и их тоже бы надо бы объявить как static. Экземпляры нужны, например, если на один вектор прерывания забиндено несколько (хотя бы два) UART'ов. Тогда да - тут появляются отдельные объекты класса. Но и в этом случае статическая функция класса рулит - она одна на все объекты класса, и является корневой для процесса обработки прерывания - прерывание вызывает ее, а уж внутри нее и выясняется (например, по соответствующим битам в регистре статуса/управления, от какого именно UART'а возникло прерывание), какому объекту (экземпляру) передать управление. Хотя я не сталкивался на практике с платформами, где на одном прерывании сидело два UART'а. :)Точнее, такое у нас есть, но UART'ы живут в ПЛИСке, и на этом прерывании много чего еще сидит. Т.е. это не готовая аппаратная платформа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 5 октября, 2009 Опубликовано 5 октября, 2009 · Жалоба Но и в этом случае статическая функция класса рулит - она одна на все объекты класса, и является корневой для процесса обработки прерывания - прерывание вызывает ее, а уж внутри нее и выясняется (например, по соответствующим битам в регистре статуса/управления, от какого именно UART'а возникло прерывание), какому объекту (экземпляру) передать управление. Хотя я не сталкивался на практике с платформами, где на одном прерывании сидело два UART'а. :) На ARM это как раз делаеться легко, просто один и тот же адрес обработчика подсовываете при инициализации а дальше разбор в обработчике по номеру переферийного блока в котором возникло прерывание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechin 0 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба а если я хочу созать шаблон класса с обработчиком внутри - компилятор не вставляет код обработчика. Мелькало где-то в обсуждениях, что для шаблонов именно так. Я обойти эту ситуацию не смог. Вот пример: хочу создать шаблон класса таймеров. Аргумент шаблона - используемый таймер А или 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 одна на оба экземпляра! В чем тут причина я так-же не смог понять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба в итоге в коде нет обработчиков. Как в этой ситуации поступить? Инстанцировать их явно. а hi_Word_of_Tick_Cntr одна на оба экземпляра! В чем тут причина я так-же не смог понять.Простите, а зачем вы пишете static в объявлении переменной, если не понимаете, зачем он нужен? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechin 0 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба Инстанцировать их явно. вот и не понимаю как. Для начала - как задать компилятору вектор прерывания? В нутри класса есть аргумент, определяющий A или B таймер. Вне класса - как определить, с каким таймером работаем? Вернее понимаю как на этапе создания класса, когда уже известно какой таймер будем использовать. Я же хочу сделать универсальный класс (ну вернее шаблон) - что бы подключил h файл и вообще не открывать его (для правки). Простите, а зачем вы пишете static в объявлении переменной, если не понимаете, зачем он нужен? Пишу для того, что бы она была доступна из обработчика прерывания. Ясно что в данном случае весь класс статический - т.е. более одного экземпляра существовать не может. насчет одной переменной на оба класса: я все-таки недопонимаю тогда шаблоны: ведь компилятор создает ДВА никак не связанных между собой класса, и поэтому как может получиться одна переменная на оба класса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба У меня есть БОЛЬШИЕ сомнения по поводу допустимости такой записи #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; } ... }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechin 0 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса Делал - говорю-ж - криво выходит. Во первых обработчики всегда будут существовать - т.е. при попытке задействовать другой обработчик линковщик ругается на два определения обработчика. Во вторых - изначально собирался ввести еще один аргумент шаблона: "функцию" таймера - выставление флага (SIGNAL_TIMER) или вызов процедуры (PROC_TIMER). А это уже другие действия в обработчике. Т.е. уже четыре обработчика. А тут уже никак. Через один универсальный шаблон все очень компактно и красиво получилось. Кроме того, что обработчиков прерываний в коде нет :( Прерывания придется делать вне класса, в виде обычных функций (в количестве 2х штук), и вызывать уже внутри них метод Timer_IRQ из конкретного класса А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить :( в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать. Еще замечание - использование огмоного количества констант, выбираемых по параметру шаблона, не есть гуд :( А почему? Компилироваться долго будет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 4 декабря, 2009 Опубликовано 4 декабря, 2009 · Жалоба А, я несколько не так понял. Так, должно получиться. И наверное даже компилятор подставновку сделает (т.е. не будет лишнего вызова). Проблема тогда только в том, что бы как-нибудь "красиво" задать обработчик - т.е. как бы дистанцируясь от аппаратуры (не могу объяснить :( в общем есть файл hardware.h, в котором определена вся аппаратура, и далее в программе никаких прямых упоминаний аппаратуры нет. Тут так не выйдет - надо будет где-то задать конкретный обработчик конкретного прерывания, что сразу свяжет программу с аппаратурой, чего хочется избежать.Ну и задать эту связку где нибудь в том же hardware.cpp Проблема в том, что обработчик привязывается с помощью #pragma, а это не языковая конструкция. Т.е. никакие template'ы к ней привязать нельзя. А почему? Компилироваться долго будет?Некрасиво. Масса констант для обоих таймеров вместе с if'ами равномерно размазанных по всему телу шаблонного класса. :cranky: Лучше эти константы собрать в одном месте (и отдельно для каждого таймера) с помощью классов TIMER_?, а в самом TTimer<> уже использовать имена, независящие от конкретного типа таймера Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться