Влияние Т0 на delay()

dim3740
Offline
Зарегистрирован: 25.03.2015

Статей про delay() как грязи.... Но  опять не пойму:

В цикле есть delay(3000). Он устраивает меня на все 100%. Пусть все зависнет. Но есть еще Таймер 0, с прерыванием. Так вот вопрос: почему в определенных случаях (разная уставка сравнения Т0) у меня дилей не работает? Код просто "проскакивает его"(((( Пробовал перед делеем ставить запрет прервания, а после снова разрешал - не помогает...

Прошу совета решения. 

vvadim
Offline
Зарегистрирован: 23.05.2012

код покажите, только вставьте по нормальному и отформатируйте.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

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

dim3740
Offline
Зарегистрирован: 25.03.2015

Читал, что, якобы, Т0 системно генерирует 1 мс. И она используется в делей().

Тогда вопросы: 1) Перво наперво в сети должны все писать " Делей и применение т0 недопустимо!!. Но я такого не наблюдаю... 2) Когда Т0 "перестает" быть 1мс-ундным? Когда его программно инициализируем для своих задач? 3) Если я расчитаю уставку тоже точно в 1 мс - то delay() заработает? 

Т.е. проблема: у меня не работает делей() Это первично. И я предполагаю, что это связано именно с юзанием Т0. Хотя у меня куча прерываний, и код длинный, и делей может НЕ выполняться по причине другого прерывания.

Я хочу понять и исключить влияние Т0, если оно может иметь место. 

nik182
Offline
Зарегистрирован: 04.05.2015

Дык, таймер 0 системный. Он работу миллисов и делеев обеспечивает. Если их используешь таймер 0 лучше не трогать. Есть же первый и второй. Или сам делай пиши. 

nik182
Offline
Зарегистрирован: 04.05.2015

Таймер 0 генерит прерывание каждые 4 мкс. 

dim3740
Offline
Зарегистрирован: 25.03.2015

Ну ты подтверждаешь мои предположения.... На 1 из 10 постов в сети только пишут что Т0 системный. Хотя это очень важно. Далее. Что значит "лучше не трогать"? У меня все занято((( Ок, счас попробую погуглить как программно 3 сек сделать(((

dim3740
Offline
Зарегистрирован: 25.03.2015

nik182 пишет:

Таймер 0 генерит прерывание каждые 4 мкс. 

Спасибо. Пока это мне ни о чем не говорит правда.... Внутренние что ли прерывания? Для дилей и милиса? Для меня меня прерывание  - это переход в его обработчик.

dim3740
Offline
Зарегистрирован: 25.03.2015

dim3740 пишет:

nik182 пишет:

Таймер 0 генерит прерывание каждые 4 мкс. 

Спасибо. Пока это мне ни о чем не говорит правда.... Внутренние что ли прерывания? Для дилей и милиса? Для меня меня прерывание  - это переход в его обработчик. Дя еще и при условии разрешения и т.п.

nik182
Offline
Зарегистрирован: 04.05.2015

Да переход в обработчик. Уже в обработчике строят значения для микрос и миллис. Открой файлы ядра ардуино и посмотри на прерывание таймера 0.  

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

Вот, бл.., очень тяжело посмотреть код в  .../hardware/arduino/avr/cores/arduino/wiring.c !!!!!!

Вот обработчик прерывания:

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
	// copy these to local variables so they can be stored in registers
	// (volatile variables must be read from memory on every access)
	unsigned long m = timer0_millis;
	unsigned char f = timer0_fract;

	m += MILLIS_INC;
	f += FRACT_INC;
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
		m += 1;
	}

	timer0_fract = f;
	timer0_millis = m;
	timer0_overflow_count++;
}

вот инициализация таймера: если хоть раз в жизни прочитать даташит, то это fastpwm и делитель на 64.

	// this needs to be called before setup() or some functions won't
	// work there
	sei();
	
	// on the ATmega168, timer 0 is also used for fast hardware pwm
	// (using phase-correct PWM would mean that timer 0 overflowed half as often
	// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
	sbi(TCCR0A, WGM01);
	sbi(TCCR0A, WGM00);
#endif

	// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
	// CPU specific: different values for the ATmega128
	sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
	// this combination is for the standard atmega8
	sbi(TCCR0, CS01);
	sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
	// this combination is for the standard 168/328/1280/2560
	sbi(TCCR0B, CS01);
	sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
	// this combination is for the __AVR_ATmega645__ series
	sbi(TCCR0A, CS01);
	sbi(TCCR0A, CS00);
#else
	#error Timer 0 prescale factor 64 not set correctly
#endif

	// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
	sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
	sbi(TIMSK0, TOIE0);
#else
	#error	Timer 0 overflow interrupt not set correctly
#endif

вот код delay()

void delay(unsigned long ms)
{
	uint32_t start = micros();

	while (ms > 0) {
		yield();
		while ( ms > 0 && (micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

===================

а теперь ВНИМАНИЕ, для таких, как ты, ТС, есть _delay_ms() прямо в arv-libc. У нее есть хитрости, но должен же ты, хоть что-то сам найти в сети.

dim3740
Offline
Зарегистрирован: 25.03.2015

_delay_ms() 

вот это меня вполне устроило. Спасибо. В AVR6 применяю его. Не думал, что компилятор Ардуино его распознает. 

nik182
Offline
Зарегистрирован: 04.05.2015

Хочу заметить, что делей содержит замечательную слабую подпрограмму yield(), которую можно переопределить и во время делея заниматься чем то нужным. Т.е. заложена кое какая много задачность :-)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

dim3740 пишет:

Не думал 

Так ото ж!

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Никакой многозадачности, но хук сам посебе условно полезный. Там есть только одна проблемка пользования им, а именно: время исполнения этого хука будет существенно влиять на точность delay() и она (точность) будет сильно зависеть от того, что там вызывается. А поскольку часто специально вызывать нечего, то можно (казалось бы) вызывать loop() .. ан нет, не на прямую (рекурсия, а стек не резиновый).

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

P.S. На самом деле, практика показывает что стиль программирования "c delay()" - это ущербность от непонимая процессов управления и работы микроконтроллера. При нормальном автоматном подходе - "скрипач не нужен".. :)

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

wdrakula пишет:
очень тяжело посмотреть код

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

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Arhat109-2 пишет:
время исполнения этого хука будет существенно влиять на точность delay()
Это если мозгов нет. Но когда их нет, то и без yield'а будет всё хреново, а когда есть - то ничего, нормально всё с точностью.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Тут мозгов ни у кого нет. Проверено неоднократно. :)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Бред. Методика проверки? Приборы сертифицированы? Кое у кого мозги есть, но не у всех, конечно, это точно.

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

Разве два килобайта - это мозги? :(

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Ну, какие-никакие.

А некоторые, Архат, например, так только с восемью килобайтами работают.

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

Я сейчас с 96 работаю - все равно не жирно :(.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Архат уже как с год работает с 512 килобайтами .. ваще-то. :)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Так ото ж. А некоторые тут "два, два"!