Перейти к содержанию
    

Использование макросов с аргументами в Си

Это несерьезно.
Для меня это никак не определят серьёзность.

Просто компиляторы и уровни оптимизации бывают разные - зачем делать не единообразно?

Где есть инлайн - так, а где его нет - сяк... На мой вкус это несъедобно.

А что касается макросов, то уж что-что, то для GPIO - самое оно. Обеспечивается 100% унификация и переносимость между всеми платформами...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я обычно так делаю

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

по порядку:

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);
}

Изменено пользователем winipuh

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

: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);
}

подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом, вот этого я и добиваюсь

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но конструкция ... подразумевает вычисление или выбор по условию аргумента, а смысл макроса просто подстановка кода с уже готовым аргументом

Возможно Вы удивитесь, но на этапе компиляции не то-что инлайн — даже статические функции разворачиваются в конечное выражение не хуже макросов.

Пожалуйста:

// СИ:
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 и т.д. И в этом случае (при всем уважении) Ваши макросы — просто какая-то обертка, чтобы писать меньше букв кода. Преимущество, мягко говоря, весьма сомнительное...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А зачем у аргумента функции квалификатор const? Тут же параметр не по ссылке передается, а по значению. :blink:

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А так вот что имеем:

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 подставляем букву порта, второй параметр - номер пина. И ничего править не надо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#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:

 

Ок? :)

Макросы пишутся для того, чтобы обойти эту проблему... Ваши макросы (при все уважении) проблему эту не решают.

Теперь объясните — зачем же Вы их придумали?

 

 

 

 

Это стиль такой. Если не предполагается изменять аргумент внутри функции, то он фиксируется этим квалификатором.

Понял. :)

Изменено пользователем winipuh

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Имеем например: 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); // вкл.строба записи 
        ...
        ...
}

Единственное неудобство это описание пина двумя параметрами, но это все решаемо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Единственное неудобство это описание пина двумя параметрами, но это все решаемо.
"Мыши кололись, плакали, но продолжали жрать кактус"

 

Вы не до конца поняли намёк про макросы Аскольда Волкова.

Не поленитесь - погуглите да изучите.

Вот они.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...