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

 
 
3 страниц V  < 1 2 3 >  
Closed TopicStart new topic
> отладка в Keil
Сергей Борщ
сообщение Sep 1 2018, 18:34
Сообщение #16


Гуру
******

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



QUOTE (Professor Chaos @ Sep 1 2018, 21:04) *
Любое битовое поле в регистре в общем случае записывается в два прохода:
сначала выставляются 1 в нужных позициях
затем 0
Можно наоборот, порядок не важен.
Кто вас научил такому ужасному ужасу, "библиотеки"? Что будет делать контроллер, получив 1 в нужных позициях и случайные предыдущие значения вместо нулей в остальных (или наоборот, не важно)? Я уже не говорю о лишней записи в регистр. Грамотный программист использует либо конструкцию Reg = (Reg & Mask1) | Mask2, либо ее же, разбитую на два выражения и временную переменную.
И еще - грамотный программист сложное выражение в #define обрамляет в do {} while(0)


--------------------
На любой вопрос даю любой ответ
"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
mihlit
сообщение Sep 2 2018, 02:30
Сообщение #17


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 7-04-18
Пользователь №: 103 011



Объяснюсь по поводу своего вопроса.
1. На просторах Интернета много раз встречал высказывания, что "магическое" число - это не есть хорошо.
2. ИМХО, работа через регистры более компактна и нагляднее чем применение библиотек.
3. Из п2. вытекает(для меня), что написание своих макросов и дефайнов не сокращает время долбания клавиатуры и не повышает читаемость кода.
Go to the top of the page
 
+Quote Post
mihlit
сообщение Sep 2 2018, 05:05
Сообщение #18


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 7-04-18
Пользователь №: 103 011



Задам еще вопрос по Keil. У меня версия 5.23 (32Кб). Иногда при запуске Keil, теряется какой-то заголовочный файл. Лечится перезагрузкой Keil, но чаще приходится перезагружать Win7. Не смертельно, но иногда задалбывает. Кто- нибудь сталкивался с подобным?
Go to the top of the page
 
+Quote Post
Professor Chaos
сообщение Sep 2 2018, 05:06
Сообщение #19


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 25-08-17
Пользователь №: 98 970



Цитата(Сергей Борщ @ Sep 1 2018, 21:34) *
Что будет делать контроллер, получив 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);
Приведите пример, если можете.
Go to the top of the page
 
+Quote Post
x893
сообщение Sep 2 2018, 05:17
Сообщение #20


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Это очень просто
https://www.google.ru/search?q=зачем+исполь...ile+в+%40define
и читаем первый ответ.
Если есть Яндекс Алиса - можно голосом задать вопрос

https://ru.stackoverflow.com/questions/6801...D1%8F-do-while0
Go to the top of the page
 
+Quote Post
Professor Chaos
сообщение Sep 2 2018, 05:51
Сообщение #21


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 25-08-17
Пользователь №: 98 970



Цитата(mihlit @ Sep 2 2018, 05:30) *
1. На просторах Интернета много раз встречал высказывания, что "магическое" число - это не есть хорошо.

Так и есть. Лучше давать таким константам осмысленные имена. Так и читается легче и вносить изменения в код проще.
Цитата
2. ИМХО, работа через регистры более компактна и нагляднее чем применение библиотек.

Компактна - да, возможно, в некоторых случаях. Но далеко не всегда и не везде. Что компактней: в некотором регистре установить какой-то бит в 1 (сбросить бит в 0) или вызвать функцию с 2-3 параметрами? В обоих случаях это будет одна строка кода.
Наглядна - нет. Если бы библиотеки делали код менее наглядным их бы не писали в принципе. А библиотеки как раз и пишутся для повышения наглядности. Они повышают уровень абстракции. Работая с регистрами вам надо знать не только "что делать", но и "как это делать" - какие битовые поля в каких регистрах в какие значения установить. Работая с библиотекой надо знать лишь "что делать". Вопрос "как это сделать" библиотечная функция взяла на себя. Она сама внутри своего тела оперирует регистрами, битами, их позициями в регистрах, сдвигами и масками битовых полей. Снаружи ничего этого не видно и знать не нужно.
Цитата
3. Из п 2. вытекает(для меня), что написание своих макросов и дефайнов не сокращает время долбания клавиатуры и не повышает читаемость кода.

Не сокращает и не повышает.
Но если надо сделать что-то, чего не умеют библиотечные функции, либо сделать то, что могут и они, но как-то по-другому - то для этого пишутся свои функции. Специализированные, под конкретные задачи.

Цитата(x893 @ Sep 2 2018, 08:17) *
Это очень просто

Точно, вспомнил - из-за точки с запятой.
Просто компилятор Кейла допускает конструкцию типа { }; и не ругаются на неё, связывая идущий после этого else с последним if. Так что забыл про этот неприятный момент, хотя и читал про это ранее (забыл уже где).
Go to the top of the page
 
+Quote Post
mihlit
сообщение Sep 2 2018, 06:02
Сообщение #22


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 7-04-18
Пользователь №: 103 011



Цитата
Работая с регистрами вам надо знать не только "что делать", но и "как это делать" - какие битовые поля в каких регистрах в какие значения установить. Работая с библиотекой надо знать лишь "что делать". Вопрос "как это сделать" библиотечная функция взяла на себя. Она сама внутри своего тела оперирует регистрами, битами, их позициями в регистрах, сдвигами и масками битовых полей. Снаружи ничего этого не видно и знать не нужно.

Не буду оспаривать очевидное.
Небольшой нюанс - я к МК пришел через проектирование электроники на логических элементах малой степени интеграции, поэтому у меня в крови - знать и понимать что и как я делаю. Чувствую себя не комфортно, если не понимаю, как это действие выполняется.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 2 2018, 06:07
Сообщение #23


Гуру
******

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



QUOTE (Professor Chaos @ Sep 2 2018, 08:06) *
Так лучше?
Да. Осталось избавиться от pos, перейдя от (val) << (pos) к (val) * ((msk) & -(msk)). Поскольку и val и msk - константы времени компиляци, замена сдвига на умножение не повлияет на размер и скорость результирующего кода, а в исходнике будет меньше вероятность использовать pos и msk от разных битовых полей.
QUOTE (Professor Chaos @ Sep 2 2018, 08:51) *
Точно, вспомнил - из-за точки с запятой.
Просто компилятор Кейла допускает конструкцию типа { }; и не ругаются на неё, связывая идущий после этого else с последним if.
Надеюсь, что тут вы ошибаетесь. Иначе это был бы компилятор "языка, похожего на Си".


--------------------
На любой вопрос даю любой ответ
"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
Arlleex
сообщение Sep 2 2018, 08:02
Сообщение #24


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(Сергей Борщ @ 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) *
Не буду оспаривать очевидное.
Небольшой нюанс - я к МК пришел через проектирование электроники на логических элементах малой степени интеграции, поэтому у меня в крови - знать и понимать что и как я делаю. Чувствую себя не комфортно, если не понимаю, как это действие выполняется.

Это хороший подход к делу!
Go to the top of the page
 
+Quote Post
Professor Chaos
сообщение Sep 2 2018, 08:17
Сообщение #25


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 25-08-17
Пользователь №: 98 970



Цитата(Сергей Борщ @ Sep 2 2018, 09:07) *
Надеюсь, что тут вы ошибаетесь. Иначе это был бы компилятор "языка, похожего на Си".

Да, ошибся. Проверил. Действительно, выдаёт ошибку.
Это он не ругается на ; после блока в конструкциях вида:
Код
operator1;
{  operator2;
   operator3;
};
operator4;

Код
while (SomeExpr1) {
  if (SomeExpr2) {
    operator1;
    operator2;
  };
}

хотя ; после } там не нужна.
Возможно, он воспринимает ; после } как пустой оператор, поэтому и не имеет ничего против.
Go to the top of the page
 
+Quote Post
mihlit
сообщение Sep 2 2018, 08:25
Сообщение #26


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 7-04-18
Пользователь №: 103 011



Цитата
Нужно больше информации. Скрин экрана, например, либо что конкретно пишет среда. У меня такой проблемы нет.

Дык в том то и дело, что стоит крест на, допустим, строчке
#include "stm32f4xx.h"
наводишь стрелку на крест - внизу экрана выводится - "фатальная ошибка: нет пути"
но Keil то работает, т.е можно запустить компиляцию - выдает 0 ошибок, отладка тоже запускается и работает.
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Sep 2 2018, 08:54
Сообщение #27


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(mihlit @ Sep 2 2018, 11:25) *
Дык в том то и дело, что стоит крест на, допустим, строчке
#include "stm32f4xx.h"
наводишь стрелку на крест - внизу экрана выводится - "фатальная ошибка: нет пути"
но Keil то работает, т.е можно запустить компиляцию - выдает 0 ошибок, отладка тоже запускается и работает.

Include paths прописаны в закладке C/C++ проекта?
У Keil есть такая болезнь, ставить крестики на нормальных строчках. Но не на stm32f4xx.h (у себя ни разу не видел).
Go to the top of the page
 
+Quote Post
mihlit
сообщение Sep 2 2018, 09:06
Сообщение #28


Участник
*

Группа: Участник
Сообщений: 34
Регистрация: 7-04-18
Пользователь №: 103 011



Цитата
Include paths прописаны в закладке C/C++ проекта?
У Keil есть такая болезнь, ставить крестики на нормальных строчках.

Ест-но. В основном h-файлы из SPL, юзеровских ни разу не видел, вот сегодня "stm32f4xx.h". Поначалу очень нервничал, потом ничего привык - а у него болячка такая оказывается.
Go to the top of the page
 
+Quote Post
Professor Chaos
сообщение Sep 2 2018, 12:48
Сообщение #29


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 25-08-17
Пользователь №: 98 970



С макросом оказалось всё немного сложнее.
При введении в него промежуточной переменной 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)
Go to the top of the page
 
+Quote Post
jcxz
сообщение Sep 2 2018, 14:20
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Professor Chaos @ Sep 2 2018, 15:48) *
// в позицию 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.gif
reg = ((reg) & ~(msk)) | ((val) << (pos) & (msk));
Либо так:
reg = ((reg) | (msk)) ^ (~(val) << (pos) & (msk));
и никаких промежуточных переменных....
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 16th April 2024 - 13:06
Рейтинг@Mail.ru


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