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

Битовые Операции В Gcc


rmatveev

Рекомендуемые сообщения

Друзья!

А можно ли как-то "красиво" осуществлять битовые операции в GCC?

Например, я хочу что бы кнопочка на ножке RA7 отражалась на светодиод на ножке PB0.

В рамках моих знаний надо писать как-то так:

if( PINA & 0b10000000 )

PORTB |= 0x00000001;

else

PORTB &= 0x11111110;

Это все не красиво ИМХО.

А красиво было бы так:

PORTB0 = PINA7;

Велосипед уже изобретен?

Спасибо!

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

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

А как с применением макроса может выглядеть такая операция?

set_bit( PORTB0, get_bit( PINA7 ) );

Так?

ЗЫ (PORTB0 и PINA7 - тоже макросы ессно)

Изменено пользователем rmatveev
Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

if(PINA & (1 << 7))
   PORTB |= (1 << 0);
else
   PORTB &= ~(1 << 0);

"a << b" означает "значение a, сдвинутое на b разрядов влево"

"~" означает инверсию (было 00010000, стало 11101111)

Изменено пользователем Tesla
Ссылка на комментарий
Поделиться на другие сайты

Не, так не очень красиво, я имел в виду SET не всмысле установить, а в смысле записать значение.

То есть поправлюсь:

write_bit( PORTB0, get_bit( PINA7 ) );

Получается что ничего лучше сделать?

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

не всмысле установить, а в смысле записать значение
А, понял. get_bit - тоже макрос, возвращающий значение.

Получается, что лучше не сделать. Чтобы с ПИНом работаь как с битом, нужно что бы компилятор поддерживал тип bit. Или можно через битовое поле, адрес которого будет адресом порта.

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

Продолжаю биться с сабжом в рамках того, что я накопал.

Вот хочу я объявить PORTB как битовое поле. PORTB в хедере определяется как _SFR_IO8(0x18) (это AtTiny26). Как мне тогда объявить PORTB0?

struct {

char b0: 1;

char b1: 1;

char b2: 1;

char b3: 1;

char b4: 1;

char b5: 1;

char b6: 1;

char b7: 1;

} _SFR_IO8(0x18) PORTB;

Но не компилируется (AVR-GCC). Пишет error: expected identifier or '(' before 'volatile'

UPD: Пока суть да дело, пишу по-старинке:

#define _DAC_DIN PORTA,0

#define _DAC_SCLK PORTA,2

#define _DAC_SYNC PORTA,3

#define _setb(port,bit) ( (port)|= (1<<(bit)) )

#define _clrb(port,bit) ( (port)&=~(1<<(bit)) )

#define _wrib(port,bit,data) ( (data)?(_setb(port,bit):(_clrb(port,bit)) )

#define _testb(port,bit) ( (port)&=(1<<(bit)) )

void WriteDAC( char value )

{

unsigned data = value;

data = data << 4;

_setb( _DAC_SYNC );

_setb( _DAC_SCLK );

_clrb( _DAC_SYNC );

for( int i=0; i<16; i++ )

{

_wrib( _DAC_DIN, _testb( data, 15 ) );

_clrb( _DAC_SCLK );

_setb( _DAC_SCLK );

}

}

Но компилятор ругается, что, например, макрос _clrb требует два параметра, а я ему даю только один. Т.е. вызов макроса внутри макроса отрабатывается не так как мне бы хотелось. Как можно форсить исполнить макрос внутри макроса?

Изменено пользователем rmatveev
Ссылка на комментарий
Поделиться на другие сайты

Как мне тогда объявить PORTB0?

#define PORTB0 PORTB.b0

..........
..........

PORTB0 = 1;
..........
if(PORTB0){
PORTB0 = 0;
}

А это для какого компилятора? У меня avr-gcc - ругается. Говорит: 'error: request for member 'b0' in something not a structure or union'

Т.е. я пишу:

PORTB.b0 = 1;

И получаю ошибку, которую указал выше :(

Или вы 'b0' взяли из моего кода? Так я его не могу применить, если я объявляю такую структуру - компилятор ее не пропускает...

Изменено пользователем rmatveev
Ссылка на комментарий
Поделиться на другие сайты

в хайтеке биты описываются так

/* Definitions for temp_PORTA register */
volatile	   bit RA0	 @((unsigned)&PORTA*8)+0;
volatile	   bit RA1	  @((unsigned)&PORTA*8)+1;
volatile	   bit RA2	 @((unsigned)&PORTA*8)+2;
volatile	   bit RA3  @((unsigned)&PORTA*8)+3;
volatile	   bit RA4  @((unsigned)&PORTA*8)+4;
volatile	   bit RA5  @((unsigned)&PORTA*8)+5;
volatile	   bit RA6  @((unsigned)&PORTA*8)+6;
volatile	   bit RA7  @((unsigned)&PORTA*8)+7;

может Gcc также....

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

Т.е. я пишу:

PORTB.b0 = 1;

И получаю ошибку, которую указал выше

Вы же сказали:
PORTB в хедере определяется как _SFR_IO8(0x18)
По этому, я так понял, что PORTB - структура, которую Вы привели.
Ссылка на комментарий
Поделиться на другие сайты

typedef struct{
   unsigned    b0:1 ;
   unsigned    b1:1 ;
   unsigned    b2:1 ;
   unsigned    b3:1 ;
   unsigned    b4:1 ;
   unsigned    b5:1 ;
   unsigned    b6:1 ;
   unsigned    b7:1 ;
}tPort;
const tPort* pPortA = (tPort*)&PORTA;
const tPort* pPortB = (tPort*)&PORTB;
const tPort* pPortC = (tPort*)&PORTC;

if(pPortA->b0){
   pPortB->b0 = 1;
}

Работать должно, но не известно во что это всё выльет компилятор.

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

typedef struct{
unsigned b0:1 ;
unsigned b1:1 ;
unsigned b2:1 ;
unsigned b3:1 ;
unsigned b4:1 ;
unsigned b5:1 ;
unsigned b6:1 ;
unsigned b7:1 ;
}tPort;
const tPort* pPortA = (tPort*)&PORTA;
const tPort* pPortB = (tPort*)&PORTB;
const tPort* pPortC = (tPort*)&PORTC;

if(pPortA->b0){
pPortB->b0 = 1;
}

Работать должно, но не известно во что это всё выльет компилятор.

Попробовал. Теперь компилятор ругается на то, что объект только на чтение :(

Я попробовал на чтение. Но констукция:

if( pPortA->b0 ) blablabla();

Компилируется в:

lds r30, 0x0062

lds r31, 0x0063

ld r18, (z)

sbrs r18, 0

rjmp .+10

Т.е. мягко говоря не то... Загрузка в R18 содержимого ячейки по адресу 0x6362 и уже в загруженном проверяется бит

Изменено пользователем rmatveev
Ссылка на комментарий
Поделиться на другие сайты

в хайтеке биты описываются так

/* Definitions for temp_PORTA register */
volatile	 bit RA0	 @((unsigned)&PORTA*8)+0;
volatile	 bit RA1	 @((unsigned)&PORTA*8)+1;
volatile	 bit RA2	 @((unsigned)&PORTA*8)+2;
volatile	 bit RA3 @((unsigned)&PORTA*8)+3;
volatile	 bit RA4 @((unsigned)&PORTA*8)+4;
volatile	 bit RA5 @((unsigned)&PORTA*8)+5;
volatile	 bit RA6 @((unsigned)&PORTA*8)+6;
volatile	 bit RA7 @((unsigned)&PORTA*8)+7;

может Gcc также....

:(Error: Unknown type 'bit'

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

Ура! Кажется, нашел решение. Здесь: http://www.avrfreaks...er=asc&start=36

Цитирую (лишние для меня регистры я удалил):

typedef struct
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
} BYTE_BITFIELD;

#define ddra (*((volatile BYTE_BITFIELD*)(&DDRA)))
#define ddrb (*((volatile BYTE_BITFIELD*)(&DDRB)))
#define porta (*((volatile BYTE_BITFIELD*)(&PORTA)))
#define portb (*((volatile BYTE_BITFIELD*)(&PORTB)))
#define pina (*((volatile BYTE_BITFIELD*)(&PINA)))
#define pinb (*((volatile BYTE_BITFIELD*)(&PINB)))

#define _DAC_DIN porta.bit0
#define _DAC_SCLK porta.bit2
#define _DAC_SYNC porta.bit3

void WriteDAC( char value )
{
unsigned data = value;
if( _DAC_DIN )
_DAC_SYNC = 1;

НО! К сожалению, if( _DAC_DIN ) компилируется в неоптимальный код

in r18,0x1b
sbrs r18,0

вместо оптимального и, на мой взгляд, очевидного

sbis 0x1b,0

Попробовал разные варианты оптимизации, получается сделать только хуже.

Изменено пользователем rmatveev
Ссылка на комментарий
Поделиться на другие сайты

Теперь компилятор ругается на то, что объект только на чтение
const уберите и поставьте volatile - получится то-же самое, что и Вы нашли. Ну почти тоже самое... В моём примере создаются указатели, а в Вашем всё делается через дефайны.
НО! К сожалению, if( _DAC_DIN ) компилируется в неоптимальный код
Вы бы разобрались что происходит, тогда поняли бы почему код получается не оптимальный... Работа с регистрами происходит через указатели, иначе никак...

PS: Кстати, попробуйте в Вашем коде, в дефайнах, убрать volatile и посмотрите на код. Возможно, оптимизатор отработает своё и будет Вам чудо :)

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

НО! К сожалению, if( _DAC_DIN ) компилируется в неоптимальный код
Вы бы разобрались что происходит, тогда поняли бы почему код получается не оптимальный... Работа с регистрами происходит через указатели, иначе никак...

PS: Кстати, попробуйте в Вашем коде, в дефайнах, убрать volatile и посмотрите на код. Возможно, оптимизатор отработает своё и будет Вам чудо :)

Убрал. Компилируетя, но результат тот же.

Скажите, а где можно почитать про модификаторы вроде volatile? Я что-то толковой документации на WinAVR (или как правильнее сказать: GCC?) так и не нашел.

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

Спасибо, почитал, многое понял. Но все-таки это немножко не то. Я хотел доки на РАЗНЫЕ модификаторы типов данных. Может быть среди них я бы нашел нужный мне. Но я даже е знаю какие они бывают (ну кроме volatile)

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

  • 1 год спустя...

Я для доступа к битам порта использую следующий способ:

union bfbyte

{

struct

{

unsigned char bit0 :1;

unsigned char bit1 :1;

unsigned char bit2 :1;

unsigned char bit3 :1;

unsigned char bit4 :1;

unsigned char bit5 :1;

unsigned char bit6 :1;

unsigned char bit7 :1;

};

unsigned char byte; // это поле для того чтоб сразу байт в порт вывести

};

#ifdef PORTB

#define portb (*((volatile bfbyte*)&PORTB))

#endif

int main(void)

{

while(1)

{

portb.bit0 = 1; // установка PB0 в 1

portb.bit0 = 0; // установка PB0 в 0

portb.byte = 0x03; // Запись в порт значения

}

}

Работает в AvrStudio 6.1. При вводе точки после имени (portb) штатная подсветка ситтаксиса предлагает варианты полей что очень удобно

Компилятором генерится следующий код:

00000019 LDI R24,0x03 Load immediate // загрузка значения порта в регистр

0000001A SBI 0x18,0 Set bit in I/O register // portb.bit0 = 1;

0000001B CBI 0x18,0 Clear bit in I/O register // portb.bit0 = 0;

0000001C OUT 0x18,R24 Out to I/O location // portb.byte = 0x03;

0000001D RJMP PC-0x0003 Relative jump // переход (бесконечный цикл)

как видно из листинга никаких излишеств!

Изменено пользователем Quake3
Ссылка на комментарий
Поделиться на другие сайты

Продолжаю биться с сабжом в рамках того, что я накопал.

Вот хочу я объявить PORTB как битовое поле. PORTB в хедере определяется как _SFR_IO8(0x18) (это AtTiny26). Как мне тогда объявить PORTB0?

struct {

char b0: 1;

char b1: 1;

char b2: 1;

char b3: 1;

char b4: 1;

char b5: 1;

char b6: 1;

char b7: 1;

} _SFR_IO8(0x18) PORTB;

Но не компилируется (AVR-GCC). Пишет error: expected identifier or '(' before 'volatile'

UPD: Пока суть да дело, пишу по-старинке:

#define _DAC_DIN PORTA,0

#define _DAC_SCLK PORTA,2

#define _DAC_SYNC PORTA,3

#define _setb(port,bit) ( (port)|= (1<<(bit)) )

#define _clrb(port,bit) ( (port)&=~(1<<(bit)) )

#define _wrib(port,bit,data) ( (data)?(_setb(port,bit) :(_clrb(port,bit)) )

#define _testb(port,bit) ( (port)&=(1<<(bit)) )

void WriteDAC( char value )

{

unsigned data = value;

data = data << 4;

_setb( _DAC_SYNC );

_setb( _DAC_SCLK );

_clrb( _DAC_SYNC );

for( int i=0; i<16; i++ )

{

_wrib( _DAC_DIN, _testb( data, 15 ) );

_clrb( _DAC_SCLK );

_setb( _DAC_SCLK );

}

}

Но компилятор ругается, что, например, макрос _clrb требует два параметра, а я ему даю только один. Т.е. вызов макроса внутри макроса отрабатывается не так как мне бы хотелось. Как можно форсить исполнить макрос внутри макроса?

Я для доступа к битам порта использую следующий способ:

union bfbyte

{

struct

{

unsigned char bit0 :1;

unsigned char bit1 :1;

unsigned char bit2 :1;

unsigned char bit3 :1;

unsigned char bit4 :1;

unsigned char bit5 :1;

unsigned char bit6 :1;

unsigned char bit7 :1;

};

unsigned char byte; // это поле для того чтоб сразу байт в порт вывести

};

#ifdef PORTB

#define portb (*((volatile bfbyte*)&PORTB))

#endif

int main(void)

{

while(1)

{

portb.bit0 = 1; // установка PB0 в 1

portb.bit0 = 0; // установка PB0 в 0

portb.byte = 0x03; // Запись в порт значения

}

}

Работает в AvrStudio 6.1. При вводе точки после имени (portb) штатная подсветка ситтаксиса предлагает варианты полей что очень удобно

Компилятором генерится следующий код:

00000019 LDI R24,0x03 Load immediate // загрузка значения порта в регистр

0000001A SBI 0x18,0 Set bit in I/O register // portb.bit0 = 1;

0000001B CBI 0x18,0 Clear bit in I/O register // portb.bit0 = 0;

0000001C OUT 0x18,R24 Out to I/O location // portb.byte = 0x03;

0000001D RJMP PC-0x0003 Relative jump // переход (бесконечный цикл)

как видно из листинга никаких излишеств!

Изменено пользователем Quake3
Ссылка на комментарий
Поделиться на другие сайты

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

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

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

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

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...