Перейти к содержанию
    

port definition for IAR C++

Всем доброго времени суток!

 

 

 

Для написания программ для 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.

 

 

 

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

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

приведен неполный код. То что вы привели по идее не должно быть причиной 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;
...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

приведен неполный код. То что вы привели по идее не должно быть причиной 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-а) прерывания. Ведь в прерывание я не смогу передать параметр, а функции класса всегда получают хотя бы один параметр - указатель класса. Делать для этого в модуле глобальную переменную -указатель? Или есть еще каки нибудь методы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По поводу кода: я попытался переделать на С++ драйвер 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-а) прерывания. Ведь в прерывание я не смогу передать параметр, а функции класса всегда получают хотя бы один параметр - указатель класса. Делать для этого в модуле глобальную переменную -указатель? Или есть еще каки нибудь методы?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

Сделать метод класса обработчиком прерывания - нельзя. Но можно объявить класс-драйвер так, чтобы он попадал в область видимости функции обработчика прерывания, т.о. внутри функции обработчка прерывания можно будет вызывать методы конкретного экземпляра этого класса.

 

Да я тоже подумал, что можно сделать другом класса функцию прерывания

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как победить эти warnings не знаю, они рождаются линкером при использовании прилагающихся к пакету заголовочных файлов ioxxx.h. А что касается обработчика прерывания - его можно сделать статическим членом класса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как победить эти warnings не знаю, они рождаются линкером при использовании прилагающихся к пакету заголовочных файлов ioxxx.h. А что касается обработчика прерывания - его можно сделать статическим членом класса.

 

 

 

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

 

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

 

 

 

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

 

Не можно его делать статическим членом класса - не будет доступа к НЕстатическим (читай - всем нужным мне) членам (переменным и функциям) этого класса. Кстати,другом тоже не получится, все равно придется передавать параметр-указатель класса. Стандартный путь - в модуле сделать глобальный указатель на класс. Кстати, таким макаром, я предвижу, можно будет и двумя USART поуправлять, если сделать две переменные. Хотя пока это только планы)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это должно быть то же, что

#include <ioavr.h>

Если оно где-то подключается (а лучше, ИМХО, именно его и подключать, а не ioxxx.h), то дважды включается нужный ioxxx.h, а там нет

#if !defined _ioxxx_h_

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

реплика не в тему созданную мной, но дабы не занимать пространство форума продолжу сдесь задавать вопросы по 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. В принципе я знаю про такой эффект компилятора, но надеялся что когда я перейду на Си++, компилятор "поумнеет". Увы.. Может быть кто занет как решить проблему, или подскажет способ, как внедрить прерывание в класс?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В итоге когда я посмотрел листинг то опешил, каждое прерывание сопровождается массовым сохранением в стек регистров, в начале, и таким же массовым в конце, что не есть хорошо на больших скоростях обмена по 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 функций, и постобработку принятых данных в основном цикле программы методами классов. Только такая организация потребует строго определенной структуры программы, что сделает Ваш драйвер менее универсальным, хотя и более эффективным.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Код у Вас небезопастный, а это плохо..

 

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

 

PS: избежать накладных расходов, на мой взгляд, можно в случае если скомбинировать обработку прерываний средствами inline функций, и постобработку принятых данных в основном цикле программы методами классов. Только такая организация потребует строго определенной структуры программы, что сделает Ваш драйвер менее универсальным, хотя и более эффективным.

 

Будем пробовать)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...