Этюды для начинающих: blink и без delay, и без millis

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ну от. Значить, gcc всёже лучше меня оптимизирует :) 

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

Оптимизация вообще последнее дело. Только в исключительных случаях.

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

ну это понятно, сдвинуть на десять разрядов за два такта совсем никак, хотя бы за десять )))

Bruzzer
Offline
Зарегистрирован: 17.03.2020

ua6em пишет:

ну это понятно, сдвинуть на десять разрядов за два такта совсем никак, хотя бы за десять )))

Меня переклинило потому что я предположил - т.к результат uint_8t то  вдруг он просто берет второй байт от long. Ну а то, что в байте не 10 бит, это мой мозг пропустил, в попытке обосновать 2 такта.

NikShel
Offline
Зарегистрирован: 21.01.2018

Уважаемый dimax !

Пытался сделать блинк из Вашего "Терминального" генератора

Немного переделал, т.к. мне очень надо, чтобы ещё была частота: 0 (без блинка).

Это я пытаюсь сделать индикацию режимов.  Задача простая

Частота: 0 - обычный режим;

Частота №1 - режим настройки  №1;

Частота №2 - режим настройки  №2.

Переключение режимов вручную (пока не задано новое значение).

Но пока у меня получилось, что блинк работает с нужной частотой примерно 1 сек. Переменная reqfreq почему-то обнуляется в конце void loop() , хотя я пытался сделать её глобальной переменной.

Подскажите, что не так!

[code]
volatile long reqfreq = 0; //<--N.Sh.
uint32_t ocr = OCR1A; // uint16_t divider = 1;  float freq;  //<--N.Sh.

void setup() {
  Serial.begin(9600);
  pinMode (9, OUTPUT); // выход генератора
  TCCR1A = 0; TCCR1B = 0;
}

void loop() {
  //  static uint32_t reqfreq = 0; //<-- dimax переменная запроса частоты
  uint16_t divider = 1;  float freq; // uint32_t ocr = OCR1A; <-- dimax
  if (Serial.available() > 0) {
    reqfreq = Serial.parseInt();

    if (reqfreq > F_CPU / 2) {
      return;
    }
    if (reqfreq == 0) {
      TCCR1A = 0; TCCR1B = 0;
      Serial.println("0 Hz");
      return;
    }  // <--N.Sh. / dimax--> if (reqfreq==0 || reqfreq>F_CPU/2) {return;}
    ocr = (F_CPU / reqfreq / 2 / divider);
    byte shifts[] = {3, 3, 2, 2};
    for (byte i = 0; i < 4; i++) {
      if (ocr > 65536) {
        divider <<= shifts[i];
        ocr = F_CPU / reqfreq / 2 / divider;
      }
      else {
        TCCR1B = (i + 1) | (1 << WGM12);   //Mode4 (CTC)
        break;
      }
    }
    OCR1A = ocr - 1; TCCR1A = 1 << COM1A0;
    freq = (float) F_CPU / 2 / (OCR1A + 1) / divider;
    if (freq < 10000) {
      Serial.print(freq, 1);
      Serial.println(" Hz ");
    }
    if (freq >= 10000) {
      Serial.print(freq / 1000, 3);
      Serial.println(" kHz");
    }
  }
  // Serial.println(reqfreq);
}

//Скетч использует 4430 байт (14%) памяти устройства. Всего доступно 30720 байт.
//Глобальные переменные используют 222 байт (10%) динамической памяти, оставляя 1826 байт для локальных переменных. Максимум: 2048 байт.
[/code]

 

venus
venus аватар
Offline
Зарегистрирован: 08.10.2019

volatile-то вам зачем? Serial.parseInt() у вас возвращает ноль не только если введена строка "0", но и если мусор считал.

uint32_t ocr = OCR1A; // uint16_t divider = 1;  float freq;  //<--N.Sh.

void setup() {
  Serial.begin(9600);
  pinMode (9, OUTPUT); // выход генератора
  TCCR1A = 0; TCCR1B = 0;
}

void loop() {
  static uint32_t reqfreq = 0; //<-- dimax переменная запроса частоты
  static char in[16];
  uint16_t divider = 1;  float freq; // uint32_t ocr = OCR1A; <-- dimax
  if (Serial.available() > 0 && Serial.readBytes(in, 15) > 0 && sscanf(in, "%lu", &reqfreq) == 1) {
    if (reqfreq > F_CPU / 2) {
      return;
    }
    if (reqfreq == 0) {
      TCCR1A = 0; TCCR1B = 0;
      Serial.println("0 Hz");
      return;
    }  // <--N.Sh. / dimax--> if (reqfreq==0 || reqfreq>F_CPU/2) {return;}
    ocr = (F_CPU / reqfreq / 2 / divider);
    byte shifts[] = {3, 3, 2, 2};
    for (byte i = 0; i < 4; i++) {
      if (ocr > 65536) {
        divider <<= shifts[i];
        ocr = F_CPU / reqfreq / 2 / divider;
      }
      else {
        TCCR1B = (i + 1) | (1 << WGM12);   //Mode4 (CTC)
        break;
      }
    }
    OCR1A = ocr - 1; TCCR1A = 1 << COM1A0;
    freq = (float) F_CPU / 2 / (OCR1A + 1) / divider;
    if (freq < 10000) {
      Serial.print(freq, 1);
      Serial.println(" Hz ");
    }
    if (freq >= 10000) {
      Serial.print(freq / 1000, 3);
      Serial.println(" kHz");
    }
  }
  // Serial.println(reqfreq);
}

//Скетч использует 4430 байт (14%) памяти устройства. Всего доступно 30720 байт.
//Глобальные переменные используют 222 байт (10%) динамической памяти, оставляя 1826 байт для локальных переменных. Максимум: 2048 байт.

 

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

NikShel пишет:

 Переменная reqfreq почему-то обнуляется в конце void loop() , хотя я пытался сделать её глобальной переменной. Подскажите, что не так!

По виду всё так. Наверно из терминалки прилетает ноль. Если в ардуиновском мониторе смотрите, то выберете в настройке "Нет конца строки"

venus
venus аватар
Offline
Зарегистрирован: 08.10.2019

dimax пишет:
Наверно из терминалки прилетает ноль.

там что попало прилетает, функция parseint просто такая. замена на readbytes плюс sscanf решает вопрос. проверил.

NikShel
Offline
Зарегистрирован: 21.01.2018

в настройке "Нет конца строки"

Помогло, спасибо!

NikShel
Offline
Зарегистрирован: 21.01.2018

venus пишет:

dimax пишет:
Наверно из терминалки прилетает ноль.

там что попало прилетает, функция parseint просто такая. замена на readbytes плюс sscanf решает вопрос. проверил.

 readbytes плюс sscanf  - можно по-подробней. В справочниках не нашёл.

venus
venus аватар
Offline
Зарегистрирован: 08.10.2019

NikShel пишет:
readbytes плюс sscanf  - можно по-подробней. В справочниках не нашёл.

я же прицепил исправленный скетч в ответе на ваш вопрос. сравните со своим, там лишь пара строк отличается.

NikShel
Offline
Зарегистрирован: 21.01.2018

venus пишет:

 исправленный скетч в ответе на ваш вопрос. сравните со своим, там лишь пара строк отличается.

Я протестил: работает, спасибо!

NikShel
Offline
Зарегистрирован: 21.01.2018

Ну и вот он мой вариант Блинка:

#define D9_High TCCR1A = B11 << COM1A0; // 11 - установить пин_9 HIGH = off
#define D9_LOW TCCR1A = B10 << COM1A0; // 10 - установить пин_9 LOW = on
#define D9_F_1Hz TCCR1B = 12; OCR1A = 31249; TCCR1A = 1 << COM1A0; //  Frequency: 1Hz; 
#define D9_F_2Hz TCCR1B = 11; OCR1A = 62499;  TCCR1A = 1 << COM1A0; //  Frequency: 2Hz;

void setup() {
  Serial.begin(9600);
  pinMode (9, OUTPUT); // выход генератора
  TCCR1A = B10 << COM1A0;
}

void loop() {

  static uint32_t var = 0; //<-- dimax переменная запроса режима
  static char in[1];

  if (Serial.available() > 0 && Serial.readBytes(in, 1) > 0 && sscanf(in, "%lu", &var) == 1) { //  <-- venus
    Serial.println(var);
    switch (var) {
      case 0:
        D9_High //выполняется, когда var равно 0 - выкл
        break;
      case 1:
        D9_F_1Hz //выполняется, когда var равно 1
        break;
      case 2:
        D9_F_2Hz //выполняется когда  var равно 2
        break;
      default:
        D9_LOW // обычный режим

    }
  }
}

//Скетч использует 3836 байт (12%) памяти устройства. Всего доступно 30720 байт.
//Глобальные переменные используют 197 байт (9%) динамической памяти, оставляя 1851 байт для локальных переменных. Максимум: 2048 байт.

Спасибо, venus 

Спасибо, dimax 

Спасибо, ЕвгенийП !

NikShel
Offline
Зарегистрирован: 21.01.2018

Евгений, в качестве продолжения темы.

А как переделать Ваш калькулятор для рассчёта параметров для Timer2.

Есть желание сделать на одной Нане два Блинка с разными регулируемыми частотами.

Пока на втором Таймере получилась пищалка.

с Наступающим!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Сделай всё то же самое, но на одном таймере, я разрешил

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

NikShel пишет:

А как переделать Ваш калькулятор для рассчёта параметров для Timer2.

Ну, калькулятор - игрушка, а делать расчёты для всех таймеров позволяет вот такая библиотека. Прелесть её в том, что она ВСЕ вычисления делает на этапе компиляции и в код попадают уже готовые цифири 0 никаких расчётов во время выполнения. Там на гитхабе есть ссылка на обсуждение и подробности на этом форуме.

Upper
Offline
Зарегистрирован: 23.06.2020

DetSimen пишет:

Сделай всё то же самое, но на одном таймере, я разрешил

На гитхабе в описании к библиотеке написано, что  с вопросами и предложениями лучше обращаться на форум arduino.ru. Если на форуме есть своя тема по этой библиотеке, может имеет смысл на гитхабе дать не нее ссылку?

Сама библиотека вызывает двоякое впечатление. С одной стороны мне было интересно и полезно посмотреть в коде, как на практике используются разные приемы программирования. С другой стороны, "поломка" работы millis (ибо кого волнует точность?) отталкивает от желания использовать на практике.

Еще вопрос. В операторе "--" вы разрешаете прерывания перед вызовом fCallback();.  Насколько это допустимо? Ведь этот оператор используется внутри обработки прерывания ISR(TIMER0_COMPA_vect).

	TCounterDown &operator --(int) {

		uint8_t sreg = SREG;   // на всякий случай запомним состояние прерываний

		cli();				// запрещаем прерывания

		if ((isActive()) && (!isEmpty()) && ((--fWorkCount) == 0)) {  // если счетчик досчитал до 0
			fWorkCount = fInitCount; // перезагружаем рабочий счётчик начальным значением, чтобы считать заново
			sei();				// разрешаем прерывания
			fCallback();		// и вызываем нашу фунцию обратного вызова
		}
		
		SREG = sreg;     // восстанавливаем прерывания
		return *this;
	}

 

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

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

NikShel пишет:

А как переделать Ваш калькулятор для рассчёта параметров для Timer2.

Ну, калькулятор - игрушка, а делать расчёты для всех таймеров позволяет вот такая библиотека. Прелесть её в том, что она ВСЕ вычисления делает на этапе компиляции и в код попадают уже готовые цифири 0 никаких расчётов во время выполнения. Там на гитхабе есть ссылка на обсуждение и подробности на этом форуме.

а Важгад не к этой библиотеке добавляли?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Upper пишет:
...отталкивает от желания использовать на практике.

Так я ж и не настаиваю. :) 

В последней версии millis() не врёт, используется такая конструкция

OCR0A += TIMER_ONE_MS;

вместо

TCNT0 = 0xFF;

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

А я вообще сторонник не накрученности. Чем проще, чем понятнее, тем лучше. Или нет?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вапще-то, правила хорошего тона, в низкоуровневом программировании, требуют разрешать прерывания при заходе в обработчик, за исключением случаев, критичных ко времени обработки.  Зачем создавать очередь отложенных прерываний, если оне друг другу не мешают?  Но, тут нужна еще культура написания самого обработчика, чтоб он выполнялся как можно быстрее и не делал ничего лишнего.  Поэтому, в последних версиях я отказался от колбэков, сработавший таймер просто кладёт в очередь сообщение о событии, а оно потом уже штатно обрабатывается диспеччером в loop().  И никто никаво не тормозит. 

Upper
Offline
Зарегистрирован: 23.06.2020

DetSimen пишет:

В последней версии millis() не врёт, используется такая конструкция

OCR0A += TIMER_ONE_MS;

вместо

TCNT0 = 0xFF;

Может мы о разных библиотека говорим?
Я говорю о той, на которую вы дали ссылку
https://github.com/DetSimen/Arduino_TimerList/blob/master/TimerList.cpp
В ней TCNT0 = 0xFF;

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

DetSimen пишет:

  Поэтому, в последних версиях я отказался от колбэков, сработавший таймер просто кладёт в очередь сообщение о событии, а оно потом уже штатно обрабатывается диспеччером в loop().  И никто никаво не тормозит. 

+100500!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Upper пишет:

Может мы о разных библиотека говорим?

Я говорю о той, на которую вы дали ссылку
https://github.com/DetSimen/Arduino_TimerList/blob/master/TimerList.cpp
В ней TCNT0 = 0xFF;

На гитхабе старая. Но, для несложных задач падёт, типа 2-х независимых блинков, как нужно было вопрошающему.  Я поправлю, как руки дойдут. :) 

NikShel
Offline
Зарегистрирован: 21.01.2018

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

ConstTimersComplexTest:

Arduino: 1.8.5 (Windows 10), Board: "Arduino Nano, ATmega328P"
 
C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino: In function 'void setup()':
 
ConstTimers:33: error: ambiguous overload for 'operator<<' (operand types are 'Print' and 'char')
 
           Serial << "*** Error with \"by period\" calculation: timer/counter:" << timerId << "; period:" << period << "; bits:" << bits << '(' << prescalerValue(timerId, bits) << "); ticks:" << ticks << "; realPeriod:" << realPeriod << "\r\n"; // NikShel edition
 
                                                                                                                                         ^
 
C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:33:137: note: candidates are:
 
In file included from C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:8:0:
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:10:17: note: Print& operator<<(Print&, __int24)
 
  inline Print & operator << (Print &s, __int24 n) { s.print((int32_t)n); return s; }
 
                 ^
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:11:17: note: Print& operator<<(Print&, __uint24)
 
  inline Print & operator << (Print &s, __uint24 n) { s.print((uint32_t)n); return s; }
 
                 ^
 
ConstTimers:45: error: ambiguous overload for 'operator<<' (operand types are 'Print' and 'char')
 
                    << "; bits:" << bitsF << '(' << prescalerValue(timerId, bitsF) << "); ticks:"
 
                                          ^
 
C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:45:42: note: candidates are:
 
In file included from C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:8:0:
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:10:17: note: Print& operator<<(Print&, __int24)
 
  inline Print & operator << (Print &s, __int24 n) { s.print((int32_t)n); return s; }
 
                 ^
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:11:17: note: Print& operator<<(Print&, __uint24)
 
  inline Print & operator << (Print &s, __uint24 n) { s.print((uint32_t)n); return s; }
 
                 ^
 
ConstTimers:60: error: ambiguous overload for 'operator<<' (operand types are 'Print' and 'const char*')
 
          << "\r\n\r\nВремÑ? выполнениÑ?: " << (minutes < 10 ? "0" : "") << minutes << ':' << (seconds < 10 ? "0" : "") << seconds
 
                                                         ^
 
C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:60:57: note: candidates are:
 
In file included from C:\Arduino\Gen1-2Hz\ConstTimers\ConstTimers.ino:8:0:
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:10:17: note: Print& operator<<(Print&, __int24) <near match>
 
  inline Print & operator << (Print &s, __int24 n) { s.print((int32_t)n); return s; }
 
                 ^
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:10:17: note:   no known conversion for argument 2 from 'const char*' to '__int24'
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:11:17: note: Print& operator<<(Print&, __uint24) <near match>
 
  inline Print & operator << (Print &s, __uint24 n) { s.print((uint32_t)n); return s; }
 
                 ^
 
C:\Install\arduino-1.8.5-windows\arduino-1.8.5\libraries\ConstTimers/Printing.h:11:17: note:   no known conversion for argument 2 from 'const char*' to '__uint24'
 
exit status 1
ambiguous overload for 'operator<<' (operand types are 'Print' and 'char')
 
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
NikShel
Offline
Зарегистрирован: 21.01.2018

ConstTimersPartialTest:

Функционирует. Но, как я понял это для Timer1

Но не все результаты совпадают с выданными калькулятором.

 

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

NikShel пишет:

Функционирует. 

Т.е. с int24 разобрались? Надо,, блин, убрать её оттуда, это Ворота выпендрился.

NikShel пишет:

Но, как я понял это для Timer1 ? 

Блин, ну там же в начале файла библиотеки полная документация, все написано! 

Это для любого таймера, номер таймера задаётся в первом параметре "timerTicksByFrequency(1, ..." и "prescalerBitsByFrequency(1, ..."

NikShel пишет:

Но не все результаты совпадают с выданными калькулятором.

Не обязано.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Спрошу здесь, дабы не плодить темы.
Можно ли заменить micros другой конструкцией в данном примере?

currentmicros = micros(); // текущее время
 if (currentmicros - previousmicros >= interval) {
/* мой код*/
}

Это работает на Ардуино, и на других атмегах, но упорно не хочет работать на Attiny13. Кроме того, зачем использовать две переменные unsigned long, когда мне нужно измерять интервалы времени до 200 микросекунд с точностью +-5 микросекунд.

Как я это вижу: при каждой проверке сравниваем значение счётчика с интервалом, и сразу же обнуляем счётчик, и так далее.

Мучаюсь уже сутки, но не получаю ожидаемого.

 

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

seri0shka пишет:

Как я это вижу: при каждой проверке сравниваем значение счётчика с интервалом, и сразу же обнуляем счётчик, и так далее.

 

это вы микрос хотите обнулять? - не выйдет, обходитесь без обнуления

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Нет, не микрос обнулять. Можно ли обойтись без микрос вообще?

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018
Green
Offline
Зарегистрирован: 01.10.2015
static uint16_t prev;
uint16_t curr = micros(); // текущее время
if (curr - prev >= INTERVAL) {
  prev = curr;
  /* мой код*/
}

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

attiny-1-series очень далеки от attiny13, это сравнительно новое поколение AVR, для них есть готовое ядро, поддерживающее в том числе и микрос, и на них у меня тоже всё работает. Также работает и на старушке attiny25, а на attiny13 отлично компилируется, но не отрабатывает микрос нормально, пробовал с несколькими разными ядрами (MicroCore и ещё три).

Объясню ещё раз свою задумку: таймер-счетчик Т0 (например) работает с предделителем, обеспечивающим переключение, скажем, каждые 2 микросекунды, прерывание по совпадению обнуляют таймер-счетчик Т0, к примеру, раз в 6 микросекунд, при каждом прерывании МОЙ СЧЁТЧИК (не таймер-счетчик) прибавляет значение. В основном цикле программы я в любой момент могу считать значение МОЕГО СЧЁТЧИКА, а также обнулить его. Таким образом, я смогу считать с дискретностью 6 мкс, что даёт интервалы до 255*6=1530 мкс, что меня вполне устраивает.

На самом деле у меня не получается

1 заставить таймер-счетчик сбрасываться по совпадению менее чем каждые 5 мкс, и цифры не соответствуют даташитам

2 МОЙ СЧЁТЧИК тоже ведёт себя не так как нужно.

Все опыты на Ардуино нано, прошивать каждый раз attiny13 задолбаешься.

 

Green, это всё у меня есть, на ардуино именно так и работает

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

Каждые 6 мкс по совпадению... Боюсь, не успеете.
Нужна полная схема и софт. Тогда только возможна помощь.

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

Green пишет:

Нужна полная схема и софт. Тогда только возможна помощь.

и лучше это сделать отдельной темой в разделе Программирования. Думаю что в теме для начинающих про миллис этот вопрос явный оффтоп

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Вот привожу испытательный код

 

int a;
void setup() {
  DDRB = 255;             // пины 8...13 - выходы
  noInterrupts();         // отключаем все прерывания
  TCCR0A = (1 << WGM01);  // режим таймера CTC
  TCCR0B = (1 << CS00);   // Тактировать без делителя
  OCR0A = 31;             // регистр сравнения
  TIMSK0|= (1 << OCIE0A); // включаем прерывание по совпадению
  TCNT0 = 0;              // счетный регистр 
  interrupts();           // разрешаем все прерывания
}
//ОБРАБОТЧИК ПРЕРЫВАНИЙ ПО ТАЙМЕРУ
ISR (TIMER0_COMPA_vect)
{
  TCNT0 = 0; a++; 
}

void loop() { 
  if (a > 10) { // переключаем порт в противоположное состояние
    a = 0;
    if (PORTB == 0)PORTB = 255;
    else PORTB = 0;
  }
}

Запускаю таймер-счетчик Т0 без делителя, значит он прибавляет своё значение каждые 62,5 наносекунд. По достижении значения 31 происходит прерывание, переменная а увеличивается на единицу, а таймер-счетчик обнуляется. В основном цикле я проверяю значение переменной а, если больше 10, инвертирую порт. Логическим анализатором проверяю выходы, вижу там меандр с периодом примерно 80 микросекунд. Хотя по моим расчётам должно быть 20 мксек. Но и это не всё. OCR0A можно увеличивать вплоть до 255, период импульсов тоже увеличивается примерно пропорционально. Но при уменьшении OCR0A меньше 31 период не уменьшается, а может даже увеличиваться почти в два раза, это мне не понятно. При уменьшении if (a > 10) до if (a > 1) тоже период уменьшается не сильно. Минимальный период 10 мксек удаётся получить при if (a > 0) и OCR0A= 31, меньше никак.

Это не совсем то, что мне нужно, но я уже вижу немного другое решение с тем же таймер-счетчиком Т0, о результатах напишу.

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Вот то, что я применил  в итоге.

int a;

void setup() {
  DDRB = 255;                   // пины 8...13 - выходы
  noInterrupts();               // отключаем все прерывания
  TCCR0A = (1 << WGM01);        // режим таймера CTC
  TCCR0B = (1<<CS00)|(1<<CS01); // Тактировать с делителем 64
  TIMSK0=0;                     // вЫключаем прерывание по совпадению
  interrupts();                 // разрешаем все прерывания
}

void loop() { 
  if (TCNT0 > 100) { // переключаем порт в противоположное состояние
    TCNT0 = 0;
    if (PORTB == 0)PORTB = 255;
    else PORTB = 0;
  }
}

Запускаю таймер-счетчик Т0 с делителем 64, он увеличивается каждые 4 мксек, в основном цикле просто сравниваю значение счётчика с заданным, при необходимости таймер-счетчик обнуляю. Можно измерять интервалы до 255*4=1020 мксек с дискретностью 4 мксек, что меня вполне устраивает.

Если предделитель установить 8, дискретность будет 0,5 мксек, измерять интервалы до 255*0,5=120 мксек.

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

seri0shka, а какая собссно конечная цель, что должно выполняться раз в 100 тактов? Вполне возможно что сама конечная задача не успеет отработаться за 100 тактов, и ситуация if (TCNT0 > 100) никогда не наступит или будет работать абы как. Поэтому принято, работая  с переполняющимся регистром проверять соответствующие флаги переполнения  в регистре TIFR.  Флаг никуда не убежит, и будет терпеливо ждать пока его прочтут.


int main() {
  DDRB |= 1<<DDB5; //pin13 -выход   
  TCCR0A = (1 << WGM01);        // режим таймера CTC
  TCCR0B = (1<<CS00)|(1<<CS01); // Тактировать с делителем 64
  OCR0A=99;// поднять флаг каждые 100 тактов
while(1) { 
  if (TIFR0&(1<<OCF0A)) { // если было совпадение
    TIFR0=(1<<OCF0A); //снять флаг
    PORTB^=1<<5; //переключаем порт в противоположное состояние
    }
   }
}

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

dimax пишет:
Вполне возможно что сама конечная задача не успеет отработаться за 100 тактов, и ситуация if (TCNT0 > 100) никогда не наступит

Ситуация if (TCNT0 > 100) никогда не наступит, если задача не успеет отработаться за 255 тактов. А вообще надо подумать, я не знал об этом флаге. Флаг поднимется после 99 такта от нулевого состояния счётчика или от момента снятия флага?

Ещё интересный момент: Все скетчи со счётчиком у меня не хотят работать с написанием

int main() {
  while (1) {
  }
}

но работают с написанием

void setup() {
}
void loop() {
}

 

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

seri0shka пишет:

Ещё интересный момент: Все скетчи со счётчиком у меня не хотят работать с написанием

int main() {
  while (1) {
  }
}

но работают с написанием

void setup() {
}
void loop() {
}

Действительно, интересный момент.

Помнится, у Ваенги тоже подобный был :-)

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

Ага, похоже абсент... Сначала миллис - "а, это я знаю", затем 6 мкс по совпадению, затем main()... Ужос!(

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

На американском форуме Вы задаете вопрос и Вам дают ответ.
На еврейском форуме Вы задаете вопрос и Вам задают встречный вопрос.
На русском форуме Вы задаете вопрос и Вам долго объясняют почему Вы такой мудак.

Именно поэтому я вопросы на форумах задаю крайне редко.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ты бы для начала свою тему создал, нафиг чужую засирать?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

seri0shka пишет:

...Вам долго объясняют почему Вы такой мудак.

Именно поэтому я вопросы на форумах задаю крайне редко.

Ну, если Вы и без форума это знаете, зачем тогда вообще вопросы задавать?

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

seri0shka пишет:

На американском форуме Вы задаете вопрос и Вам дают ответ.

Это точно, и у нас в песочнице есть пример такого ответа.