уже не получится.
Развивая тему с препроцессором можно задавать номер ножки и ее порт в
одном определении, ведь Си-шный препроцессор работает не с
идентификаторами и не какими-то ни-было языковыми конструкциями, а
просто со строковыми литералами.
1
2
3
#define LCD_RS PORTA, 0 //define MCU pin connected to LCD RS
#define LCD_RW PORTB, 1 //define MCU pin connected to LCD R/W
#define LCD_E PORTB, 2 //define MCU pin connected to LCD E
Добавим к этому средства для манипуляции линией и получим так
называемые макросы Аскольда Волкова:
1
2
3
4
5
6
7
#define _setL(port,bit) do { port &= ~(1 << bit); } while(0)
#define _setH(port,bit) do { port |= (1 << bit); } while(0)
#define _clrL(port,bit) do { port |= (1 << bit); } while(0)
#define _clrH(port,bit) do { port &= ~(1 << bit); } while(0)
#define _bitL(port,bit) (!(port & (1 << bit)))
#define _bitH(port,bit) (port & (1 << bit))
#define _cpl(port,bit,val) do {port ^= (1 << bit); } while(0)
Этот подход, в отличии от предыдущих, уже можно сделать переносимым на
разные аппаратные платформы. Достаточно только определить эти макросы
для целевой платформы соответствующим образом. Однако, у нас по-
прежнему остались нерешенными некоторые проблемы. Во-первых, большой
размер и низкое быстродействие кода, ведь мы используем побитовый вывод
в порты. Даже если часть линий находятся в одном порту и идут подряд,
определить эту ситуацию с помощью макросов невозможно. И если,
например, размер кода окажется слишком большим, то уже написанную и
отлаженную библиотеку придется подгонять под конкретный проект, плодя
многочисленные ее версии и, возможно, внося ошибки.
Во-вторых, подключение нескольких однотипных устройств возможно
только путём дублирования кода. Опять-же результирующий размер
программы неоправданно увеличивается. А потом в две версии одного и
того-же кода вносятся изменения независимо друг от друга и каждая из них
начинает жить своей жизнью. Спасает здесь только относительно малый