Сб апр 22, 2017 08:45:00
// вспомогательный макрос конкатенации макросов
#define _CONCAT_(x,y) x ## y
/// макрос конкатенации основной
#define CONCAT(y,x) _CONCAT_(y,x)
#define DDR(x) CONCAT(DDR,x)
#define PORT(x) CONCAT(PORT,x)
#define PIN(x) CONCAT(PIN,x)
/// макрос для определения функции-инициализатора (вызывается автоматически в секции .inix)
#define INIT(x) static void __attribute__((naked, used, section(".init" #x))) CONCAT(_init_, __COUNTER__) (void)
/// то же самое для завершающих функций
#define DONE(x) static void __attribute__((naked, used, section(".fini" #x))) CONCAT(_fini_, __COUNTER__) (void)
/// это если лень писать - самая ранняя инициализация
#define AUTOINIT() INIT(2)
/// макрос для определения компактной версии функции main()
#define MAIN() int __attribute__((OS_main)) main(void)
/// неинициализируемые переменные
#define NOINIT __attribute__((section(".noinit")))
INIT(7){
DDR(PORT_IO) |= _BV(PIN_IO);
}
#define PORT_IO D
#define PIN_IO 2
Сб апр 22, 2017 09:32:30
Сб апр 22, 2017 11:15:53
ARV писал(а):Я часто делаю проекты из кучи модулей. И многие из них работают с периферией. И периферию эту надо настраивать.
Как принято делать? в каждом таком модуле создают функцию init_xxx(), которую затем вызывают из main.
Как делаю я? эту самую функцию init_xxx() я помещаю в секцию .init7 и она вызывается сама! А в main о периферии я вообще не забочусь - все уже подготовлено само!
Какие плюсы я получаю?
Во-первых, код main становится лаконичным и красивым, в нем именно то, что и должно быть: ГЛАВНАЯ работа. Надо лампочками мигать - они мигают, надо файлы читать - они читаются... а вякая ерунда вроде портов и регистров скрыта в модулях.
И еще одно. Задавая разные номера для макроса INIT, вы можете управлять порядком вызова инициализации. Разумеется, что код в INIT(7) будет выполнен раньше, чем INIT(8). Просто помнить номера инициализаций в нескольких модулях сложновато. Я завел себе правило: если мне надо просто проинициализировать модуль, я использую секцию 7. Если надо гарантировать превентивность инициализации - 6. Если надо гарантировать "запоздалость" - 9. Иных вариантов стараюсь избегать.
void init()
{
init_xxx();
init_yyy();
init_zzz(9600);
}
void main()
{
init();
}
// module xxx
INIT(6) {
init_xxx();
}
// module yyy
INIT(7) {
init_yyy();
}
// module zzz
INIT(9) {
init_zzz(9600);
}
void main()
{
}
Сб апр 22, 2017 12:35:41
void init_xxx(void){
// some code
}
INIT(7){
init_xxx();
}
INIT(7){
// some code
}
Ну, раз интересно, вот еще несколько идей, как и обещал, про трассировку.Rtmip писал(а):Мне интересно, продолжайте, пожалуйста
#if defined(__DEBUG__)
void debuf_func(void);
#else
#define debug_func()
#endif
#define log_i(x) printf_P(PSTR("\nLOG> " __FILE__ "\%s:%04d " # x "=%d\n"), __FUNCTION__, __LINE__, x)
013: void func(void){
014: int test_var = 12;
015: log_i(test_var);
016: // какой-то код
017:}
Сб апр 22, 2017 12:45:24
ARV писал(а):да, именно так и выходит.
Сб апр 22, 2017 12:53:22
Сб апр 22, 2017 15:40:57
ARV писал(а):Все преимущества я описал.
Например, вы сделали модуль для работы с выводом "в консоль", т.е. USART. Какие параметры вы собрались передавать в функцию инициализации? Скорость? И собираетесь ее менять по ходу исполнения программы? Не лучше ли задать константу скорости в заголовочнике того модуля, и забыть вообще про него? Зачем вам нужен порядок инициализации, если к моменту начала main уже все инициализирвоано - хоть USART, хоть ЖКИ, хоть черт в ступе?
У меня вот есть давно сделанный модуль с названием usart_io.c с заголовочником usart_io.h. В заголовочнике прописана скорость 57600, и за последние 4 года я ни разу ее не менял.
если мне надо выводить в консоль, я просто кидаю эти файлы в папку проекта, и где захочется, пишу printf - все, усилия кончились на этом. Разве что попадется МК, в котором более 1 USART - тогда приходится имена регистров подправлять, да и то из-за моей же лени - ведь можно при помощи условной компиляции предусмотреть и такой вариант...
ARV писал(а):Вот так, просто и незатейливо, можно организовать трассировку всего, чего угодно. Разумеется, все эти фичи можно использовать и для других целей.
Сб апр 22, 2017 19:05:06
во-первых, номера секций менять можно не у меня, а у GCC я лишь не лишаю никого этой возможности своими макросами.Reflector писал(а):Во-первых, порядок инициализации может иметь значение, наверно именно потому у тебя и можно менять номера секций чтобы гарантировать превентивность или "запоздалость"...
переносимость модуля не от Си зависит, а от связи модуля с аппаратной частью. для AVR редко когда можно добиться полной абстракции модуля от аппаратуры, потому и переносимость модулей между проектами не высокая.Reflector писал(а):В идеале любой модуль должен переноситься между проектами без изменений, в чистом С этого добиться сложнее, но по крайней мере можно к этому стремиться
Сб апр 22, 2017 21:56:20
ARV писал(а):во-вторых, инициализация и управление по ходу пьесы - это разные вещи. инициализация задает состояние по умолчанию, для которого не требуются параметры. если хочется, по умолчанию можно настроить сразу так, чтобы работало, как хочется. а потом, если хочется, можно перенастраивать.
в-третьих, если вы пишите на С++, это еще не доказательство, что вы выбрали самый лучший подход.
кстати, у вас в С++ конструкторы статических экземпляров классов GCC сам помещает в секцию .init6 по-моему (могу ошибаться, т.к. не помню наизусть) - это вас не смущает? у меня то же самое, но для Си (если считать модуль эквивалентом экземпляра класса)
Reflector писал(а):переносимость модуля не от Си зависит, а от связи модуля с аппаратной частью. для AVR редко когда можно добиться полной абстракции модуля от аппаратуры, потому и переносимость модулей между проектами не высокая.
Вс апр 23, 2017 10:57:12
вам крупно не повезло, вам придется не применять мою методику. чего вы так всполошились - ума не приложу.Reflector писал(а): Как это можно нормально разрулить на С, да еще и с применением твоей методики я даже не представляю
ARV писал(а):менее интересен этот опыт тем, кто любит и активно использует С++
Вс апр 23, 2017 11:14:17
ARV писал(а):кстати, вроде как для вас я писал:ARV писал(а):менее интересен этот опыт тем, кто любит и активно использует С++
Вс апр 23, 2017 12:31:51
Reflector писал(а):применительно к мк такой подход плох
Сб июн 03, 2017 10:24:41
Пн июн 05, 2017 12:54:05
да, это было именно ради прикола, практической ценности не имеет.YS писал(а):Когда-то я ради прикола передавал аргументы в main(), используя похожие методы.
так и я тоже стремлюсь к этому... и при вышеописанном методе руководствовался принципом "если модуль не работает - ищи проблему в модуле". то есть если что-то не заработало - не надо ковыряться по всем файлам, выискивая, где оно инициализировалось, где стартовало, где использовалось - открывай файл модуля и думай...YS писал(а):Лично я при написании программ стараюсь по возможности исповедовать "принцип наименьшего удивления"
Пн июн 19, 2017 18:59:03
Вт июн 20, 2017 07:34:38
знаете, мне кажется, бытующее мнение о том, что легко делать кроссплатформенные (хотя правильнее - кросскомпилятоные) программы на Си - это завуалированный обман.arkhnchul писал(а):но сие в общем не есть хороший подход
Вт июн 20, 2017 10:40:07
Вт июн 20, 2017 10:43:08
Вт июн 20, 2017 11:09:46
Вт июн 20, 2017 12:07:42