demiurg_spb 0 2 декабря, 2013 Опубликовано 2 декабря, 2013 · Жалоба Это несерьезно.Для меня это никак не определят серьёзность. Просто компиляторы и уровни оптимизации бывают разные - зачем делать не единообразно? Где есть инлайн - так, а где его нет - сяк... На мой вкус это несъедобно. А что касается макросов, то уж что-что, то для GPIO - самое оно. Обеспечивается 100% унификация и переносимость между всеми платформами... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MaxiMuz 0 2 декабря, 2013 Опубликовано 2 декабря, 2013 (изменено) · Жалоба Я обычно так делаю #define LCD_WR1_pin 4 static inline void LCD_wr1(const char value) { GPIOB->BSRR = 1 << (LCD_WR1_pin + value?0:16); } Никаких макро и никаких неясных абстракций. Все конкретно. по порядку: 1) Во первых Keil 4.7 не дает инлайнить функции. 2) Не ясен смысла записи GPIOB->BSRR = 1 << (LCD_WR1_pin + value?0:16); нужно передать в порт фиксированное значение ( номер пина) 3) Нет возможности изменить порт вывода. И еще , что делает выражение value?0:16 и зачем ? я вообще не понял , возможно это мои пробелы в знаниях Си. Изменено 2 декабря, 2013 пользователем MaxiMuz Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
winipuh 0 2 декабря, 2013 Опубликовано 2 декабря, 2013 (изменено) · Жалоба по порядку: 1) Во первых Keil 4.7 не дает инлайнить функции. :blink: Да? Может у него что-то свое есть специфическое... типа __inline__ и т.п.? 2) Не ясен смысла записи GPIOB->BSRR = 1 << (LCD_WR1_pin + value?0:16); BSRR - управляет 16-тью пинками GPIO. Младшие 16 бит отвечают за установку пинов в "1", старшие 16 - за установку в "0". Можно одной записью одновременно установить и сбросить несколько разных пинов... А вышеприведенная (и, возможно, местами изъебисто написанная) конструкция буквально означает следующее: // n - номер GPIO-пина (от 0 до 15) #define SET_PIN(n) (0x0001 << (n)) #define CLR_PIN(n) (0x0100 << (n)) // ну или так — (0x0001 << ((n) + 16)) // какой-то конкретный пин #define LCD_wr1_pin 4 // Функция для установки/сброса какого-то конкретного пина static inline void LCD_wr1(const char value) { if (value) GPIOB->BSRR = SET_PIN(LCD_wr1_pin); else GPIOB->BSRR = CLR_PIN(LCD_wr1_pin); } Изменено 2 декабря, 2013 пользователем winipuh Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MaxiMuz 0 2 декабря, 2013 Опубликовано 2 декабря, 2013 · Жалоба :blink: Да? Может у него что-то свое есть специфическое... типа __inline__ и т.п.? вот этого я пока не знаю BSRR - управляет 16-тью пинками GPIO. Младшие 16 бит отвечают за установку пинов в "1", старшие 16 - за установку в "0". Можно одной записью одновременно установить и сбросить несколько разных пинов... все мне известно но конструкция static inline void LCD_wr1(const char value) { if (value) GPIOB->BSRR = SET_PIN(LCD_wr1_pin); else GPIOB->BSRR = CLR_PIN(LCD_wr1_pin); } подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом, вот этого я и добиваюсь Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
winipuh 0 2 декабря, 2013 Опубликовано 2 декабря, 2013 · Жалоба но конструкция ... подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом Возможно Вы удивитесь, но на этапе компиляции не то-что инлайн — даже статические функции разворачиваются в конечное выражение не хуже макросов. Пожалуйста: // СИ: extern void my_func(unsigned int x); static unsigned int my_value(unsigned int n) { return n ? 0x80 : 0x8000; } void call_func(n) { my_func(value(4)); // на самом деле все это вычисляется на этапе компиляции } // ASM: stmfd sp!, {r3, lr} mov r0, #128 // и в итоге получается my_func(0x80) ( 0x80 = 128 ) bl my_func ldmfd sp!, {r3, lr} bx lr .size call_func, .-call_func .ident "GCC: (Sourcery CodeBench Lite 2013.05-23) 4.7.3" Ну и наверное сочту своим долгом повторить еще раз то, что Вам уже говорил MrYuran Если абстрагироваться, то нужно и от пинов, и от портов, и от уровней. А так вот что имеем: RbitP(A,7); // вкл. на запись адреса A0=0 SbitP(A,5); // вкл.строба записи Вопрос: Что будете делать, если Вам потребуется перенести пины с GPIOA на GPIOB? Что будете делать, если Вам потребуется использовать для строба записи на Pin5, а напр. Pin8? Правильный вариант — это когда для этого нужно открыть некий h-файл и поправить там несколько строчек. В вашем случае - править придется все места, где вызываются макросы SbitP, RbitP и т.д. И в этом случае (при всем уважении) Ваши макросы — просто какая-то обертка, чтобы писать меньше букв кода. Преимущество, мягко говоря, весьма сомнительное... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 34 3 декабря, 2013 Опубликовано 3 декабря, 2013 · Жалоба А зачем у аргумента функции квалификатор const? Тут же параметр не по ссылке передается, а по значению. :blink: Это стиль такой. Если не предполагается изменять аргумент внутри функции, то он фиксируется этим квалификатором. Для безопасности. Например, передаётся в функцию количество чего-нибудь, внутри оно используется несколько раз в разных местах. Если не зафиксировать, то имеется ненулевая вероятность, что в какой-то точке значение будет изменено под текущие локальные нужды (такое обычно бывает при редактировании сорцов, которые давно не трогали - внимания на вникание во все нюансы не хватает) без учёта того, что ниже по коду оно используется в предположении, что должно быть неизменным. Это полезная практика - фиксировать ещё на этапе проектирования. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MaxiMuz 0 3 декабря, 2013 Опубликовано 3 декабря, 2013 · Жалоба А так вот что имеем: RbitP(A,7); // вкл. на запись адреса A0=0 SbitP(A,5); // вкл.строба записи Вопрос: Что будете делать, если Вам потребуется перенести пины с GPIOA на GPIOB? Что будете делать, если Вам потребуется использовать для строба записи на Pin5, а напр. Pin8? Правильный вариант — это когда для этого нужно открыть некий h-файл и поправить там несколько строчек. В вашем случае - править придется все места, где вызываются макросы SbitP, RbitP и т.д. #define SbitP(Port,Nbit) GPIO##Port->BSRR=GPIO_BSRR_BS##Nbit вместо Port подставляем букву порта, второй параметр - номер пина. И ничего править не надо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
winipuh 0 3 декабря, 2013 Опубликовано 3 декабря, 2013 (изменено) · Жалоба #define SbitP(Port,Nbit) GPIO##Port->BSRR=GPIO_BSRR_BS##Nbit вместо Port подставляем букву порта, второй параметр - номер пина. И ничего править не надо. Вы меня не поняли! :( Все бывает в первый раз: 1) Пришлось корректировать разводку — как следствие поменялись функции пинов GPIO... 2) Пришлось добавить новую модель изделия. Немного другая разводка (другие функции пинов). Дерево исходников общее. Собираем либо под одно железо, либо под другое... Имеем например: SbitP(A,5); // вкл.строба записи Допустим теперь строб записи не на GPIOA(Pin_5) а на GPIOB(Pin_12) ... Как будете править исходники? Еще хуже — если править их придется кому-то другому... :( Придется пройтись по сишным файлам и везде строчку SbitP(A,5) поменять на SbitP(B,12). ... Можно, но сложно и некрасиво... А собирать из одного дерева под разное железо - задача в Вашем случае вообще непосильная... :smile3046: Ок? :) Макросы пишутся для того, чтобы обойти эту проблему... Ваши макросы (при все уважении) проблему эту не решают. Теперь объясните — зачем же Вы их придумали? Это стиль такой. Если не предполагается изменять аргумент внутри функции, то он фиксируется этим квалификатором. Понял. :) Изменено 3 декабря, 2013 пользователем winipuh Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MaxiMuz 0 11 декабря, 2013 Опубликовано 11 декабря, 2013 · Жалоба Имеем например: SbitP(A,5); // вкл.строба записи Допустим теперь строб записи не на GPIOA(Pin_5) а на GPIOB(Pin_12) ... Как будете править исходники? Еще хуже — если править их придется кому-то другому... :( Придется пройтись по сишным файлам и везде строчку SbitP(A,5) поменять на SbitP(B,12). ... Можно, но сложно и некрасиво... А собирать из одного дерева под разное железо - задача в Вашем случае вообще непосильная... :smile3046: Ок? :) Макросы пишутся для того, чтобы обойти эту проблему... Ваши макросы (при все уважении) проблему эту не решают. Теперь объясните — зачем же Вы их придумали? Решение проблемы в моем случае - дефейнить название портов. gpio.h /****************** Macros Set/Clear Bit of Port ***************************/ #define SbitP(Port,Nbit) _SbitP(Port,Nbit) #define RbitP(Port,Nbit) _RbitP(Port,Nbit) #define _SbitP(Port,Nbit) GPIO##Port->BSRR=GPIO_BSRR_BS##Nbit #define _RbitP(Port,Nbit) GPIO##Port->BSRR=GPIO_BSRR_BR##Nbit #define SmbitP(Port,mask) GPIO##Port->BSRR=(mask) #define RmbitP(Port,mask) GPIO##Port->BSRR=(mask)<<16 main.c #define LCD_ctrlPort A // Порт управляющих сигналов #define LCD_dataPort A // Порт шины данных #define LCD_dataShift 1 // Смещение шины данных от начала порта #define LCD_A0 7 // Выбор: Адрес A0=L/ Данные A0=H #define LCD_WR1 5 #include "gpio.h" //описание макросов ввода/вывода .... .... void LCD_wrAdr (u8 Adr) { SmbitP(LCD_dataPort,((Adr&0x0f)<<LCD_dataShift)); // выставляем на шину адрес RbitP(LCD_dataPort,LCD_A0); // вкл. на запись адреса A0=0 SbitP(LCD_dataPort,LCD_WR); // вкл.строба записи ... ... } Единственное неудобство это описание пина двумя параметрами, но это все решаемо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 11 декабря, 2013 Опубликовано 11 декабря, 2013 · Жалоба Единственное неудобство это описание пина двумя параметрами, но это все решаемо."Мыши кололись, плакали, но продолжали жрать кактус" Вы не до конца поняли намёк про макросы Аскольда Волкова. Не поленитесь - погуглите да изучите. Вот они. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 11 декабря, 2013 Опубликовано 11 декабря, 2013 · Жалоба Не понимаю, зачем такие "муки творчества", если для установки или сброса бита в порте требуется всего-то (показано для STM32F2xx, но разница невелика): #define RSTO_ON() GPIOC->BSRRH = (uint16_t)(1<<0) //!< Выдать сброс (Low) #define RSTO_OFF() GPIOC->BSRRL = (uint16_t)(1<<0) //!< Убрать сброс (High) #define ANSYN_ON() GPIOD->BSRRH = (uint16_t)(1<<2) //!< ANSYN Low #define ANSYN_OFF() GPIOD->BSRRL = (uint16_t)(1<<2) //!< ANSYN High Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 11 декабря, 2013 Опубликовано 11 декабря, 2013 · Жалоба Не понимаю, зачем такие "муки творчества",Чтобы не определять *_ON() и *_OFF() для каждой лапы. А если захочется ввод/вывод попереключать - еще два макроса дописывать? А если читать - еще один? А если изменить состояние на противоположное - еще один? В такой простыне уже на пяти выводах запутаешься, а часто их больше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться