Сергей Борщ 117 1 сентября, 2018 Опубликовано 1 сентября, 2018 · Жалоба Любое битовое поле в регистре в общем случае записывается в два прохода: сначала выставляются 1 в нужных позициях затем 0 Можно наоборот, порядок не важен. Кто вас научил такому ужасному ужасу, "библиотеки"? Что будет делать контроллер, получив 1 в нужных позициях и случайные предыдущие значения вместо нулей в остальных (или наоборот, не важно)? Я уже не говорю о лишней записи в регистр. Грамотный программист использует либо конструкцию Reg = (Reg & Mask1) | Mask2, либо ее же, разбитую на два выражения и временную переменную. И еще - грамотный программист сложное выражение в #define обрамляет в do {} while(0) Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mihlit 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Объяснюсь по поводу своего вопроса. 1. На просторах Интернета много раз встречал высказывания, что "магическое" число - это не есть хорошо. 2. ИМХО, работа через регистры более компактна и нагляднее чем применение библиотек. 3. Из п2. вытекает(для меня), что написание своих макросов и дефайнов не сокращает время долбания клавиатуры и не повышает читаемость кода. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mihlit 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Задам еще вопрос по Keil. У меня версия 5.23 (32Кб). Иногда при запуске Keil, теряется какой-то заголовочный файл. Лечится перезагрузкой Keil, но чаще приходится перезагружать Win7. Не смертельно, но иногда задалбывает. Кто- нибудь сталкивался с подобным? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Что будет делать контроллер, получив 1 в нужных позициях и случайные предыдущие значения вместо нулей в остальных (или наоборот, не важно)? Я уже не говорю о лишней записи в регистр. Грамотный программист использует либо конструкцию Reg = (Reg & Mask1) | Mask2, либо ее же, разбитую на два выражения и временную переменную. Согласен с замечанием. Так лучше? // Макрос записи в регистр 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); И еще - грамотный программист сложное выражение в #define обрамляет в do {} while(0) А здесь - не могу представить себе пример кода, когда обрамляющие фигурные скобки (блок {} ) работают хуже (да просто не точно так же), как конструкция do {} while (0); Приведите пример, если можете. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 32 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Это очень просто https://www.google.ru/search?q=зачем+исполь...ile+в+%40define и читаем первый ответ. Если есть Яндекс Алиса - можно голосом задать вопрос https://ru.stackoverflow.com/questions/6801...D1%8F-do-while0 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба 1. На просторах Интернета много раз встречал высказывания, что "магическое" число - это не есть хорошо. Так и есть. Лучше давать таким константам осмысленные имена. Так и читается легче и вносить изменения в код проще. 2. ИМХО, работа через регистры более компактна и нагляднее чем применение библиотек. Компактна - да, возможно, в некоторых случаях. Но далеко не всегда и не везде. Что компактней: в некотором регистре установить какой-то бит в 1 (сбросить бит в 0) или вызвать функцию с 2-3 параметрами? В обоих случаях это будет одна строка кода. Наглядна - нет. Если бы библиотеки делали код менее наглядным их бы не писали в принципе. А библиотеки как раз и пишутся для повышения наглядности. Они повышают уровень абстракции. Работая с регистрами вам надо знать не только "что делать", но и "как это делать" - какие битовые поля в каких регистрах в какие значения установить. Работая с библиотекой надо знать лишь "что делать". Вопрос "как это сделать" библиотечная функция взяла на себя. Она сама внутри своего тела оперирует регистрами, битами, их позициями в регистрах, сдвигами и масками битовых полей. Снаружи ничего этого не видно и знать не нужно. 3. Из п 2. вытекает(для меня), что написание своих макросов и дефайнов не сокращает время долбания клавиатуры и не повышает читаемость кода. Не сокращает и не повышает. Но если надо сделать что-то, чего не умеют библиотечные функции, либо сделать то, что могут и они, но как-то по-другому - то для этого пишутся свои функции. Специализированные, под конкретные задачи. Это очень просто Точно, вспомнил - из-за точки с запятой. Просто компилятор Кейла допускает конструкцию типа { }; и не ругаются на неё, связывая идущий после этого else с последним if. Так что забыл про этот неприятный момент, хотя и читал про это ранее (забыл уже где). Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mihlit 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Работая с регистрами вам надо знать не только "что делать", но и "как это делать" - какие битовые поля в каких регистрах в какие значения установить. Работая с библиотекой надо знать лишь "что делать". Вопрос "как это сделать" библиотечная функция взяла на себя. Она сама внутри своего тела оперирует регистрами, битами, их позициями в регистрах, сдвигами и масками битовых полей. Снаружи ничего этого не видно и знать не нужно. Не буду оспаривать очевидное. Небольшой нюанс - я к МК пришел через проектирование электроники на логических элементах малой степени интеграции, поэтому у меня в крови - знать и понимать что и как я делаю. Чувствую себя не комфортно, если не понимаю, как это действие выполняется. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 117 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Так лучше?Да. Осталось избавиться от pos, перейдя от (val) << (pos) к (val) * ((msk) & -(msk)). Поскольку и val и msk - константы времени компиляци, замена сдвига на умножение не повлияет на размер и скорость результирующего кода, а в исходнике будет меньше вероятность использовать pos и msk от разных битовых полей. Точно, вспомнил - из-за точки с запятой. Просто компилятор Кейла допускает конструкцию типа { }; и не ругаются на неё, связывая идущий после этого else с последним if. Надеюсь, что тут вы ошибаетесь. Иначе это был бы компилятор "языка, похожего на Си". Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 129 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Кто вас научил такому ужасному ужасу, "библиотеки"? Что будет делать контроллер, получив 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 Объяснюсь по поводу своего вопроса. 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? Задам еще вопрос по Keil. У меня версия 5.23 (32Кб). Иногда при запуске Keil, теряется какой-то заголовочный файл. Лечится перезагрузкой Keil, но чаще приходится перезагружать Win7. Не смертельно, но иногда задалбывает. Кто- нибудь сталкивался с подобным? Нужно больше информации. Скрин экрана, например, либо что конкретно пишет среда. У меня такой проблемы нет. Согласен с замечанием. Так лучше? // Макрос записи в регистр 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) не нужна. Не буду оспаривать очевидное. Небольшой нюанс - я к МК пришел через проектирование электроники на логических элементах малой степени интеграции, поэтому у меня в крови - знать и понимать что и как я делаю. Чувствую себя не комфортно, если не понимаю, как это действие выполняется. Это хороший подход к делу! Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Надеюсь, что тут вы ошибаетесь. Иначе это был бы компилятор "языка, похожего на Си". Да, ошибся. Проверил. Действительно, выдаёт ошибку. Это он не ругается на ; после блока в конструкциях вида: operator1; { operator2; operator3; }; operator4; while (SomeExpr1) { if (SomeExpr2) { operator1; operator2; }; } хотя ; после } там не нужна. Возможно, он воспринимает ; после } как пустой оператор, поэтому и не имеет ничего против. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mihlit 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Нужно больше информации. Скрин экрана, например, либо что конкретно пишет среда. У меня такой проблемы нет. Дык в том то и дело, что стоит крест на, допустим, строчке #include "stm32f4xx.h" наводишь стрелку на крест - внизу экрана выводится - "фатальная ошибка: нет пути" но Keil то работает, т.е можно запустить компиляцию - выдает 0 ошибок, отладка тоже запускается и работает. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 129 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Дык в том то и дело, что стоит крест на, допустим, строчке #include "stm32f4xx.h" наводишь стрелку на крест - внизу экрана выводится - "фатальная ошибка: нет пути" но Keil то работает, т.е можно запустить компиляцию - выдает 0 ошибок, отладка тоже запускается и работает. Include paths прописаны в закладке C/C++ проекта? У Keil есть такая болезнь, ставить крестики на нормальных строчках. Но не на stm32f4xx.h (у себя ни разу не видел). Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mihlit 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба Include paths прописаны в закладке C/C++ проекта? У Keil есть такая болезнь, ставить крестики на нормальных строчках. Ест-но. В основном h-файлы из SPL, юзеровских ни разу не видел, вот сегодня "stm32f4xx.h". Поначалу очень нервничал, потом ничего привык - а у него болячка такая оказывается. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба С макросом оказалось всё немного сложнее. При введении в него промежуточной переменной tmp появилась необходимость указывать её тип. Он должен совпадать с типом reg. А т.к. он в общем случае разный и заранее неизвестный, то придётся его вводить одним из параметров макроса. Как-то так // Макрос записи в регистр reg битовой последовательности val // в позицию pos (по младшему разряду), msk - маска битового поля #define TuneBitField(typename,reg,val,pos,msk) \ do { \ typename tmp=reg; \ tmp |= (((val) << (pos))&(msk)); \ tmp &= (((val) << (pos))|~(msk)); \ reg=tmp; \ } while (0) В С++ этот макрос можно (а скорее нужно) переоформить в виде шаблонной подставляемой (inline) функции, где параметром шаблона как раз и будет имя типа регистра reg, а аргументом функции будет ссылка на регистр, чтобы его содержимое можно было изменить. Второй вариант выхода из ситуации (для Си без плюсов) - переписать макрос без использования промежуточной переменной, приведя его к виду: do {reg=(reg&msk1)|msk2;} while (0) // Макрос записи в регистр reg битовой последовательности val // в позицию pos (по младшему разряду), msk - маска битового поля #define TuneBitField(reg,val,pos,msk) \ do { \ reg = ((reg)&(((val) << (pos)))|~(msk))|(((val) << (pos))&(msk)); \ } while (0) Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 172 2 сентября, 2018 Опубликовано 2 сентября, 2018 · Жалоба // в позицию pos (по младшему разряду), msk - маска битового поля #define TuneBitField(typename,reg,val,pos,msk) \ do { \ typename tmp=reg; \ tmp |= (((val) << (pos))&(msk)); \ tmp &= (((val) << (pos))|~(msk)); \ reg=tmp; \ } while (0)[/code] Это-ж как так надо запутать простейшее выражение?? : Пользуйтесь: :rolleyes: reg = ((reg) & ~(msk)) | ((val) << (pos) & (msk)); Либо так: reg = ((reg) | (msk)) ^ (~(val) << (pos) & (msk)); и никаких промежуточных переменных.... Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться