Форум программистов, компьютерный форум, киберфорум
Наши страницы
C (Си)
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
_20_
12 / 11 / 4
Регистрация: 29.09.2011
Сообщений: 265
1

Тонкости языка С,define

04.09.2016, 06:24. Просмотров 711. Ответов 10
Метки нет (Все метки)

Здравствуйте.
Разбираюсь с одной либой для hd44780, есть вопрос по поводу использования define'ов.
Вот отрывок:
C
1
2
3
4
5
6
7
8
9
#define GLUE(a, b)     a##b
 
/* single-bit macros, used for control bits */
#define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
#define SET(what, x) SET_(what, x)
#define CLR(what, x) CLR_(what, x)
#define GET(/* PIN, */ x) GET_(x)
Вот как так, CLR определенна с двумя переменными как CLR_ с двумя переменными, но CLR_ с двумя переменными не определенна, вместо этого определенна CLR_ с тремя переменными, как это может работать?

Вот полный код файла:
HD44780.c
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * ----------------------------------------------------------------------------
 *
 * HD44780 LCD display driver
 *
 * The LCD controller is used in 4-bit mode with a full bi-directional
 * interface (i.e. R/~W is connected) so the busy flag can be read.
 *
 * $Id$
 */
 
#include "defines.h"
 
#include <stdbool.h>
#include <stdint.h>
 
#include <avr/io.h>
#include <util/delay.h>
 
#include "hd44780.h"
 
#define GLUE(a, b)     a##b
 
/* single-bit macros, used for control bits */
#define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
#define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
#define SET(what, x) SET_(what, x)
#define CLR(what, x) CLR_(what, x)
#define GET(/* PIN, */ x) GET_(x)
 
/* nibble macros, used for data path */
#define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \
                        ~((1 << (m)) | (1 << ((m) + 1)) | \
                          (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \
                            ((v) << (m))
#define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \
                        (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m)
#define ASSIGN(what, x, v) ASSIGN_(what, x, v)
#define READ(what, x) READ_(what, x)
 
#define HD44780_BUSYFLAG 0x80
 
/*
 * Send one pulse to the E signal (enable).  Mind the timing
 * constraints.  If readback is set to true, read the HD44780 data
 * pins right before the falling edge of E, and return that value.
 */
static inline uint8_t
hd44780_pulse_e(bool readback) __attribute__((always_inline));
 
static inline uint8_t
hd44780_pulse_e(bool readback)
{
  uint8_t x;
 
  SET(PORT, HD44780_E);
  /*
   * Guarantee at least 500 ns of pulse width.  For high CPU
   * frequencies, a delay loop is used.  For lower frequencies, NOPs
   * are used, and at or below 1 MHz, the native pulse width will
   * already be 1 us or more so no additional delays are needed.
   */
#if F_CPU > 4000000UL
  _delay_us(0.5);
#else
  /*
   * When reading back, we need one additional NOP, as the value read
   * back from the input pin is sampled close to the beginning of a
   * CPU clock cycle, while the previous edge on the output pin is
   * generated towards the end of a CPU clock cycle.
   */
  if (readback)
    __asm__ volatile("nop");
#  if F_CPU > 1000000UL
  __asm__ volatile("nop");
#    if F_CPU > 2000000UL
  __asm__ volatile("nop");
  __asm__ volatile("nop");
#    endif /* F_CPU > 2000000UL */
#  endif /* F_CPU > 1000000UL */
#endif
  if (readback)
    x = READ(PIN, HD44780_D4);
  else
    x = 0;
  CLR(PORT, HD44780_E);
 
  return x;
}
 
/*
 * Send one nibble out to the LCD controller.
 */
static void
hd44780_outnibble(uint8_t n, uint8_t rs)
{
  CLR(PORT, HD44780_RW); // Запись в дисплей.
  if (rs)                // Посылаем данные.
    SET(PORT, HD44780_RS);
  else                   // Или команды.
    CLR(PORT, HD44780_RS);
  ASSIGN(PORT, HD44780_D4, n);// Посылаем данные.
  (void)hd44780_pulse_e(false);// Подаём импульс.
}
 
/*
 * Send one byte to the LCD controller.  As we are in 4-bit mode, we
 * have to send two nibbles.
 */
void
hd44780_outbyte(uint8_t b, uint8_t rs)
{
  hd44780_outnibble(b >> 4, rs);
  hd44780_outnibble(b & 0xf, rs);
}
 
/*
 * Read one nibble from the LCD controller.
 */
static uint8_t
hd44780_innibble(uint8_t rs)
{
  uint8_t x;
 
  SET(PORT, HD44780_RW);
  ASSIGN(DDR, HD44780_D4, 0x00);
  if (rs)
    SET(PORT, HD44780_RS);
  else
    CLR(PORT, HD44780_RS);
  x = hd44780_pulse_e(true);
  ASSIGN(DDR, HD44780_D4, 0x0F);
  CLR(PORT, HD44780_RW);
 
  return x;
}
 
/*
 * Read one byte (i.e. two nibbles) from the LCD controller.
 */
uint8_t
hd44780_inbyte(uint8_t rs)
{
  uint8_t x;
 
  x = hd44780_innibble(rs) << 4;
  x |= hd44780_innibble(rs);
 
  return x;
}
 
/*
 * Wait until the busy flag is cleared.
 */
void
hd44780_wait_ready(bool longwait)
{
#if USE_BUSY_BIT
  while (hd44780_incmd() & HD44780_BUSYFLAG) ;
#else
  if (longwait)
    _delay_ms(1.52);
  else
    _delay_us(37);
#endif
}
 
/*
 * Initialize the LCD controller.
 *
 * The initialization sequence has a mandatory timing so the
 * controller can safely recognize the type of interface desired.
 * This is the only area where timed waits are really needed as
 * the busy flag cannot be probed initially.
 */
void
hd44780_init(void)
{
  SET(DDR, HD44780_RS);
  SET(DDR, HD44780_RW);
  SET(DDR, HD44780_E);
  ASSIGN(DDR, HD44780_D4, 0x0F);
 
  _delay_ms(15);        /* 40 ms needed for Vcc = 2.7 V */
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);// -- отсюда
  _delay_ms(4.1);
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
  _delay_ms(0.1);
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);// -- досюда
  _delay_us(37);    // инициализация одинаковая для 8ми и 4х битного 
                                                    // подключения.
  hd44780_outnibble(HD44780_FNSET(0, 1, 0) >> 4, 0);// выбор 4х битного подключения.
  hd44780_wait_ready(false);
  hd44780_outcmd(HD44780_FNSET(0, 1, 0));// Выбор режима.
  hd44780_wait_ready(false);
  hd44780_outcmd(HD44780_DISPCTL(0, 0, 0));// выключение дисплея.
  hd44780_wait_ready(false);
}
 
/*
 * Prepare the LCD controller pins for powerdown.
 */
void
hd44780_powerdown(void)
{
  ASSIGN(PORT, HD44780_D4, 0);
  CLR(PORT, HD44780_RS);
  CLR(PORT, HD44780_RW);
  CLR(PORT, HD44780_E);
}


HD44780.h
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * ----------------------------------------------------------------------------
 *
 * HD44780 LCD display driver
 *
 * $Id$
 */
 
/*
 * Send byte b to the LCD.  rs is the RS signal (register select), 0
 * selects instruction register, 1 selects the data register.
 */
void    hd44780_outbyte(uint8_t b, uint8_t rs);
 
/*
 * Read one byte from the LCD controller.  rs is the RS signal, 0
 * selects busy flag (bit 7) and address counter, 1 selects the data
 * register.
 */
uint8_t hd44780_inbyte(uint8_t rs);
 
/*
 * Wait for the busy flag to clear.
 */
void    hd44780_wait_ready(bool islong);
 
/*
 * Initialize the LCD controller hardware.
 */
void    hd44780_init(void);
 
/*
 * Prepare the LCD controller pins for powerdown.
 */
void    hd44780_powerdown(void);
 
 
/* Send a command to the LCD controller. */
#define hd44780_outcmd(n)   hd44780_outbyte((n), 0)
 
/* Send a data byte to the LCD controller. */
#define hd44780_outdata(n)  hd44780_outbyte((n), 1)
 
/* Read the address counter and busy flag from the LCD. */
#define hd44780_incmd()     hd44780_inbyte(0)
 
/* Read the current data byte from the LCD. */
#define hd44780_indata()    hd44780_inbyte(1)
 
 
/* Clear LCD display command. */
#define HD44780_CLR \
    0x01
 
/* Home cursor command. */
#define HD44780_HOME \
    0x02
 
/*
 * Select the entry mode.  inc determines whether the address counter
 * auto-increments, shift selects an automatic display shift.
 */
#define HD44780_ENTMODE(inc, shift) \
    (0x04 | ((inc)? 0x02: 0) | ((shift)? 1: 0))
 
/*
 * Selects disp[lay] on/off, cursor on/off, cursor blink[ing]
 * on/off.
 */
#define HD44780_DISPCTL(disp, cursor, blink) \
    (0x08 | ((disp)? 0x04: 0) | ((cursor)? 0x02: 0) | ((blink)? 1: 0))
 
/*
 * With shift = 1, shift display right or left.
 * With shift = 0, move cursor right or left.
 */
#define HD44780_SHIFT(shift, right) \
    (0x10 | ((shift)? 0x08: 0) | ((right)? 0x04: 0))
 
/*
 * Function set.  if8bit selects an 8-bit data path, twoline arranges
 * for a two-line display, font5x10 selects the 5x10 dot font (5x8
 * dots if clear).
 */
#define HD44780_FNSET(if8bit, twoline, font5x10) \
    (0x20 | ((if8bit)? 0x10: 0) | ((twoline)? 0x08: 0) | \
        ((font5x10)? 0x04: 0))
 
/*
 * Set the next character generator address to addr.
 */
#define HD44780_CGADDR(addr) \
    (0x40 | ((addr) & 0x3f))
 
/*
 * Set the next display address to addr.
 */
#define HD44780_DDADDR(addr) \
    (0x80 | ((addr) & 0x7f))


defines.h
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
/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * ----------------------------------------------------------------------------
 *
 * General stdiodemo defines
 *
 * $Id$
 */
 
/* CPU frequency */
#define F_CPU 1000000UL
 
/* UART baud rate */
#define UART_BAUD  9600
 
/* HD44780 LCD port connections */
#define HD44780_RS A, 6
#define HD44780_RW A, 4
#define HD44780_E  A, 5
/* The data bits have to be not only in ascending order but also consecutive. */
#define HD44780_D4 A, 0
 
/* Whether to read the busy flag, or fall back to
   worst-time delays. */
#define USE_BUSY_BIT 1
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
04.09.2016, 06:24
Ответы с готовыми решениями:

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

Тонкости работы с vararg
Думается, многим будет полезно попробовать разобраться с одной проблемой. С...

Обмен переменных через XOR - тонкости
main() { int a=5, b=10; a^=b; b^=a; a^=b; printf(&quot;%d %d&quot;, a, b); }...

#define
Не работает следующий пример - если удалить строку 5 #define DEBUG, то...

#define и const
В чем их различия? Делая тест по подготовке к ЕГЭ, в заданиях части С были...

10
ValeryS
Модератор
7264 / 5518 / 692
Регистрация: 14.02.2011
Сообщений: 18,691
04.09.2016, 07:12 2
Цитата Сообщение от _20_ Посмотреть сообщение
Вот как так, CLR определенна с двумя переменными
есть пример применения???
сдается мне что при вызове дефайна используется три аргумента
вообще вопрос то про Си а не про AVR
перенести?
там быстрей ответят
0
_20_
12 / 11 / 4
Регистрация: 29.09.2011
Сообщений: 265
04.09.2016, 16:22  [ТС] 3
ValeryS,
Вот пример из той же библиотеки. Коментарии мои.
C
1
2
3
4
5
6
7
8
9
10
11
static void
hd44780_outnibble(uint8_t n, uint8_t rs)
{
  CLR(PORT, HD44780_RW); // Запись в дисплей.
  if (rs)                // Посылаем данные.
    SET(PORT, HD44780_RS);
  else                   // Или команды.
    CLR(PORT, HD44780_RS);
  ASSIGN(PORT, HD44780_D4, n);// Посылаем данные.
  (void)hd44780_pulse_e(false);// Подаём импульс.
}
Перенесите, если считаете, что так будет лучше, спасибо.
0
ValeryS
Модератор
7264 / 5518 / 692
Регистрация: 14.02.2011
Сообщений: 18,691
04.09.2016, 17:01 4
Цитата Сообщение от _20_ Посмотреть сообщение
CLR(PORT, HD44780_RW);
как определены макросы PORT и HD44780_RW?
0
_20_
12 / 11 / 4
Регистрация: 29.09.2011
Сообщений: 265
04.09.2016, 17:49  [ТС] 5
Цитата Сообщение от ValeryS Посмотреть сообщение
как определены макросы PORT и HD44780_RW?
HD44780_RW определена в defines.h
C
1
#define HD44780_RW A, 4
Где определена PORT я так и не нашёл, думаю самому определять надо.
0
Evg
Эксперт CАвтор FAQ
19288 / 7147 / 528
Регистрация: 30.03.2009
Сообщений: 19,997
Записей в блоге: 30
04.09.2016, 19:16 6
Лучший ответ Сообщение было отмечено ValeryS как решение

Решение

"CLR(PORT, HD44780_RS)" превращается в "CLR_(PORT, A, 4)" в соответствии с тем, как определено HD44780_RW
2
ValeryS
Модератор
7264 / 5518 / 692
Регистрация: 14.02.2011
Сообщений: 18,691
04.09.2016, 19:30 7
Лучший ответ Сообщение было отмечено Evg как решение

Решение

Цитата Сообщение от _20_ Посмотреть сообщение
HD44780_RW A, 4
вот они и три аргумента
Цитата Сообщение от Evg Посмотреть сообщение
CLR_(PORT, A, 4)
Цитата Сообщение от _20_ Посмотреть сообщение
Где определена PORT я так и не нашёл, думаю самому определять надо.
не надо
PORT, A превратится в PORTA, благодаря вот этому макросу
Цитата Сообщение от _20_ Посмотреть сообщение
C
1
#define GLUE(a, b)    a##b
1
_20_
12 / 11 / 4
Регистрация: 29.09.2011
Сообщений: 265
04.09.2016, 19:55  [ТС] 8
Спасибо, но всё - таки требуется небольшое пояснение.
Имеем:
C
1
2
3
4
#define HD44780_RW A, 4
#define GLUE(a, b)     a##b
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
#define CLR(what, x) CLR_(what, x)
C
1
CLR(PORT, HD44780_RW);
Преврашается в
C
1
CLR(PORT, A, 4);
, но CLR с тремя аргументами не определенно. Как препроцессор понимает, что 3 аргумента - это два, которые три?
0
Evg
Эксперт CАвтор FAQ
19288 / 7147 / 528
Регистрация: 30.03.2009
Сообщений: 19,997
Записей в блоге: 30
04.09.2016, 20:12 9
Цитата Сообщение от _20_ Посмотреть сообщение
Преврашается в
Превращается не в CLR, а в CLR_ (превращается в процессе раскрытия макроса CLR)
1
_20_
12 / 11 / 4
Регистрация: 29.09.2011
Сообщений: 265
04.09.2016, 20:27  [ТС] 10
Должна же быть какая - то очерёдность в действиях?
Можете по шагам расписать, очерёдность макросов, и почему эта очерёдность именно такая, а не какая - либо ещё?

Добавлено через 7 минут
Я так понимаю, что бы это работало, сначала должен исполниться макрос
C
1
#define CLR(what, x) CLR_(what, x)
и превратить
C
1
CLR(PORT, HD44780_RW);
в
C
1
CLR_(PORT, HD44780_RW);
, потом макрос
C
1
#define HD44780_RW A, 4
, в результате получаем
C
1
CLR_(PORT, A, 4);
, а затем уже макрос
C
1
#define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
Но если очерёдность макросов измениться, результата ма не получим, ведь так?
Что помогает компилятору выбрать правильную последовательность макросов?
0
Evg
Эксперт CАвтор FAQ
19288 / 7147 / 528
Регистрация: 30.03.2009
Сообщений: 19,997
Записей в блоге: 30
05.09.2016, 09:23 11
Замена макроса CLR на "CLR_(параметры)" делается одновременно с подстановкой параметров. Т.е. берётся правая часть дефайна и вместо "CLR(PORT, HD44780_RW)" подставляется вся правая часть. Т.е. сначала подставили "CLR_(", затем должны вписать "what", но видим, что "what" это параметр, а потому вместо "what" пишем "PORT", затем пишем ", ". Затем должны вписать "x", но видим, что "x" это параметр, а потому должны как бы вписать "HD44780_RW", но оно является макросом, а потому вместо "x" пишем "A, 4". И затем уже пишем ")".

В реальности даже и это описание не верно, потому что "CLR_(" является открывающей частью другого макроса, а потому сразу же вписывается раскрытие макроса CLR_. Т.е. тут всё делается как бы одновременно, но я просто описал, как происходит подстановка одного уровня

Вместо того, чтобы читать тонну литературы и описаний, попросту научись в компиляторе смотреть препроцессированный текст и экспериментируй на коротких примерах

На всякий случай ссылка http://www.cyberforum.ru/blogs/18334/blog100.html, но подозреваю, что тебе она без надобности, т.к. базовые сведения тебе вроде бы как и не нужны, а нужны тонкости
1
05.09.2016, 09:23
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.09.2016, 09:23

Идентификатор в #define
Требуется,чтобы за место чисел были их текстовые значения: например,вместо...

#define: макросы
Доброго времени суток. Веду разбирательство с директивами препроцессора и тут...

Массив, константы и #define
Всем доброго дня! Сразу к делу. Есть большое желание иметь массив длиной в...


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

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

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