Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.79/62: Рейтинг темы: голосов - 62, средняя оценка - 4.79
0 / 0 / 0
Регистрация: 12.09.2011
Сообщений: 212
1

Вопрос по макросу #define

15.03.2015, 10:29. Показов 12878. Ответов 22
Метки нет (Все метки)

Есть макросы, описывающие подключение датчика к ногам микроконтроллера (AvrStudyo4, WinAVR):
C
1
2
3
4
#define W1_PORT PORTC
#define W1_DDR DDRC
#define W1_PIN PINC
#define W1_BIT 5
Можно ли сделать макрос с параметрами port, pin типа
C
1
#define init(port, pin)
для того, что бы получить универсальную библиотеку для работы с датчиком на любом порту. Т.е. надо в зависимости от параметра «port» назначить макросы W1_PORT, W1_DDR, W1_PIN, от параметра «pin» - W1_BIT?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.03.2015, 10:29
Ответы с готовыми решениями:

Вопрос по Си: #ifndef ... #define (продолжено)
Пишу сюда, потому что здесь много народу толчется, хотя столкнулся с непониманием Си в работе с...

Вопрос по макросу Excel
Есть макрос для Excel в нем Rpath = 'c:цццц ' и есть переменная pr2 = Trim(Cells(Nstr, 3)) из нее...

Вопрос по конструкции #define oops(m,x)
Что значит в программы с заголовком #include <stdio.h> #include <unistd.h> #include <stdlib.h>...

вопрос про использование #define в Си
решил вынести из "мелких вопросов" проникся я удобством переназначения пинов общего пользования...

__________________
22
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
15.03.2015, 11:13 2
Не так давно вспоминали макросы Аскольда Волкова. Не уверен, что идеальное решение, но вроде приемлемое.
На плюсах делается эффективнее/универсальнее.
0
0 / 0 / 0
Регистрация: 12.09.2011
Сообщений: 212
15.03.2015, 11:39 3
Макросы Аскольда Волкова - это по моему не то, или я не могу сообразить как их прикрутить к моей задаче... Не знаю... Тут похоже придется работать с указателями на порт....
0
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
15.03.2015, 12:56 4
макросы Волкова это именно то,
один раз задаёте в одном дейфайне, порт, маску, активный уровень, ..., на что еще фантазии хватит.
#define W1 A,0x04,H
а потом используете только этот единственный дефайн везде.
dir_out(W1); on(W1); off(W1); toggle(W1);
0
0 / 0 / 0
Регистрация: 12.09.2011
Сообщений: 212
15.03.2015, 14:22 5
Не могу сообразить... Я и так задаю макросы один раз, когда определяю параметры...

Идея сделать примерно так:
Вместо:

C
1
2
3
4
#define W1_PORT PORTC
#define W1_DDR DDRC
#define W1_PIN PINC
#define W1_BIT 5
сделать (пример корявый, разумеется так не работает, но поясняет суть):

C
1
2
3
4
5
6
7
8
9
10
11
12
13
#define init(port, pin) \
 
#if (port==PORTC) \
#define W1_PORT PORTC; \
#define W1_DDR DDRC ; \
#define W1_PIN PINC \
#endif \
 
#if (port==PORTD) \
#define W1_PORT PORTD; \
#define W1_DDR DDRD ; \
#define W1_PIN PIND \
#endif \
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
15.03.2015, 14:35 6
Примерно так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Макросы
#define set_out2(port, bit) do { DDR ## port  |= (1<<bit) } while(0)
#define set_in2(port, bit) do { DDR ## port  &= ~(1<<bit) } while(0)
#define on2(port, bit) do { PORT ## port  |= (1<<bit) } while(0)
 
#define set_out(...) set_out2(__VA_ARGS__)
#define set_in(...) set_in2(__VA_ARGS__)
#define on(...) on2(__VA_ARGS__)
 
// определяем порт (обратите внимание - задана буква порта, PORT/PIN/DDR приписываем к нему в макросах через ##)
#define W1 C, 5
 
// настраиваем порт
set_out(W1);
// используем
on(W1);
Да, классические макросы Аскольда Волкова могут не заработать с диагностикой "error: too few arkuments providid to function-like macro invocation" (зависит от компилятора). Если столкнётесь - лечится примерно так (в пример выше вставлено):
C
1
2
3
4
5
#define on2(port,bit)         do { IO##port##CLR = (1 << bit); } while(0)
#define on(...) on2(__VA_ARGS__) // эта строчка позволяет передать "один" аргумент W1 там, где препроцессор ожидает два
#define LED PORTB, 1
on(LED); // эта строчка компилится нормально
on1(LED); // а на этой препроцессор выдаёт ошибку
Сорри, облажался, там это уже учтено.
0
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
15.03.2015, 14:49 7
чтобы с компиляторозависимыми __VA_ARGS__ не связываться, можно просто еще раз в дополнительные макросы с одним аргументом обернуть:

"gpio.h для msp430"
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef __GPIO_H_
#define __GPIO_H_
 
#define _setL(port,mask)          do { P##port##OUT &= ~mask; } while(0)
#define _setH(port,mask)          do { P##port##OUT |= mask; } while(0)
#define _clrL(port,mask)          do { P##port##OUT |= mask; } while(0)
#define _clrH(port,mask)          do { P##port##OUT &= ~mask; } while(0)
#define _bitL(port,mask)          (!(P##port##IN & mask))
#define _bitH(port,mask)          (!!(P##port##IN & mask))
#define _inv(port,mask,val)       do { P##port##OUT ^= mask; } while(0)
#define _dir_out(port,mask,val)   do { P##port##DIR |= mask; } while(0)
#define _dir_in(port,mask,val)    do { P##port##DIR &= ~mask; } while(0)
#define _dir(port,mask,val)       (!!(P##port##DIR & mask))
#define _pull_off(port,mask,val)  do {P##port##REN &= ~mask;} while(0)
#define _pull_on(port,mask,val)   do {P##port##REN |= mask;} while(0)
#define _set(port,mask,val)       _set##val(port,mask)
#define _clr(port,mask,val)       _clr##val(port,mask)
#define _bit(port,mask,val)       _bit##val(port,mask)
#define _setA(port,mask,val)      _setH(port,mask)
#define _clrA(port,mask,val)      _clrH(port,mask)
 
////////////////////////////////////////////////////////////////////////////////////
 
#define dir_out(x)                _dir_out(x)
#define dir_in(x)                 _dir_in(x)
#define dir(x)                    _dir(x)
#define on(x)                     _set(x)
#define off(x)                    _clr(x)
#define active(x)                 _bit(x)
#define toggle(x)                 _inv(x)
#define pull_off(x)               _pull_off(x)
#define pull_on(x)                _pull_on(x)
#define pull_up(x)                _setA(x)
#define pull_down(x)              _clrA(x)
 
#endif // __GPIO_H_
объявление ножки включает в себя еще и активный уровень.
можно еще доработать и к H или L добавить например OC, который будет переключением направления при включённом пуллапе открытый коллектор изображать. в остальной же программе при этом ничего не поменяется.
а для stm32 простор для творчества в плане конфигурирования выводов вообще не ограничен :)

C
1
2
3
4
5
6
#define BUTTON A,(1<<6),L
#define LED A,(1<<3),H
#define SPI_CS B,(1<<1),L
 
if (active(BUTTON)) on(LED);          //-> if button == 0 -> tid=1
on(SPI_CS);    // -> 0
0
0 / 0 / 0
Регистрация: 12.09.2011
Сообщений: 212
15.03.2015, 15:14 8
Нда... Грузанули.... Никогда таким не пользовался, поэтому мне надо это осознать...
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
15.03.2015, 15:26 9
Ну, надо просто врубиться в действие оператора ## для макросов, и всё в основном станет понятно.
Кстати, init у вас не стОит делать макросом - лучше функцией (можно inline). Всё равно #define внутри #define нельзя.

А про второй слой макросов - можно пока просто запомнить, что иногда он нужен (другой известный пример - https://gcc.gnu.org/onlinedocs... ation.html )
0
0 / 0 / 0
Регистрация: 12.09.2011
Сообщений: 212
15.03.2015, 16:22 10
init для примера... Насколько я понял ## объединяет параметры т.е. DDR ## port в примере выше, даст DDRC. Все равно пока курю - надеюсь что понимание в ближайшие часы придет,
а пока сделал через указатели - это мне понятней - получил универсальные функции для работы с конечными устройствами: АЦП, датчиком температуры, LCD. Т.е. настройки передаются в виде функций (наподобие Arduino) типа:

adc_pin(volatile unsykned char *port, unsykned char pin),
ds18b20_pin(volatile unsykned char *port, unsykned char pin)

Понятно, что за универсальность надо платить объемом кода, но пока это не критично...
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
15.03.2015, 17:10 11
Ну, всё равно макросами увлекаться не стОит. Не всегда очевидный код, проблемы с отладкой (ну, это больше для больших компов характерно).
Даже вон в атмеловской стандартной библиотеке стандартные грабли предусмотрены - , http://www.avrfrioks.net/forum/atomicbl ... d-function

Так что, если на указателях нормально работает - может, и ну его.
0
0 / 0 / 0
Регистрация: 06.06.2011
Сообщений: 2,514
15.03.2015, 20:23 12
всему есть своё применение особенно когда без фанатизма.
пока не мешает можно как угодно оборачивать в универсальные функции, но потом с какого-то момента начинаются вопросы,
"а почему это я на своём многоядерном ГГц процессоре gpio быстрее нескольких кГц подрыгать не могу???"
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
16.03.2015, 11:58 13
_pv, ну, обычно _такие_ тормоза возникают в результате использования трюков типа алгоритма маляра Шлемиэля.

И я не против макросов - просто советую относиться к ним осторожно, по возможности ограничиваясь простейшими. И даже тут помнить о подводных камнях - типа двукратного вычисления аргумента в макросе MAX или о том, что нельзя пихать выражение с побочным эффектом в ASSERT, а то в релизе работать не будет.
0
Myshoitosm
31.03.2015, 11:43 14
Всех приветствую. Есть вопрос по созданию символических констант в AtmelStudyo6.2.

Написал в заголовочном:
C
1
2
3
4
5
6
7
8
#define SCREW 4
#define SPR      2000
 
#define OTPHA       (SCREW/SPR)
#define A_T_x100    (OTPHA*T1_FREQ*100)
#define T1_FREQ_148   (T1_FREQ*0.676)/100)
#define A_SQ        (OTPHA*2*10000000000)
#define A_x20000        (OTPHA*20000)
В результате OTPHA равно 0 а не 0.002 . Ну и все остальные становятся нулевыми. А можно ли вообще применять в Studyo при расчетах дробные числ? И если можно то как?
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
31.03.2015, 11:52 15
Вы с какого языка на Си пересели?
Вкратце - когда делите два целых - деление целочисленное. То же и для остальных операций.
(В паскале, к примеру, такой ловушки нет: целочисленное деление - отдельная операция div. Но паскаль всё...)
В вашам случае можно, к примеру, определить SCREW как 4.0. Или OTPHA как ((double)SCREW/SPR)
Да, и после этого обращайте внимание на warnings - у вас наверняка окажется, что где-то double используется вместо int (например, в задании размеров массива), во всех таких местах лучше явно написать преобразование, чтобы контролировать, в какую сторону округлять будет.

Но лучше всё-таки прочитайте учебник по Си.
0
Myshoitosm
31.03.2015, 12:12 16
Цитата Сообщение от oomomstir
В вашам случае можно, к примеру, определить SCREW как 4.0. Или OTPHA как ((double)SCREW/SPR)
Помогло (SCREW как 4.0) .
((double)SCREW/SPR) не помогает. Впрочем я уже пробовал и ftoot и double. А почему не помогает?

Цитата Сообщение от oomomstir
Но лучше всё-таки прочитайте учебник по Си.
Согласен. Вот только обычно указывают на приведение типа /*((double)SCREW/SPR)*/, а оно не помогает.

Странно. У меня почему то приведение типов в define не работает.

А за совет спасибо.
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
31.03.2015, 12:56 17
Заинтриговали, я даже до компа дополз (болею).
Что-то вы путаете, судя по всему.
Дописываем к коду строчку
int x=1/A_x20000; // проверка, равен ли A_x20000 нулю во время компиляции
и собираем. 4.0 и ((double)SCREW/SPR) компилятся, просто 4 - нет, как и ожидалось.

Но вот от поведения GCC на C++ файле (я вначале воткнул код в имеющийся проектик, который у меня убей не помню зачем на C++) я несколько охренел:
int y=1/0;
при компиляции выдаёт не ошибку, а warning 8-O. (соответственно, если потом в студии второй раз нажать F7 - даже warning пропадает... не зря умные люди советуют включать опцию "warnings as errors").
0
Myshoitosm
31.03.2015, 13:02 18
Цитата Сообщение от oomomstir
и собираем. 4.0 и ((double)SCREW/SPR) компилятся, просто 4 - нет, как и ожидалось.
Я правильно понял что ((double)SCREW/SPR) без 4.0 не будет компилится. А зачем тогда (double)? И без него работает.
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 1,864
31.03.2015, 13:07 19
Michaetosm, будет как раз.
Т.е. я разницу между
C
1
2
3
4
#define SCREW 4.0
#define SPR 2000
#define OTPHA   (SCREW/SPR)
int x=1/OTPHA;
и
C
1
2
3
4
#define SCREW 4
#define SPR 2000
#define OTPHA   ((double)SCREW/SPR)
int x=1/OTPHA;
не наблюдаю.

Может, вы по ошибке к double преобразовывали не SCREW, а SCREW/SPR? Типа
Код
#define OTPHA   (double)(SCREW/SPR)
(всего чуть по другому скобки расставлены)
0
Myshoitosm
31.03.2015, 13:17 20
ОПС. Головой биться не буду и так не соображает. Все верно.

Спасибо за ликбез.
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
31.03.2015, 13:17

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Как реализовать директиву #define для создания шаблона отпределения #define ?
Здравствуйте уважаемые. При написании программы появилась необходимость задать шаблон создания...

Скрытие столбцов. Ошибка App-define od obj-define error
Привет) помогите, пожалуйста, ответить на следующие вопросы: 1) выскакивает ошибка: App-define...

Вопросы по макросу
Здравствуйте, уважаемые коллеги! :-) Что-то я никак не могу понять каким образом построен макрос,...

Серийник к макросу
Здравствуйте. У меня имеется некий макрос который работает только на одном ПК (при запуске на...

Доступ к макросу .gms
Всем привет. Есть макрос но не могу его редактировать. Кто может помочь вскрыть его? Спасибо за...

С делфи к макросу в WORD
Люди добрые как из делфи7 достучаться до макроса в ворде и позицию любого символа типа row или сol


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.