Страница 1 из 2
avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 06:34:05
sunjob
добрый день
есть ли возможность использовать препроцессор подобным образом? (пример в коде, естестенно "как есть" не прокатывает)
т.е. необходимо в зов-ти от определения порта (PORTB, PORTC, or PORTD) - вставлять соответствующие функции прерывания
AVR/Arduino
спасибо
Спойлер
Код: Выделить всё
#define PORT_XXX = PORTC
// ...
#if (PORT_XXX == PORTB)
ISR(PCINT0_vect)
#elif (PORT_XXX == PORTC)
ISR(PCINT1_vect)
#elif (PORT_XXX == PORTD)
ISR(PCINT2_vect)
#endif
{
// ...
}
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 06:45:29
ARV
увы, нельзя - я
это проходил уже...
можно извратиться, если определить кучу собственных констант, но это ничем не будет отличаться от того, чтобы просто использовать уже определенные константы для указания векторов прерываний.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 09:52:45
sunjob
с дополнительные определением "кучи всего" - это мне понятно...
хотел сделать локонично/короко/понятно
может кто обьяснить почему не катит условие:
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 10:05:15
Reflector
sunjob писал(а):может кто обьяснить почему не катит условие:
Посмотри как объявлен PORTB, для препроцессора это темный лес, он синтаксическим анализом не занимается.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 10:12:45
ARV
как мне объясняли, для препроцессора все нечисловые макросы одинаково не равны нулю, вот и все. т.е. если макрос определен типа так
#define MACRO 10, то препроцессор знает, что это 10. а если в определении макроса имя другого макроса, препроцессор знает только, что этот макрос определен и не равен нулю. поэтому любое сравнение таких макросов ВСЕГДА будет истинным.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 11:23:58
sunjob
порты определены как указатели, поэтому, "по идее" - все должно работать правильно, но при использовании такой конструкции выдается ошибка на предыдушее определение порта, т.е. на
Код: Выделить всё
#define PORT_XXX PORTC
^
encoder.h:42: error: operator '*' has no left operand
уточняю, код пишется под
AVR-ARDUINO (по моему там куча подводных камней... возможно, блин, это "ардуиновский подход" к работе с макросами ... )
п.с.
суть препроцессора - проще не бывает, брать "то что ему подсунули/определили" и "вставлять" эти определения, где он "повстречает", а если используются "условные операции", то обрабатывать их "как есть"... т.е. в данном случае идет сравнение указателей, по идее, такое сравнение должно быть корректным... но, видимо, ардуиновский "препроцессор" действует по своему... листинг препроцессора смотрел, вроде все нормально...
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 11:40:03
Reflector
sunjob писал(а):порты определены как указатели
PORTB имеет тип uint8_t, по крайней мере в gcc.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 11:44:23
ARV
на уровне препроцессора идет сравнение констант. на этапе сравнения слева и справа от == два макроса, т.е. две ненулевые величины, и это сравнение всегда истинно. раскрутки макросов на этом этапе не происходит. если слева макрос-число, то справа от == должно быть другое число, а не макрос. во всяком случае, я так понял...
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 11:50:43
Reflector
ARV писал(а):на уровне препроцессора идет сравнение констант. на этапе сравнения слева и справа от == два макроса, т.е. две ненулевые величины, и это сравнение всегда истинно. раскрутки макросов на этом этапе не происходит. если слева макрос-число, то справа от == должно быть другое число, а не макрос. во всяком случае, я так понял...
Код: Выделить всё
#define a(x, y) (x + y)
#define b(x, y) (x + y)
#if a(10, 5) == b(10, 5)
Какие тут проблемы? Никаких, значение имеет что именно внутри макросов, а не сам факт их наличия.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:03:12
ARV
возможно, я что-то не так понял или не правильно передал смысл понятого...
PORTB, например, это не число-константа, а значение по указателю, поэтому на этапе препроцессора проанализиорвано быть не может
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:07:04
Reflector
ARV писал(а):PORTB, например, это не число-константа, а значение по указателю, поэтому на этапе препроцессора проанализиорвано быть не может
Естественно. И адрес у PORTB тоже брать нельзя, т.к. препроцессор для таких вещей слишком примитивен.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:13:23
Siarzhuk
Reflector писал(а):PORTB имеет тип uint8_t, по крайней мере в gcc.
За PORTB скрывается обычно сложная синтаксическая конструкция из приведения абсолютного адреса регистра к структуре описывающей, ээээ, компоненты регистра. Препроцессор такие конструкции сравнивать не способен - только подставлять их текст в месте использования макроса. Компилятор и препроцессор - это по сути разные программы.
В любом случае не помешаетз заглянуть в файл определения регистров - возможно базовые регистры заданы как абсолютные адреса - а вот их сравнивать можно. И даже в качестве параметров в C++ template использовать.

Кстати, "гадания на препроцессоре" значительно облегчаются после нахождения и включения в настройках тулчейна опции "не удалять промежуточные файлы препроцессора" или "только препроцессить" (preprocess only). После чего в папке с объектными файлами ищется результат работы препроцессора с конкретным .с файлом до передачи его компилятору - и проблема сводится лишь к поиску соответствующего куска в портянке развёрнутого кода.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:22:33
Reflector
Siarzhuk писал(а):
За PORTB скрывается обычно сложная синтаксическая конструкция из приведения абсолютного адреса регистра к структуре описывающей, ээээ, компоненты регистра. Препроцессор такие конструкции сравнивать не способен - только подставлять их текст в месте использования макроса. Компилятор и препроцессор - это по сути разные программы.
Это собственно то, о чем я написал в своем первом посте этой темы

Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:28:50
sunjob
PORTB имеет тип uint8_t, по крайней мере в gcc.
если я не ошибаюсь :
Спойлер
Код: Выделить всё
//
// hardware/tools/avr/avr/include/avr/sfr_defs.h
//
#if _SFR_ASM_COMPAT
#ifndef __SFR_OFFSET
/* Define as 0 before including this file for compatibility with old asm
sources that don't subtract __SFR_OFFSET from symbolic I/O addresses. */
# if __AVR_ARCH__ >= 100
# define __SFR_OFFSET 0x00
# else
# define __SFR_OFFSET 0x20
# endif
#endif
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
#define _SFR_IO_ADDR(sfr) ((sfr) - __SFR_OFFSET)
#define _SFR_MEM_ADDR(sfr) (sfr)
#define _SFR_IO_REG_P(sfr) ((sfr) < 0x40 + __SFR_OFFSET)
#else /* !_SFR_ASM_COMPAT */
#ifndef __SFR_OFFSET
# if __AVR_ARCH__ >= 100
# define __SFR_OFFSET 0x00
# else
# define __SFR_OFFSET 0x20
# endif
#endif
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _SFR_IO16(io_addr) _MMIO_WORD((io_addr) + __SFR_OFFSET)
#define _SFR_MEM_ADDR(sfr) ((uint16_t) &(sfr))
#define _SFR_IO_ADDR(sfr) (_SFR_MEM_ADDR(sfr) - __SFR_OFFSET)
#define _SFR_IO_REG_P(sfr) (_SFR_MEM_ADDR(sfr) < 0x40 + __SFR_OFFSET)
//
// hardware/tools/avr/avr/include/avr/iom328p.h
//
#define PINB _SFR_IO8(0x03)
#define PINB0 0
#define PINB1 1
#define PINB2 2
#define PINB3 3
#define PINB4 4
#define PINB5 5
#define PINB6 6
#define PINB7 7
#define DDRB _SFR_IO8(0x04)
#define DDB0 0
#define DDB1 1
#define DDB2 2
#define DDB3 3
#define DDB4 4
#define DDB5 5
#define DDB6 6
#define DDB7 7
#define PORTB _SFR_IO8(0x05)
#define PORTB0 0
#define PORTB1 1
#define PORTB2 2
#define PORTB3 3
#define PORTB4 4
#define PORTB5 5
#define PORTB6 6
#define PORTB7 7
Кстати, "гадания на препроцессоре" значительно облегчаются после нахождения и включения в настройках тулчейна опции "не удалять промежуточные файлы препроцессора" или "только препроцессить" (preprocess only). После чего в папке с объектными файлами ищется результат работы препроцессора с конкретным .с файлом до передачи его компилятору - и проблема сводится лишь к поиску соответствующего куска в портянке развёрнутого кода.
ну собственно, ан-дурина это все и предоставляет по умолчанию... смотрел я "конечный результат" ... не помогло, :о) вот и обратился к котам :о))
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:34:24
Reflector
sunjob писал(а):если я не ошибаюсь :
А что есть _MMIO_BYTE?
Если порты - это адреса, тогда пришлось бы писать:
ps. Если объявлен _SFR_ASM_COMPAT, то похоже можно сделать как ты хочешь, но это облегчил жизнь в этом конкретном случае, но усложнит в большинстве остальных.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 12:54:39
sunjob
_MMIO_BYTE :
Код: Выделить всё
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
...
дак вот!!! еще одно, что до сих пор я не понял, по идее ДА, для доступа к данным по указателю нужно использовать операцию разыменования... ага, а вот нихренашечки :о) везде втч и в хелпах/учебниках обращаемся непосредственно в порт:
блин, и это работает
ешкин кот, и это тоже работает...едренть :о)
...
ну это применительно, конечно же к avr/дурина-андурина
нигде про "эти кошачьи загашнички" не написано, точнее нашел что то подходящее на западных сайтах, но смысл не был доступен мому разуму... вот, было бы неплохо, если найдутся такие, пару строк черкануть с дотошным описанием/обьяснением... а то как то "типизация" данного фрукта как "порт" не совсем понятна... :о) гипотетически ясно куда нас посылают, но все же хотелось бы уточнить.. :о)
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 13:05:45
ptr128
sunjob писал(а):
т.е. необходимо в зов-ти от определения порта (PORTB, PORTC, or PORTD) - вставлять соответствующие функции прерывания
Спойлер
Код: Выделить всё
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# define __INTR_ATTRS used, externally_visible
#else /* GCC < 4.1 */
# define __INTR_ATTRS used
#endif
#ifdef __cplusplus
# define ISR(vector, ...) \
extern "C" void vector (void) __attribute__ ((signal,__INTR_ATTRS)) __VA_ARGS__; \
void vector (void)
#else
# define ISR(vector, ...) \
void vector (void) __attribute__ ((signal,__INTR_ATTRS)) __VA_ARGS__; \
void vector (void)
#endif
#define _PORTB_SEQ_NUMBER_ 1
#define _PORTC_SEQ_NUMBER_ 2
#define _PORTD_SEQ_NUMBER_ 3
#define PORT_XXX _PORTC_SEQ_NUMBER_
// ...
#if PORT_XXX == _PORTB_SEQ_NUMBER_
ISR(PCINT0_vect)
#elif PORT_XXX == _PORTC_SEQ_NUMBER_
ISR(PCINT1_vect)
#elif PORT_XXX == _PORTD_SEQ_NUMBER_
ISR(PCINT2_vect)
#endif
{
// ...
}
Результат:
Спойлер
Код: Выделить всё
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 28 "test.c"
void PCINT1_vect (void) __attribute__ ((signal,used, externally_visible)) ; void PCINT1_vect (void)
{
}
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 13:18:10
sunjob
не помешали бы комментарии :о) если не сложно, муррр
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 13:25:48
ARV
какие еще комментарии? я с самого первого поста вам сказал
ARV писал(а):можно извратиться, если определить кучу собственных констант
вот вам и сделали кучу собственных констант
ptr128 писал(а):#define _PORTB_SEQ_NUMBER_ 1
#define _PORTC_SEQ_NUMBER_ 2
#define _PORTD_SEQ_NUMBER_ 3
#define PORT_XXX _PORTC_SEQ_NUMBER_
делать вектор прерывания в зависимости от выбранного порта вы все равно не можете - вам предлагают вместо порта выбирать свою константу. все, что выше - это лишнее для вашей задачи.
Re: avr c/c++ препроцессор для макроса PORT_x
Добавлено: Ср ноя 23, 2016 13:40:01
sunjob
хрюн, ты чего так нервничаешь? если тебя тут что то бесит, пожалуйста, не заходи сюда ...
> с дополнительные определением "кучи всего" - это мне понятно...
> хотел сделать локонично/короко/понятно
че да как мы тут с хозяином имели изначально "полную чашку всяких сущностей"...
Код: Выделить всё
#define ID_PORTB 0
#define ID_PORTC 1
#define ID_PORTD 2
#define XXX_ID_PORT ID_PORTC
...
#if (XXX_ID_PORT == ID_PORTB)
ISR(PCINT0_vect)
#elif (XXX_ID_PORT == ID_PORTC)
ISR(PCINT1_vect)
#elif (XXX_ID_PORT == ID_PORTD)
ISR(PCINT2_vect)
#endif
{
//...
}
p.s.
если че не понятно, это наш выкус из кода, кот. мы хотели упростить... из-за чего и появилась тема...
...
если будут более локоничные и красивые идеи, пишите, пожалуйста, надеюсь, обществу пригодится
всем спасибо