UNO: таймер 2

orgEx2
Offline
Зарегистрирован: 25.09.2020

Arduino UNO 16 МГц (проверил на кварце осцилографом и убедился программатором, что фьюзы CKSEL=0111)
Как известно из даташита - таймер 2  8-битный.

Следовательно, при выключенном предделителе - прерывание TIMER2_COMPB_vect должно вызываться 16000000/256 = 62500 раз в секунду.
Но на осциллографе я вижу прямоугольный сигнал с частотой ~244 Гц (!)
Как будто бы прерывание срабатывает не 62500 раз в секунду, а 62500/256 = 244 раз в секунду...
Я бы понял, если бы это был таймер 1 (он 16-битный). Но у меня ведь таймер 2!

#include <Arduino.h>

ISR (TIMER2_OVF_vect) {
  PORTB |= (1 << PB5); // При переполнении - высокий уровень
}

ISR (TIMER2_COMPB_vect) {
  PORTB &= ~(1 << 5); // При совпадении - низкий уровень
}
void setup() {
  
  DDRB |= 1 << PB5; // Пин D13 - выход на светодиод
    
  OCR2B = 0x25; // "Процент" заполнения
 
  //TCCR2B = (1 << CS21) | (1 << CS20);  // На счётчик подаётся CLK=16 МГц
  TCCR2B |= 1 << CS20;  // На счётчик подаётся CLK=16 МГц
  TIMSK2 |= 1<<OCIE2B; // Вызов прерывания при совпадении
  TIMSK2 |= 1<<TOIE2;   // Вызов прерывания при переполнении
  
}

void loop() {

}

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

А считай и выведи в сериал или на диспплей значение TCCR2B в конце сетапа. Он же не с нуля у тебя иницируется. А OR-м. Так что предделитель там, скорее всего не 1 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

PWM на этом таймере уже настроен, 490 герц где-то

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

У Вас делитель 128! Среда ардуино пишет туда CS22 и Вы в дополнение CS20 пихаете.

Так что, всё правильно.

Иницилиазируйте таймер полностью, с нуля.

Green
Offline
Зарегистрирован: 01.10.2015
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016
enum Prescaler {
   PRESCALER_STOP = 0 ,
   PRESCALER_1 = 1 ,
   PRESCALER_8 = 2 ,
   PRESCALER_32 = 3 ,
   PRESCALER_64 = 4 ,
   PRESCALER_128 = 5 ,
   PRESCALER_256 = 6 ,
   PRESCALER_1024 = 7  
};
unsigned  int counter = 0 ;

void  setup () {
   pinMode ( 13 , ВЫХОД);
   
   uint8_t prescaler = PRESCALER_128;
   uint8_t topValue = 255 ;
   pinMode ( 11 , ВЫХОД);
   TCCR2A = 0x42 ;              // Инвертирование пина 11 по сравнению и режим CTC то OCR2A
   TCCR2B = 0x00 | прескалер;  // Установить СТС режим и делитель частоты
   OCR2A = topValue;           // установить TOP равным topValue
  }
   
void  loop () {
 while ( digitalRead ( 11 ) == LOW);
  счетчик ++;
  if (counter == 60000 ) {
  digitalWrite ( 13 ,! digitalRead ( 13 ));
  counter = 0 ;}
}

 

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

Иницилиазируйте таймер полностью, с нуля.


А можно подробнее, для особо одарённых.) Лучше с примером. Понятие нуля хотелось бы понять.)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:

А можно подробнее, для особо одарённых.)

Для особо одарённых не могу, т.к. никогда не работал в школе для особо одарённых и не знаю тамошних методик преподавания.

Green пишет:

Лучше с примером.

Закажите в "Ищу исполнителя".

Green пишет:

Понятие нуля хотелось бы понять.)

А чего тут понимать? Прописывать нужно ВСЕ биты так, как Вам надо, а не только 1-цы. Нельзя надеяться, на то, что до Вашей настройки там было что-то определённое и разумное.

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

А чего тут понимать? Прописывать нужно ВСЕ биты так, как Вам надо, а не только 1-цы. Нельзя надеяться, на то, что до Вашей настройки там было что-то определённое и разумное.


ЕвгенийП, ну вот как раз я вас и хочу убедить в том, что не ВСЕ приписывания ВСЕХ требуемых регистров помогают. Оказывается, всё ещё зависит и от режима в котором Таймер находился до этого. Это что ж получается? Я должен знать/помнить ВСЕ(!) режимы этого таймера, что бы настроить на свой?
Для примера, 1602 в 4-битном режиме. В ДШ чётко расписана последовательность действий по инициализации его (1602) в этом режиме. Не зависимо от того в каком режиме он находился до этого.
Вы понимаете?

b707
Offline
Зарегистрирован: 26.05.2017

Что такое 1602? Мне казалось разговор о таймерах. Дисплей такой знаю, а таймер нет

Green
Offline
Зарегистрирован: 01.10.2015

Я привёл пример для дисплея 1602, как показана его инициализация в ДШ. Чего не наблюдается в ДШ по инициализации таймера.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Я привёл пример для дисплея 1602, как показана его инициализация в ДШ. Чего не наблюдается в ДШ по инициализации таймера.)

Green
Offline
Зарегистрирован: 01.10.2015

Красиво. Жаль только, что не все регистры указаны.)) Ладно, не будем засорять топик.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:

ЕвгенийП, ну вот как раз я вас и хочу убедить в том, что не ВСЕ приписывания ВСЕХ требуемых регистров помогают. Оказывается, всё ещё зависит и от режима в котором Таймер находился до этого. 

Что-то Вы не то говорите. Что такое "режим в котором таймер был до этого"? Это просто комбинация битов прописаннае в регистрах. Если Вы все биты перепропишете как Вам надо в соответствие с даташитом, то каким боком прошлый режим может Вам помешать?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Green пишет:

ЕвгенийП, ну вот как раз я вас и хочу убедить в том, что не ВСЕ приписывания ВСЕХ требуемых регистров помогают. Оказывается, всё ещё зависит и от режима в котором Таймер находился до этого. 

Что-то Вы не то говорите. Что такое "режим в котором таймер был до этого"? Это просто комбинация битов прописаннае в регистрах. Если Вы все биты перепропишете как Вам надо в соответствие с даташитом, то каким боком прошлый режим может Вам помешать?

Евгений Петрович, а не озвучить ли здесь типичную ошибку связанную при применением функции attachInterrupt() вследствии её кривой реализации и иных багов среды, а именно эта не сбрасывает флаг прерываний перед её включением, в результате имеем криво работающий код!

А может в новых версиях это уже поправили?

Лечим просто:

EIFR = 0x01;
attachInterrupt(Pin, ISR_prog, RISING);

 

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

Что-то Вы не то говорите. Что такое "режим в котором таймер был до этого"? Это просто комбинация битов прописаннае в регистрах. Если Вы все биты перепропишете как Вам надо в соответствие с даташитом, то каким боком прошлый режим может Вам помешать?


Я ж приводил пример):

void setup() {
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  TCCR2B = 1<<CS20;              //делитель 1:1
}

void loop() {}

Как видите, никаких единичек, всё строго. Всё согласно ДШ. Неиспользуемые OCR2B, ASSR, GTCCR = 0, можно дописать при желании. Однако на выходе 8, вместо 4-х мгц.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Green пишет:

ЕвгенийП пишет:

Что-то Вы не то говорите. Что такое "режим в котором таймер был до этого"? Это просто комбинация битов прописаннае в регистрах. Если Вы все биты перепропишете как Вам надо в соответствие с даташитом, то каким боком прошлый режим может Вам помешать?


Я ж приводил пример):

void setup() {
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21; //выход и CTC
  TCCR2B = 1<<CS20;              //делитель 1:1
}

void loop() {}

Как видите, никаких единичек, всё строго. Всё согласно ДШ. Неиспользуемые OCR2B, ASSR, GTCCR = 0, можно дописать при желании. Однако на выходе 8, вместо 4-х мгц.

Привет, коллеги! Я тут на отдыхе, и читаю уже не первый раз про таймер ;))). Тебе же ДимаХ ответил, что нужно завести полезную привычку выставлять OCR последним. Мне даже кажется, что что-то про это я видел в документации, но не уверен.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Green пишет:

ЕвгенийП пишет:

А чего тут понимать? Прописывать нужно ВСЕ биты так, как Вам надо, а не только 1-цы. Нельзя надеяться, на то, что до Вашей настройки там было что-то определённое и разумное.


ЕвгенийП, ну вот как раз я вас и хочу убедить в том, что не ВСЕ приписывания ВСЕХ требуемых регистров помогают. Оказывается, всё ещё зависит и от режима в котором Таймер находился до этого. Это что ж получается? Я должен знать/помнить ВСЕ(!) режимы этого таймера, что бы настроить на свой?
Для примера, 1602 в 4-битном режиме. В ДШ чётко расписана последовательность действий по инициализации его (1602) в этом режиме. Не зависимо от того в каком режиме он находился до этого.
Вы понимаете?

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

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Green пишет:

Как видите, никаких единичек, всё строго. Всё согласно ДШ. Неиспользуемые OCR2B, ASSR, GTCCR = 0, можно дописать при желании. Однако на выходе 8, вместо 4-х мгц.

Так это по даташиту на камень.
У Ардуино свои приколы.
Она же выставляет эти таймеры уже.
Где то на ШИМ, где то на миллис.
Смените среду, удалите загрузчик и тогда все будет работать как в даташите на камень

Green
Offline
Зарегистрирован: 01.10.2015

wdrakula пишет:

Привет, коллеги! Я тут на отдыхе, и читаю уже не первый раз про таймер ;))). Тебе же ДимаХ ответил, что нужно завести полезную привычку выставлять OCR последним. Мне даже кажется, что что-то про это я видел в документации, но не уверен.


Теперь то я в курсе). Но полтора часа пришлось потратить.( Сначала заработало методом тыка, а затем начал читать ДШ. Но в документации нужно глубоко копать - до ШИМ режимов аж, которые здесь причём, казалось бы!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

GREEN

согласно даташиту надо так видимо?
 

void setup() {
  DDRD  = 1<<3;                  //пин
  OCR2A = 1;                     //частота 4
  TCCR2A = 1<<COM2B0 | 1<<WGM21 | 0 << WGM20; //выход и CTC
  TCCR2B = 0 << WGM22 | 1<<CS20 | 0 << CS21 | 0 << CS22;              //делитель 1:1
}

void loop() {}

 

Green
Offline
Зарегистрирован: 01.10.2015

Kakmyc пишет:

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


Задним числом мы все умные.) Порты вы тоже сначала обнуляете прежде чем в них что то записать?

Green
Offline
Зарегистрирован: 01.10.2015

ua6em пишет:

GREEN

согласно даташиту надо так видимо?


Это одно и тоже, нули можно не сдвигать.) Немного нагляднее только.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

Kakmyc пишет:

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


Задним числом мы все умные.) Порты вы тоже сначала обнуляете прежде чем в них что то записать?

это всё из-за битовых операций )))

 интересно, а как прочитать содержимое этих регистров?

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Так так и читать:
X=OCR2A
И тд

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Kakmyc пишет:
Так так и читать: X=OCR2A И тд

Понятно!
а вот тут второй строкой бит в 0 устанавливают?
 

TCCR2B |= ((1<<CS22) | (1<<CS20));
TCCR2B &= ~(1<<CS21);

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:

Как видите, никаких единичек, всё строго. Всё согласно ДШ. 

Точно всё? Вы таки упустили главное из моего поста - самое главное

ЕвгенийП пишет:

Если Вы все биты перепропишете как Вам надо в соответствие с даташитом

Вам показать в даташите что Вы не так сделали? Или (судя по ответу графу) Вы и так знаете где там про это?

А тогда я не понимаю, с чем Вы спорите. С тем, что это в даташите "глубоко закопано"? Так его весь знать надо. Спор-то ни о чём.

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:
Вы таки упустили главное из моего поста - самое главное

Конечно, покажите мне самое главное.) И я с вами не спорю, с вами сложно спорить. Я тему создал после того как уже всё выяснил. Но не вижу что бы для многих это было очевидно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:
Но не вижу что бы для многих это было очевидно.
А должно быть? 

Тут уж надо выбирать, если человек не хочет изучать даташит, то надо пользоваться средствами IDE или, уж если приспичило, ставить хорошую библиотеку. А если человек хочет сам ручками что-то настраивать и при этом не хочет изучать даташит - сам себе злобный буратино, что тут скажешь?

Green
Offline
Зарегистрирован: 01.10.2015

Ну вы ж понимаете, хочется раз-два и готово. А даташит - это когда уже не идёт... Да и не упомнишь нюансы всё.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

ua6em пишет:

Kakmyc пишет:
Так так и читать: X=OCR2A И тд

Понятно!
а вот тут второй строкой бит в 0 устанавливают?
 

TCCR2B |= ((1<<CS22) | (1<<CS20));
TCCR2B &= ~(1<<CS21);

 

Да