Цитата(Сергей Борщ @ Sep 1 2018, 21:34)
Кто вас научил такому ужасному ужасу, "библиотеки"? Что будет делать контроллер, получив 1 в нужных позициях и случайные предыдущие значения вместо нулей в остальных (или наоборот, не важно)? Я уже не говорю о лишней записи в регистр. Грамотный программист использует либо конструкцию Reg = (Reg & Mask1) | Mask2, либо ее же, разбитую на два выражения и временную переменную.
И еще - грамотный программист сложное выражение в #define обрамляет в do {} while(0)
Добавлю только, что бывают еще регистры, чувствительные на операции чтения или записи. И двойная запись или двойное чтение может повлиять на работу периферии, к которой этот регистр относится.
Для
mihlit:
1. Запись нового значения в регистр
Код
REG = value; // запишет в регистр REG значение value
2. Установка некоторых бит в регистре, не затрагивая значений остальных бит
Код
REG |= value; // установит в REG биты в 1, установленные в двоичном представлении value
3. Сброс некоторых бит в регистре, не затрагивая значений остальных бит
Код
REG &= ~value; // сбросит в REG биты в 0, установленные в двоичном представлении value
4. Одновременные действия пунктов 2 и 3 (было уже озвучено выше)
Код
REG = (REG & Mask1) | Mask2; // сбросит нужные биты по маске Mask1 (там, где у нее 0 в битах) и установит биты по маске Mask2
Цитата(mihlit @ Sep 2 2018, 05:30)
Объяснюсь по поводу своего вопроса.
1. На просторах Интернета много раз встречал высказывания, что "магическое" число - это не есть хорошо.
2. ИМХО, работа через регистры более компактна и нагляднее чем применение библиотек.
3. Из п2. вытекает(для меня), что написание своих макросов и дефайнов не сокращает время долбания клавиатуры и не повышает читаемость кода.
1. Да, так и есть. Я, например, осмысленные числа, которые еще тем более могут корректироваться в проекте в процессе отладки, заменяю на именованные #define. Пример
Код
#define HW_EEPROM_I2C_ADDRESS 0xA0
#define HW_EXCHANGE_I2C_ADDRESS_OWN 0x12
#define HW_EXCHANGE_I2C_ADDRESS_ABONENT 0x34
В некоторых местах, например, я прибегаю к явным числам, например
Код
if(xSemaphoreTake(MeasureSemaphoreHandle, 50) == pdTRUE) // жду семафор в течение 50мс
В Вашем случае AFRH15 - это 4 старших бита 32-битного регистра AFRH (GPIOx->AFR[1]).
Теперь можно написать что-то вроде
Код
#define AFRH_POS_0 0
...
#define AFRH_POS_15 28
#define AFRH_REG_WRITE(GPIOX, POSITION, VALUE) GPIOX->AFR[1] |= VALUE << POSITION
...
...
...
(в коде)
AFRH_REG_WRITE(GPIOA, AFRH_POS_15, 5);
Здесь устанавливаются нужные биты, заданные числом (5 в данном случае), в позициях битового поля AFRH15 регистра AFRH.
Естественно, можно заморочиться и написать еще более удобнее, но для начинающего менее понятно синтаксически.
2. Не всегда. Меня, например, в некоторых приложениях полностью устраивает библиотека настройки, например, тех же GPIO. Я их настроил, а вот уже дальше - в основном работа через регистры. В общем-то, разницы нет. Можно и через регистры написать свою компактную библиотеку, это не возбраняется.
3. Заблуждение. По мере написания проекта Вы начнете понимать, что Вы полностью этот проект контролируете и разбираетесь в нем. Поверьте, в этом случае, если Вы будете использовать магические числа, будет только хуже. Основное правило - зачем исправлять одну и ту же настройку (например, размер приемного буфера какого-либо интерфейса) в разных местах проекта, если его достаточно поправить в одном определении #define?
Цитата(mihlit @ Sep 2 2018, 08:05)
Задам еще вопрос по Keil. У меня версия 5.23 (32Кб). Иногда при запуске Keil, теряется какой-то заголовочный файл. Лечится перезагрузкой Keil, но чаще приходится перезагружать Win7. Не смертельно, но иногда задалбывает. Кто- нибудь сталкивался с подобным?
Нужно больше информации. Скрин экрана, например, либо что конкретно пишет среда. У меня такой проблемы нет.
Цитата(Professor Chaos @ Sep 2 2018, 08:06)
Согласен с замечанием.
Так лучше?
Код
// Макрос записи в регистр reg битовой последовательности val в позицию pos (по младшему разряду)
// msk - маска битового поля
#define TuneBitField(reg,val,pos,msk) \
do { \
tmp=reg; \
(tmp) |= (((val) << (pos))&(msk)); \
(tmp) &= (((val) << (pos))|~(msk)); \
reg=tmp; \
} while (0);
Точка с запятой после while(0) не нужна.
Цитата(mihlit @ Sep 2 2018, 09:02)
Не буду оспаривать очевидное.
Небольшой нюанс - я к МК пришел через проектирование электроники на логических элементах малой степени интеграции, поэтому у меня в крови - знать и понимать что и как я делаю. Чувствую себя не комфортно, если не понимаю, как это действие выполняется.
Это хороший подход к делу!