реклама на сайте
подробности

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
> Использование макросов с аргументами в Си
demiurg_spb
сообщение Dec 2 2013, 11:53
Сообщение #16


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(_Pasha @ Dec 2 2013, 10:29) *
Это несерьезно.
Для меня это никак не определят серьёзность.
Просто компиляторы и уровни оптимизации бывают разные - зачем делать не единообразно?
Где есть инлайн - так, а где его нет - сяк... На мой вкус это несъедобно.
А что касается макросов, то уж что-что, то для GPIO - самое оно. Обеспечивается 100% унификация и переносимость между всеми платформами...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Dec 2 2013, 12:14
Сообщение #17


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(_Pasha @ Nov 29 2013, 21:19) *
Я обычно так делаю
Код
#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 и зачем ? я вообще не понял , возможно это мои пробелы в знаниях Си.

Сообщение отредактировал MaxiMuz - Dec 2 2013, 12:10
Go to the top of the page
 
+Quote Post
winipuh
сообщение Dec 2 2013, 12:34
Сообщение #18


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 31-10-12
Пользователь №: 74 189



Цитата(MaxiMuz @ Dec 2 2013, 16:14) *
по порядку:
1) Во первых Keil 4.7 не дает инлайнить функции.

blink.gif Да? Может у него что-то свое есть специфическое... типа __inline__ и т.п.?

Цитата(MaxiMuz @ Dec 2 2013, 16:14) *
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);
}


Сообщение отредактировал winipuh - Dec 2 2013, 12:35
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Dec 2 2013, 19:09
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(winipuh @ Dec 2 2013, 15:34) *
blink.gif Да? Может у него что-то свое есть специфическое... типа __inline__ и т.п.?

вот этого я пока не знаю


Цитата(winipuh @ Dec 2 2013, 15:34) *
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);
}
подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом, вот этого я и добиваюсь
Go to the top of the page
 
+Quote Post
winipuh
сообщение Dec 2 2013, 20:00
Сообщение #20


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 31-10-12
Пользователь №: 74 189



Цитата(MaxiMuz @ Dec 2 2013, 23:09) *
но конструкция ... подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом

Возможно Вы удивитесь, но на этапе компиляции не то-что инлайн — даже статические функции разворачиваются в конечное выражение не хуже макросов.
Пожалуйста:
Код
// СИ:
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); // вкл.строба записи

Вопрос:
  1. Что будете делать, если Вам потребуется перенести пины с GPIOA на GPIOB?
  2. Что будете делать, если Вам потребуется использовать для строба записи на Pin5, а напр. Pin8?

Правильный вариант — это когда для этого нужно открыть некий h-файл и поправить там несколько строчек.
В вашем случае - править придется все места, где вызываются макросы SbitP, RbitP и т.д. И в этом случае (при всем уважении) Ваши макросы — просто какая-то обертка, чтобы писать меньше букв кода. Преимущество, мягко говоря, весьма сомнительное...
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 3 2013, 04:24
Сообщение #21


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



QUOTE (winipuh @ Dec 1 2013, 22:37) *
А зачем у аргумента функции квалификатор const? Тут же параметр не по ссылке передается, а по значению. blink.gif

Это стиль такой. Если не предполагается изменять аргумент внутри функции, то он фиксируется этим квалификатором. Для безопасности. Например, передаётся в функцию количество чего-нибудь, внутри оно используется несколько раз в разных местах. Если не зафиксировать, то имеется ненулевая вероятность, что в какой-то точке значение будет изменено под текущие локальные нужды (такое обычно бывает при редактировании сорцов, которые давно не трогали - внимания на вникание во все нюансы не хватает) без учёта того, что ниже по коду оно используется в предположении, что должно быть неизменным. Это полезная практика - фиксировать ещё на этапе проектирования.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Dec 3 2013, 04:30
Сообщение #22


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(winipuh @ Dec 2 2013, 23:00) *
А так вот что имеем:
RbitP(A,7); // вкл. на запись адреса A0=0
SbitP(A,5); // вкл.строба записи

Вопрос:
  1. Что будете делать, если Вам потребуется перенести пины с GPIOA на GPIOB?
  2. Что будете делать, если Вам потребуется использовать для строба записи на Pin5, а напр. Pin8?

Правильный вариант — это когда для этого нужно открыть некий h-файл и поправить там несколько строчек.
В вашем случае - править придется все места, где вызываются макросы SbitP, RbitP и т.д.

Код
#define SbitP(Port,Nbit)    GPIO##Port->BSRR=GPIO_BSRR_BS##Nbit
вместо Port подставляем букву порта, второй параметр - номер пина. И ничего править не надо.
Go to the top of the page
 
+Quote Post
winipuh
сообщение Dec 3 2013, 12:23
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 31-10-12
Пользователь №: 74 189



Цитата(MaxiMuz @ Dec 3 2013, 08:30) *
Код
#define SbitP(Port,Nbit)    GPIO##Port->BSRR=GPIO_BSRR_BS##Nbit
вместо Port подставляем букву порта, второй параметр - номер пина. И ничего править не надо.

Вы меня не поняли! sad.gif

Все бывает в первый раз:
1) Пришлось корректировать разводку — как следствие поменялись функции пинов GPIO...
2) Пришлось добавить новую модель изделия. Немного другая разводка (другие функции пинов). Дерево исходников общее. Собираем либо под одно железо, либо под другое...

Имеем например: SbitP(A,5); // вкл.строба записи
Допустим теперь строб записи не на GPIOA(Pin_5) а на GPIOB(Pin_12) ... Как будете править исходники? Еще хуже — если править их придется кому-то другому... sad.gif
Придется пройтись по сишным файлам и везде строчку SbitP(A,5) поменять на SbitP(B,12). ... Можно, но сложно и некрасиво... А собирать из одного дерева под разное железо - задача в Вашем случае вообще непосильная... smile3046.gif

Ок? sm.gif
Макросы пишутся для того, чтобы обойти эту проблему... Ваши макросы (при все уважении) проблему эту не решают.
Теперь объясните — зачем же Вы их придумали?




Цитата(dxp @ Dec 3 2013, 08:24) *
Это стиль такой. Если не предполагается изменять аргумент внутри функции, то он фиксируется этим квалификатором.

Понял. sm.gif

Сообщение отредактировал winipuh - Dec 3 2013, 12:23
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Dec 11 2013, 07:36
Сообщение #24


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(winipuh @ Dec 3 2013, 15:23) *
Имеем например: SbitP(A,5); // вкл.строба записи
Допустим теперь строб записи не на GPIOA(Pin_5) а на GPIOB(Pin_12) ... Как будете править исходники? Еще хуже — если править их придется кому-то другому... sad.gif
Придется пройтись по сишным файлам и везде строчку SbitP(A,5) поменять на SbitP(B,12). ... Можно, но сложно и некрасиво... А собирать из одного дерева под разное железо - задача в Вашем случае вообще непосильная... smile3046.gif

Ок? sm.gif
Макросы пишутся для того, чтобы обойти эту проблему... Ваши макросы (при все уважении) проблему эту не решают.
Теперь объясните — зачем же Вы их придумали?

Решение проблемы в моем случае - дефейнить название портов.
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); // вкл.строба записи
        ...
        ...
}

Единственное неудобство это описание пина двумя параметрами, но это все решаемо.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 11 2013, 08:02
Сообщение #25


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(MaxiMuz @ Dec 11 2013, 09:36) *
Единственное неудобство это описание пина двумя параметрами, но это все решаемо.
"Мыши кололись, плакали, но продолжали жрать кактус"

Цитата(demiurg_spb @ Nov 29 2013, 14:52) *
Вы не до конца поняли намёк про макросы Аскольда Волкова.
Не поленитесь - погуглите да изучите.

Вот они.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ViKo
сообщение Dec 11 2013, 08:23
Сообщение #26


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Не понимаю, зачем такие "муки творчества", если для установки или сброса бита в порте требуется всего-то (показано для 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

Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 11 2013, 09:12
Сообщение #27


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ViKo @ Dec 11 2013, 10:23) *
Не понимаю, зачем такие "муки творчества",
Чтобы не определять *_ON() и *_OFF() для каждой лапы. А если захочется ввод/вывод попереключать - еще два макроса дописывать? А если читать - еще один? А если изменить состояние на противоположное - еще один? В такой простыне уже на пяти выводах запутаешься, а часто их больше.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post

2 страниц V  < 1 2
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 15:46
Рейтинг@Mail.ru


Страница сгенерированна за 0.01483 секунд с 7
ELECTRONIX ©2004-2016