Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: port definition for IAR C++
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
prottoss
Всем доброго времени суток!



Для написания программ для AVR всегда пользовал язык С, хотя С++ знаю, но как то применял для МК, на Си было попроще. Сейчас встала необходимость применять С++ ...В принципе, все компилируется и работает, но линкер сыпет предупреждениями типа:



Warning[w35]: There is more than one definition for the struct/union type with tag '__C1'; class/struct/union field names do not match: UCSRA_Bit0 vs DDRC_Bit0
struct __C1 /* Elements: 8, Bytes: 1 */
{
unsigned char UCSRA_Bit0 : 1 /* disp: 0 */;
unsigned char UCSRA_Bit1 : 1 /* disp: 1 */;
unsigned char UCSRA_Bit2 : 1 /* disp: 2 */;
unsigned char UCSRA_Bit3 : 1 /* disp: 3 */;
unsigned char UCSRA_Bit4 : 1 /* disp: 4 */;
unsigned char UCSRA_Bit5 : 1 /* disp: 5 */;
unsigned char UCSRA_Bit6 : 1 /* disp: 6 */;
unsigned char UCSRA_Bit7 : 1 /* disp: 7 */;
};


etc.



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

Спасибо.
defunct
приведен неполный код. То что вы привели по идее не должно быть причиной warning'a.

Ну и почему бы не воспользоваться typedef struct..., определить структуру с разбивкой на биты B0..B7, и пользоваться этим типом там где это требуется.

пример:

Код
typedef struct /* Elements: 8, Bytes: 1 */
{ unsigned char
     B0 : 1,
     B1 : 1,
     B2 : 1,
     B3 : 1,
     B4 : 1,
     B5 : 1,
     B6 : 1,
     B7 : 1;
} TMyStruct;

volatile static __no_init TMyStruct DDRA @ 0x1A;
volatile static __no_init TMyStruct UCSRA @ 0x0B;
...
prottoss
Цитата(defunct @ May 27 2006, 22:48) *
приведен неполный код. То что вы привели по идее не должно быть причиной warning'a.

Ну и почему бы не воспользоваться typedef struct..., определить структуру с разбивкой на биты B0..B7, и пользоваться этим типом там где это требуется.




По поводу кода: я попытался переделать на С++ драйвер USART который я выложил в http://electronix.ru/forum/index.php?showtopic=10934# Он чуть вышего Вашего программного USART. Так вот, когда я переправил в глобальных опциях проекта CLIB на Normal DLIB (Full DLIB/ Custom DLIB), и откомпилировал проект, не написав еще ни единого класса, у меня пошли Warning-и. Так что код можете посмотреть. При CLIB ни каких предупреждений не было(((



>Re:Ну и почему бы не воспользоваться typedef struct...

Не хочется нагромождать код лишними конструкциями, так хуже воспринимается) К тому же я думаю есть более простой путь, может быть какой то хедер подключить?



Попутно еще вопрос, пусть даже на примере моего драйвера - как мне встроить в класс (допустим USART-а) прерывания. Ведь в прерывание я не смогу передать параметр, а функции класса всегда получают хотя бы один параметр - указатель класса. Делать для этого в модуле глобальную переменную -указатель? Или есть еще каки нибудь методы?
defunct
Цитата(prottoss @ May 27 2006, 18:21) *
По поводу кода: я попытался переделать на С++ драйвер USART который я выложил в http://electronix.ru/forum/index.php?showtopic=10934
...
Так вот, когда я переправил в глобальных опциях проекта CLIB на Normal DLIB (Full DLIB/ Custom DLIB), и откомпилировал проект, не написав еще ни единого класса, у меня пошли Warning-и. Так что код можете посмотреть. При CLIB ни каких предупреждений не было(((


Весьма странно. Откомпилировал Ваш проект как есть с Normal DLIB (embedded C++), единственный Warning:

Warning[Pe951]: return type of function "main" must be "int" C:\ATMEL\IAR\Prottoss\main.c 16

Цитата
Попутно еще вопрос, пусть даже на примере моего драйвера - как мне встроить в класс (допустим USART-а) прерывания. Ведь в прерывание я не смогу передать параметр, а функции класса всегда получают хотя бы один параметр - указатель класса. Делать для этого в модуле глобальную переменную -указатель? Или есть еще каки нибудь методы?

Сделать метод класса обработчиком прерывания - нельзя. Но можно объявить экземпляр класса (вашего драйвера) так, чтобы он попадал в область видимости функции обработчика прерывания, т.о. внутри функции обработчка прерывания можно будет вызывать методы конкретного экземпляра этого класса.
prottoss
Цитата(defunct @ May 27 2006, 23:41) *
Весьма странно. Откомпилировал Ваш проект как есть с Normal DLIB (embedded C++), единственный Warning:

Warning[Pe951]: return type of function "main" must be "int" C:\ATMEL\IAR\Prottoss\main.c 16


Хм...Значит буду щелкать галочками, что то где-то не включил-выключил...

Цитата(defunct @ May 27 2006, 23:41) *
Сделать метод класса обработчиком прерывания - нельзя. Но можно объявить класс-драйвер так, чтобы он попадал в область видимости функции обработчика прерывания, т.о. внутри функции обработчка прерывания можно будет вызывать методы конкретного экземпляра этого класса.


Да я тоже подумал, что можно сделать другом класса функцию прерывания
Сергей Борщ
Как победить эти warnings не знаю, они рождаются линкером при использовании прилагающихся к пакету заголовочных файлов ioxxx.h. А что касается обработчика прерывания - его можно сделать статическим членом класса.
prottoss
Цитата(Сергей Борщ @ May 28 2006, 00:05) *
Как победить эти warnings не знаю, они рождаются линкером при использовании прилагающихся к пакету заголовочных файлов ioxxx.h. А что касается обработчика прерывания - его можно сделать статическим членом класса.




Как победить Warning-и я уже разобрался, хотя может и не то сделал, но они исчезли)))

Options->Linker->Diagnostic->No_Global_Type_Checking = ON



>Re: А что касается обработчика прерывания - его можно сделать статическим членом класса

Не можно его делать статическим членом класса - не будет доступа к НЕстатическим (читай - всем нужным мне) членам (переменным и функциям) этого класса. Кстати,другом тоже не получится, все равно придется передавать параметр-указатель класса. Стандартный путь - в модуле сделать глобальный указатель на класс. Кстати, таким макаром, я предвижу, можно будет и двумя USART поуправлять, если сделать две переменные. Хотя пока это только планы)
sensor_ua
Это должно быть то же, что
#include <ioavr.h>
Если оно где-то подключается (а лучше, ИМХО, именно его и подключать, а не ioxxx.h), то дважды включается нужный ioxxx.h, а там нет
#if !defined _ioxxx_h_
prottoss
реплика не в тему созданную мной, но дабы не занимать пространство форума продолжу сдесь задавать вопросы по Embedded C++ и моих траблах с ним)



в итоге я содал класс:

Код


/*****************************************************************************
Описание класса USART
******************************************************************************/
class clUSART
{
/****************************************************************************/
protected:
   UINT RX_Flags;       // флаги ошибок
    UCHAR RX_Count;       // количество принятых байт в буфере
UCHAR RX_WrIndex;      // индекс для принимаемых в буфер данных
UCHAR RX_RdIndex;      // индекс для читаемых из буфера данных
   UCHAR  RX_Buffer[USART_RX_BUFFER_SIZE];// кольцевой FIFO буфер приемника

public:
void RX_Reset(void);    // сброс буфера приемника
BOOL RX_GetChar(UCHAR *dest);  // получить байт из буфера приемника
UCHAR RX_GetCount(void);   // проверить, если принятые данные
UCHAR RX_GetState(void);   // получить состояние приемника

/****************************************************************************/
protected:
UINT TX_Flags;       // флаги ошибок
    UCHAR TX_Count;       // количество отправляемых байт в буфере
UCHAR TX_WrIndex;      // индекс для принимаемых в буфер данных
UCHAR TX_RdIndex;      // индекс для читаемых из буфера данных
    UCHAR  TX_Buffer[USART_TX_BUFFER_SIZE];// кольцевой FIFO буфер передатчика

public:
void TX_Reset(void);   // сброс буфера передатчика
BOOL TX_PutChar(UCHAR srch); // отправить байт в буфер передатчика
UCHAR TX_GetCount(void);   // проверить, если данные для отправки
    UCHAR TX_GetState(void);   // получить состояние передатчика

/****************************************************************************/
protected:
    UCHAR Timeout;       // счетчик для подсчета таймаутов

public:
   BOOL IsFrameTimeout(void);  // проверить таймаут кадра

/****************************************************************************/
protected:

/****************************************************************************/
public:
   clUSART(void);
    void UDR_Empty(void);
    void RX_Complete(void);
    void TX_Complete(void);
    void TIMER_Timeout(void);
};




В модуле создал глобальную переменную, которую конструктор класса инициализирует адресом класса:



Код
  

/*****************************************************************************
Глобальные переменные
******************************************************************************/
clUSART *g_usart = NULL;


....





/*****************************************************************************
Инциализация USART
******************************************************************************/
clUSART::clUSART(void)
{



     g_usart = this;

....

}






А прерывания использовал так:



Код


/*****************************************************************************
Обработчик опустошения регистра данных передатчика USART UDR
******************************************************************************/
__interrupt void UDR_Empty(void)
{ g_usart->UDR_Empty();
}

void clUSART::UDR_Empty(void)
{

.....

}



// и так все остальные прерывания




В итоге когда я посмотрел листинг то опешил, каждое прерывание сопровождается массовым сохранением в стек регистров, в начале, и таким же массовым в конце, что не есть хорошо на больших скоростях обмена по USART. В принципе я знаю про такой эффект компилятора, но надеялся что когда я перейду на Си++, компилятор "поумнеет". Увы.. Может быть кто занет как решить проблему, или подскажет способ, как внедрить прерывание в класс?
defunct
Цитата(prottoss @ May 27 2006, 20:35) *
В итоге когда я посмотрел листинг то опешил, каждое прерывание сопровождается массовым сохранением в стек регистров, в начале, и таким же массовым в конце, что не есть хорошо на больших скоростях обмена по USART. В принципе я знаю про такой эффект компилятора, но надеялся что когда я перейду на Си++, компилятор "поумнеет". Увы.. Может быть кто занет как решить проблему, или подскажет способ, как внедрить прерывание в класс?

Увы и ах, такое поведение характерно не только для AVR Embedded C++, поэтому драйвера обычно пишутся без использования возможностей ООП.

Если посмотреть на это с другой стороны, то 32 байта стека и 128 циклов CPU не такая уж и большая цена за использование возможностей ООП. На 115200 с частотой следования байтов 11.52 Khz накладные расходы составят 13.3% от общей произодительности МК при частоте тактирования 11.059Mhz. Вполне терпимо..

Код
/*****************************************************************************
Глобальные переменные
******************************************************************************/
clUSART *g_usart = NULL;
....


/*****************************************************************************
Обработчик опустошения регистра данных передатчика USART UDR
******************************************************************************/
__interrupt void UDR_Empty(void)
{ g_usart->UDR_Empty();
}


Код у Вас небезопастный, а это плохо..
В обработчике прерывания, обязательно следовало бы добавить:
if (g_usart != NULL) ....

И наверное, коль Вы пишете класс, то вероятно для возможности обслуживания нескольких UART'ов одинаковыми средствами, поэтому глобальным должен быть не один объект, а список объектов, который логично формировать взависимости от, например, наличия аппаратных USART'ов МК (#ifdef UDR0, #ifdef UDR1 и т.п.)..

PS: избежать накладных расходов, на мой взгляд, можно в случае если скомбинировать обработку прерываний средствами inline функций, и постобработку принятых данных в основном цикле программы методами классов. Только такая организация потребует строго определенной структуры программы, что сделает Ваш драйвер менее универсальным, хотя и более эффективным.
prottoss
Цитата(defunct @ May 28 2006, 03:07) *
Увы и ах, такое поведение характерно не только для AVR Embedded C++, поэтому драйвера обычно пишутся без использования возможностей ООП. Если посмотреть на это с другой стороны, то 32 байта стека и 128 циклов CPU не такая уж и большая цена за использование возможностей ООП. На 115200 с частотой следования байтов 11.52 Khz накладные расходы составят 13.3% от общей произодительности МК при частоте тактирования 11.059Mhz. Вполне терпимо..


Согласен, по этому я оставил два варианта драйвера. Для одного УСАПП буду пользоваться Си, для двух или более) - Си++

Цитата(defunct @ May 28 2006, 03:07) *
Код у Вас небезопастный, а это плохо..


Согласен, это были просто наброски)

Цитата(defunct @ May 28 2006, 03:07) *
PS: избежать накладных расходов, на мой взгляд, можно в случае если скомбинировать обработку прерываний средствами inline функций, и постобработку принятых данных в основном цикле программы методами классов. Только такая организация потребует строго определенной структуры программы, что сделает Ваш драйвер менее универсальным, хотя и более эффективным.


Будем пробовать)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.