Обсуждаем контроллеры компании Atmel.
Ответить

Правильная инициализация таймера

Ср янв 22, 2020 01:43:49

Как правильно инициализировать с | или без?
В некоторых примерах можно встретить такое:

TCCR0 = 0;
TCCR0 = (0<<COM01)|(1<<COM00)|(0<<WGM01)|(0<<WGM00);
TCNT0 = 0;
OCR0 = 0;
TIMSK = 0;
TCCR0 |= (1<<CS02)|(0<<CS01)|(1<<CS00);

Re: Правильная инициализация таймера

Ср янв 22, 2020 05:49:19

при начальной настройке - однозначно без |
т.к. во первых через команду с палкой может просочиться мусор, а во вторых команда с палкой занимает во флеше больше места и дольше выполняется...
дальше в коде, когда регистр уже настроен, можно и так, и так в зависимости от ситуации
если точно знаешь какими должны быть все байты регистра - выгодней написать без |
если не знаешь (например, скорость таймера настроилась в процессе работы, или модикация регистра происходит в подпрограмме и может быть вызвана при разных состояниях таймера) то без "|" и/или "&" не обойтись.

Добавлено after 19 minutes 28 seconds:
или. в твоем примере палка была применена только для того, чтобы заново не набивать названия регистров таймера... (возможно, оптимизатор это поймёт и, дописав недостающие биты, напишет эту команду без палки)
1 команда - обнуление регистра (имхо лишняя, т.к. 2 команда его всёравно установит в точно определенное состояние, что бы в нём ни находилось)
2- настройка режима таймера
3-5 - очистка регистров таймера
6- запуск таймера (изменяются только биты, отвечающие за прескалер)

Re: Правильная инициализация таймера

Ср янв 22, 2020 07:44:15

(возможно, оптимизатор это поймёт и, дописав недостающие биты, напишет эту команду без палки)
Всё верно пишешь, кроме вот этой фразы. Регистры это volatile сущности, компилятор не имеет права ничего менять в доступе к ним.

Re: Правильная инициализация таймера

Ср янв 22, 2020 07:48:27

Первоначальная инициализация таймера (при включении питания, после сброса) непосредственное задание значения. То есть, TCCR0A = (1<<CS0); Регистры, общие для таймеров (TIMSK) - первые команды задание значений, последующие - |.
Совет, сначала задать режим работы таймера, затем разрешать флаги прерываний. Этот совет касается всего, где есть прерывания. В противном случае, если сначала разрешить прерывание, может выполниться условие и установится флаг прерывания и сработает соответствующее прерывание.

Re: Правильная инициализация таймера

Ср янв 22, 2020 09:54:33

Регистры это volatile сущности, компилятор не имеет права ничего менять в доступе к ним.
наверно... но при перенастройке собаки или делителя тактовой оптимизацию отключать всёравно приходится, а иначе он таки забывает о том что это сущности...

Re: Правильная инициализация таймера

Ср янв 22, 2020 11:42:07

В случае с ассемблером предварительное преобразование делает препроцессор, а в команду подставляется только готовая величина.
Для Си...
Возможно удобнее выполнить предварительно определение командного байта как константы, а затем уже ту константу подставлять в текст программы.
Допустим
const unsigned char com_word = (0<<COM01)|(1<<COM00)|(0<<WGM01)|(0<<WGM00);
(хотя... сдвиг нуля лишен смысла, поскольку достаточно 1<<COM00, чтобы остальные биты результата были сброшены в 0...)
а затем уже
TCCR0 = com_word;
:roll:

Re: Правильная инициализация таймера

Ср янв 22, 2020 11:54:14

С тоже пересчитывает сам... (даже не представляю насколько надо укуриться, чтоб это на камень возложить...)
тут как удобней программисту... если эта одинаковая настройка мелькает несколько раз или есть вероятность менять её перед компиляцией, то удобней её вынести из кода в начало (объявить константой или задефайнить), а если нет, то ... просто оставить где была...:)

Re: Правильная инициализация таймера

Ср янв 22, 2020 22:36:06

Правильно ли я понимаю:

TCCR0 = (0<<COM01)|(1<<COM00)|(0<<WGM01)|(0<<WGM00); - это непосредственная запись в регистр (значения)?
TCCR0 = 0b00010000 (16)
----------
TCCR0 |= (1<<CS02)|(0<<CS01)|(1<<CS00); - это наложение битовой маски(через битовое "или")?
TCCR0 = 0b00010000 - значение регистра установленное выше
|
0b00000101 - накладываем маску ((1<<CS02)|(0<<CS01)|(1<<CS00))
=
0b00010101 - результат

Во второй настройке таймера если не будем использовать маску то COM00 сбросится в 0?


Справедливо ли это для других регистров, например для АЦП?
В настройках АЦП такого вроде не встречал, всегда используется |.

Re: Правильная инициализация таймера

Чт янв 23, 2020 05:48:16

| — прбитовое или, где бы ни применялось.
|= (а также -=, +=, %=, /=, *=, &=... и т.д.) это просто сокращенная запись..
твоё TCCR0 |= (1<<CS02)|(0<<CS01)|(1<<CS00);
означает TCCR0 = (TCCR0)|(1<<CS02)|(0<<CS01)|(1<<CS00);
и выполняется в МК за 3 команды:
R16 <— TCCR0;
R16 <— R16|(0b00000101); значение в скобках вычисляется ещё при компиляции и в мк закладывается уже в таком виде,
TCCR0 <— R16;
в регистр общего назначения содержимое TCCR0 выгружается потому, что мк не умеет с ним работать напрямую... простая (без |) запись в него фиксированного значения также будет происходить через РОН, но уже без выгрузки в РОН исходного состояния регистра (т.е. займёт 2 команды).
Последний раз редактировалось Ivanoff-iv Чт янв 23, 2020 05:55:25, всего редактировалось 1 раз.

Re: Правильная инициализация таймера

Чт янв 23, 2020 05:53:51

mastech, Вы что, прикалываетесь? Откройте любой учебнике по Си и почитайте про оператор "|=".

Re: Правильная инициализация таймера

Чт янв 23, 2020 10:27:26

mastech, Вы что, прикалываетесь? Откройте любой учебнике по Си и почитайте про оператор "|=".

Вот с этого надо было начинать. А то остальные понаписали тут для ТС "сначала таймер через =, а потом через |=". Да ну нахер. Нет никакого "правильного" в данном случае. ТС просто надо прочитать чем оператор = отличается от |=. Тогда и понимание будет, а не тупо копирование без понимания. Битовые операции используются, когда надо "не трогать" другие биты. Присваивание - когда другие биты нужно установить однозначно в 0.

ТС, читай: http://www.c-cpp.ru/books/bitovye-operatory
Может лучше ссылка есть, первая что нашел. Просто учти что a |= b, это тоже самое, что a = a | b. Аналогично как a &= b == a = a & b и т.д.
Ответить