Нужна подсказка по работе с таймером/счётчиком

gena
Offline
Зарегистрирован: 04.11.2012

 Осваиваю таймер/счётчик Т0 в ATtiny13. Написал программу в AVRStudio 4.19. Ожидаю меандр на выводе 6 с частотой в 100 раз меньше тактовой. Генератор внутренний, 128 кГц. В "железе" генерации нет. Симуляция тоже подтверждает неработоспособность программы. Нужен свежий взгляд на программу.

 
  #define F_CPU 128000UL                                      // 0,128 MHz
   #include <avr/io.h>
   #include <avr/delay.h>


void init(){

  DDRB = (0<< DDB4)|(0<<DDB3)|(1<< DDB2)|(1<<DDB1)|(0<< DDB0); // настройка разрядов порта B: 4,3,0 - входы, 2,1 - выходы;
  TCNT0 = 0;                                                   // исходное значение счётчика Т0
  OCR0B = 49;                                                  // коэффициен деления в регистре OCR0B
  TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(0<<COM0B1)|(1<<COM0B0)|(1<<WGM01)|(0<<WGM00); // настройка таймера/счётчика Т0
  TCCR0B = (0<<FOC0A)|(0<<FOC0B)|(0<<WGM02)|(0<<CS02)|(0<<CS01)|(0<<CS00);
  
}

void main() {

  init();
  TCCR0B |= (1<<CS00);                                         // установить в "1" бит 0 регистра TCCR0B, (CS00 = 1) - запуск таймера
  //TCCR0B.b0 = 1;                                             // путём включения предделителя
}

 

 

gena
Offline
Зарегистрирован: 04.11.2012

    Режим таймера "СТС". В симуляторе студии вижу, что не инкрементируется регистр  TCNT0, но почему так происходит - пока не понимаю.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Вы неправильно устанавливаете и сбрасываете биты, в симуляции (окошко IO View) должно быть видно. Нужно так:

DDRB |= ((1<<DDB2)|(1<<DDB1)); //установить биты в "1"
DDRB &= ~((1<<DDB4)|(1<<DDB3)|(1<<DDB0)); //сбросить биты в "0"

Остальные по аналогии.

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

gena, смотрим для начала по даташиту в каком режиме вы хотите завести генератор. Это определяют биты WGM. Вы ставите только один бит WGM01, по таблице на странице 72 это режим 2(CTC), в нём регистр OCRA определяет до скольки считать таймеру. У вас же он не определён, значит таймер будет считать до 0.  Так что генерации быть действительно не должно :)

 

gena
Offline
Зарегистрирован: 04.11.2012
  Спасибо откликнувшимся.
1. Для Jeka_M. Посмею не согласиться с Вами относительно моей неправильной установки и сброса бит. Я не УСТАНАВЛИВАЮ и не СБРАСЫВАЮ биты, я СРАЗУ (целиком) ПРИСВАИВАЮ регистру DDRB нужное значение. Аналог моей команды:
    DDRB = 0b00000110.
Только это "магическое число", а запись
DDRB = (0<< DDB4)|(0<<DDB3)|(1<< DDB2)|(1<<DDB1)|(0<< DDB0) гораздо понятнее. 
   Пишу это не для того, что бы как то "выделиться" перед Вами (применил заглавные буквы), а что бы подсказать Вам о ходе моей мысли. Я всегда просматриваю ассемблерный код, который сгенерит компилятор. А с ассемблером я значительно дружнее чем с СИ. И через ассемблерный код разбираюсь как работает СИ. 
;Ftact.c,13 ::                 DDRB = (0<< DDB4)|(0<<DDB3)|(1<< DDB2)|(1<<DDB1)|(0<< DDB0);
        LDI        R27, 6
        OUT        DDRB+0, R27
 
2. Для dimax. Ваше замечание дало мне правильное направление для поиска ошибки. Я не настраивал регистр OCR0A т.к. меня интересует вывод 6 (PB1 = OC0B) микроконтроллера, а это завязано на регистр OCR0B. Я считал, что если я биты COM0A1,COM0А0 держу равными нулю, то этот регистр OCR0A (и аппаратная часть микроконтроллера), не влияет на работу другой, OCR0B, части. Видимо это не так. Добавил в программу один оператор, и pin 6 "зазвучал".
   #define F_CPU 128000UL                                      // 0,128 MHz
   #include <avr/io.h>
   #include <avr/delay.h>


void init(){

  DDRB = (0<< DDB4)|(0<<DDB3)|(1<< DDB2)|(1<<DDB1)|(0<< DDB0); // настройка разрядов порта B: 4,3,0 - входы, 2,1 - выходы;
  TCNT0 = 0;                                                   // исходное значение счётчика Т0
  OCR0A = 255; 
  OCR0B = 49;                                                  // коэффициен деления в регистре OCR0B
  TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(0<<COM0B1)|(1<<COM0B0)|(1<<WGM01)|(0<<WGM00); // настройка таймера/счётчика Т0
  TCCR0B = (0<<FOC0A)|(0<<FOC0B)|(0<<WGM02)|(0<<CS02)|(0<<CS01)|(0<<CS00);
  
}

void main() {

  init();
  TCCR0B |= (1<<CS00);                                         // установить в "1" бит 0 регистра TCCR0B, (CS00 = 1) - запуск таймера
  //TCCR0B.b0 = 1;                                             // путём включения предделителя
}

 

gena
Offline
Зарегистрирован: 04.11.2012

  К теме. Сейчас поэкспериментировал с "железом". Генерация есть, но есть и непонятки. Продолжаю изучать. 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

gena, да,  таймеры для большинства пользователей ардуины -тёмные лошадки, по той простой причине, что в даташите про таймеры написано всё очень формально, нормальному человеку, не вундеркинду, очень трудно разобраться.  В любых сторонних документациях про таймеры опять же приводят описание того-же даташита в том или ином варианте пересказа. На пальцах практически нигде не показывают, и до понятной формы не разжовывают. Есть некоторые ключевые моменты, которые вообще нигде не встречаются, про которые никто не писал, но  без которых невозможно полное понимание.  Например такие моменты:  существуют три основных режима  генерации частоты таймером: (1) режимы, в которых можно регулировать частоту, но нельзя регулировать скважность. (2) режимы, в которых можно регулировать скважность, но нельзя регулировать частоту (не считая "регулировку" предделителем) (3) Режимы, в которых можно регулировать и частоту и скважность. У вас получился режим (1) соответссно регистром OCR0A вы устанавливаете частоту, а регистр OCR0B имеет почти бесполезную функцию -он отвечает на какой тик счёта TCNT0 будет переключаться состояние выхода OC0B. Поэтому он не должен быть больше, чем OCR0A, иначе выход никогда не переключиться. Обычно его просто обнуляют в этом режиме.