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

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 19:07:52

хотелось бы знать, как работает предделитель таймеров, есть ли у него "железный" сброс?

В даташите наверняка всё описано… не пробовали почитать даташит?

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 19:32:06

так это же читать надо...
а чукча - писатель, а не читатель...

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 20:11:14

Даташит зачитал до дыр в мониторе. Ничего конкретного не нашёл. Может ап-ноут какой посоветуете почитать про таймеры?

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 20:48:56

плохо читал.
есть регистр SFIOR, там есть биты для сброса предделителей таймеров.
если сомневаешься, что после подачи питания предделители в нуле, сбрось их самостоятельно.

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 22:01:23

Про регистр я в курсе, использую на всякий случай. Вопрос не в том, что я сомневаюсь, а в том, как оно на самом деле.

Re: Таймеры/счётчики в AVR

Сб ноя 05, 2022 22:33:38

Попробуйте сам написать тест. Просто пишите в UART состояние преди и след установки напр. таймера.
Ниже: на ATmega328 (Arduino UNO):
Код:
void setup() {
  for (uint32_t i = 0; i < 10000000; i++) {
  }

  Serial.begin(57600);
  Serial.println("--- start ---");
  Serial.println(TCCR1B, BIN);

  noInterrupts();                        // initialize timer1 and disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 62500;                         // compare match register 16 MHz / 256 / 1 Hz
  TCCR1B |= (1 << WGM12);                // CTC mode
  TCCR1B |= (1 << CS12);                 // 256 prescaler
  TIMSK1 |= (1 << OCIE1A);               // enable timer compare interrupt
  interrupts();                          // enable all interrupts
}

void loop() {
}

ISR(TIMER1_COMPA_vect) {
  Serial.println(TCCR1B, BIN);
}

резултат:
Код:
21:31:52.575 -> --- start ---
21:31:52.575 -> 11
21:31:53.575 -> 1100
21:31:54.575 -> 1100
21:31:55.575 -> 1100
21:31:56.575 -> 1100
21:31:58.455 -> --- start ---
21:31:58.455 -> 11
21:31:59.455 -> 1100
21:32:00.455 -> 1100
21:32:01.455 -> 1100
21:32:02.455 -> 1100
...


в --- start --- нажимаю кнопку RESET
TCCR1B = 0b00000011 - начальное состояние
TCCR1B = 0b00001100 - после установки для 1 Hz

Re: Таймеры/счётчики в AVR

Вс ноя 06, 2022 06:10:04

veso74 писал(а):в --- start --- нажимаю кнопку RESET
TCCR1B = 0b00000011 - начальное состояние
TCCR1B = 0b00001100 - после установки для 1 Hz

Можно понимать, что после внешнего сброса таймер 1 начинает считать тактовую с предделителем 64??? :shock:
OCR1A = 62500; // compare match register 16 MHz / 256 / 1 Hz
Уточню, для получения интервала 1 секунда, задавать нужно
OCR1A = 62500-1, иначе интервал будет на 256 тактов длиннее. viewtopic.php?p=4222274#p4222274

Re: Таймеры/счётчики в AVR

Вс ноя 06, 2022 09:44:03

... для получения интервала 1 секунда, задавать нужно OCR1A = 62500-1

Это понятно, спс, в спешке, не обращайте внимания :).
Untitled-1.jpg
(92.71 KiB) Скачиваний: 51

Из других систем и языков мне осталос правило: в начале, по возможности: все с первоначальным установлением. Как в случае и с используем Таймер_х: в начальном состоянии все регистры.

Re: Таймеры/счётчики в AVR

Вс ноя 06, 2022 12:40:01

Попробуйте сам написать тест

Да, пожалуй, хороший совет, на корифеев надейся, а сам не плошай. Написал следующую программу. На выводе PB0 весит светодиод. Идея заключается в следующем. Программа инициализирует таймер 0, подключая его к предделителю на 1024, затем выжидает 768 (с хвостиком) тактов и читает значение счётчика этого таймера. Если значение отлично от нуля, то светодиод на PB0 выключается. Смысл в том, чтобы загрузить эту программу в МК и периодически делать reset. Если предделитель аппаратно не сбрасывается, то хотя бы иногда за 3/4 периода он будет выдавать импульс на таймер 0 за счёт того, что его содержимое было отлично от нуля в начале работы МК. Поэтому светодиод иногда будет гаснуть. Если же он аппаратно сбрасывается, то содержимое счётчика таймера в момент чтения программой будет 0 всегда, светодиод будет гореть всегда.
Код:
.include"m8def.inc"

;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
;   Инициализация периферии МК
                ;   Настройка портов ввода-вывода
                ldi     r16,    0xFF    ;   На входах -- подтяжка
                out     PORTB,  r16
                out     PORTD,  r16
                out     PORTC,  r16
                ldi     r16,    0x01    ;   PB0 -- выход, остальные биты
                out     DDRB,   r16     ;       порта B -- входы
                clr     r16             ;   Порты C и D -- входы
                out     DDRC,   r16
                out     DDRD,   r16
                ;   Настройка таймера 0
                clr     r16
                out     TCNT0,  r16
                ldi     r16,    0x05    ;   Предделитель 1024
                out     TCCR0,  r16
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
;   Основная программа
                ;   Выжидание 768 тактов
                clr     r16
pauseLoop:      dec     r16
                brne    pauseLoop
                ;   Проверка содержимого счётчика таймера 0
                in      r16,    TCNT0
                tst     r16
                breq    finalLoop
                ;   Если счётчик отличен от нуля, сброс пина PB0 в ноль
                ldi     r16,    0xFE
                out     PORTB,  r16
                ;   Конец программы
finalLoop:      rjmp    finalLoop
;==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==

Результат эксперимента: светодиод горит всегда. Конечно, если я ОЧЕНЬ несчастливый человек, и мне жутко не везёт КАЖДЫЙ раз, то это ничего не значит. В противном случае с вероятностью экспоненциально стремящейся к 100%, предделитель таймеров аппаратно сбрасывается при хардовом ресэте. Вопрос решён, всем спасибо за дискуссию!

П.С. Пожелание разрабам: пишите в документацию все подробности работы вашего устройства!

Re: Таймеры/счётчики в AVR

Пн ноя 28, 2022 18:28:22

Господа коты, помогите разобраться с формированием интервалов.
Я использую WDT-таймер настроенный на интервал 16мс.
В прерывании таймера я инкрементирую 8-и битную переменную.
Код:
ISR(WDT_vect)
{
   WDTCR |=(1<<WDTIE);
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
   {systime++;}
}

А в главном цикле использую такой код:
Код:
if (systime - tmr1 >= 10U)
{
        tmr1 = systime;
        PORTB ^= (1 << PB3);
}

1. Без явного указания беззнаковости интервала (10U) оно не работает, почему так? Со всякими millis()'ами ведь работает?
2. Экономлю память, поэтому все переменные uint8_t, соотв. ловлю переполнение и происходит "дрыг". Как сделать, чтобы переполнение было пофиг? Самого диапазона интервалов при 1 тике раз в 16мс мне хватает, разобраться бы с переполнением.
Я подсмотрел вот такой код у Гайвера, он работает, но значение интервала желательно выбрать кратным степени двойки, т.к. используется деление, а это не всегда возможно...
Код:
   uint8_t timeLeft = systime - tmr1;
   if (timeLeft >=8)
   {
      tmr1 += 8 * (timeLeft / 8);
      PORTB ^= (1 << PB3);
   }

Re: Таймеры/счётчики в AVR

Вт ноя 29, 2022 07:50:55

внутри обработчика прерывания не нужно использовать ATOMIC_BLOCK, поскольку обработчик прерывания уже "атомно" исполняется по отношению к остальному коду.

поскольку я не помню (и не собираюсь запоминать) приоритеты операций, рекомендую взять разность в скобки
Код:
if ((systime - tmr1) >= 10U)


влияние U может быть в том, что по умолчанию все результаты и константы имеют тип int, т.е. со знаком, а вам знак не нужен...

Re: Таймеры/счётчики в AVR

Вт ноя 29, 2022 09:26:01

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

Re: Таймеры/счётчики в AVR

Вт ноя 29, 2022 09:45:30

Со скобками полезный совет, спасибо! Т.к. у меня тоже приоритеты не запоминаются, всегда подглядываю в таблицу.
В общем с этим U непонятно, у меня переменная таймера и переменная "подтаймера" строго uint8_t. Значит минус туда не запихнешь.
Но интересно другое! Если используется промежуточная переменная или счет времени обернуть в функцию, то тогда явное указание беззнаковости не нужно.
Например:
Код:
uint8_t timeLeft = systime - tmr1;
   if (timeLeft >=10)
   {
      tmr1 += timeLeft;
      PORTB ^= (1 << PB3);
   }

Подозреваю эффект открытия новых чудес, когда плохо читал документацию... Но что-то я упускаю.
И еще про этот кусок кода, он корректно отрабатывает переполнение щ0ччика, интервалы все ровные, но смущает вот что:
Изначально было так:
Код:
 tmr1 += 8 * (timeLeft / 8);

Я на бумажке посчитал, результат такой же, как если бы просто значение этой переменной прибавить к tmr1. Зачем тут эти выкрутасы с делением и умножением?

Добавлено after 7 minutes 45 seconds:
кисонька, вы покажите определения переменных, а то по огрызкам сложно судить.

Пардон.
Код:
volatile uint8_t systime = 0; // глобальная переменная, которую крутит прерывание таймера
int main(void)
{
       uint8_t tmr1 = 0; // локальная переменная, для интервала софт-таймера
       while(1);
       {
            if()...
       }
}

Re: Таймеры/счётчики в AVR

Вт ноя 29, 2022 10:04:58

... как если бы просто значение этой переменной прибавить к tmr1. Зачем тут эти выкрутасы с делением и умножением?

Вероятно "округление" до кратного 8.
Пример:
123 / 8 = 15,375;
15 * 8 = 120;

Я бы удалил последние 3 бита побитово:
Код:
a &= 0b11111000;

Из примера:
123 = 0b01111011;
123 & 0b11111000 = 0b01111011 & 0b11111000 = 0b01111000 = 120;

Я почти уверен, что оптимизатор уже это сделал.

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 08:06:47

я же вам писал: результат выражения по умолчанию int, т.е. со знаком.

uint8 - uint8 это не uint8, а int! а потом идет сравнение с 10, и это 10 тоже переделывается в int.

а когда вы пишите 10u, вы говорите компилятору: э, дарагой, тут знак нэ нада, давай, досвидания!

Добавлено after 3 minutes 27 seconds:
кстати, 123/8 в целых числах и так 15, а не 15,3.

Добавлено after 1 hour 24 seconds:
Зачем тут эти выкрутасы с делением и умножением?
точного ответа у меня нет, но есть предположение.

я думаю, вы просто взяли за основу обучения код такого же, как вы, начинающего. т.е. того, кто "так работает - ну и ладно!". нельзя учиться на коде "от гуру" и на коде от "начинающего", надо учиться на коде опытного, но но не настолько, чтобы свободно применять конструкции типа
Код:
v = {1,2,3,4}[i > 0 ? 17 ^ b * *с[x]++ : 136 / '\012'];
но уже отказавшегося от конструкций типа
Код:
if(x == 0) y = 'a';
else if(x == 1) y = 'b';
else if(x == 2) у = 'c';

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 11:13:04

uint8 - uint8 это не uint8, а int!
Вот уж мне эта юношеская категоричность :)
Смотрим

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 15:06:34

uint8 - uint8 это не uint8, а int!
Вот уж мне эта юношеская категоричность :)
Смотрим

опять плюсы в сишную тему приносите? integer promotions C

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 16:04:56

Плюсы там только чтобы тип можно было посмотреть.

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 19:06:27

Плюсы там только чтобы тип можно было посмотреть.
что вы предлагали мне увидеть по вашей ссылке? или integer promotions уже отменили?

Re: Таймеры/счётчики в AVR

Ср ноя 30, 2022 20:56:10

что вы предлагали мне увидеть по вашей ссылке?
Что ваше "uint8 - uint8 это не uint8, а int!" это ложное утверждение.

или integer promotions уже отменили?
Зачем вы употребляете термины, значение которых не знаете? Есть же стандарт. Читаем 6.3.1.1 и обнаруживаем, что может быть как int, так и unsigned int. Что примеры по моей ссылке и подтверждают.
Ответить