Страница 1 из 2

Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Ср апр 27, 2016 22:12:50
Browny
Уважаемые коты, мяу!
Прошу помощи и совета.
AtTiny24, 8MHz, тактирование от внутреннего генератора.
Делаю таймер TIM0 с обработкой переполнения. Цель - отсчёт интервалов 1 мсек.
Размышляю так: 8000000 тиков в секунду, 8000 тиков в мсек. Значит, если поставить делитель на 64, получим 125 тиков таймера. Смещаем стартовое значение таймера на 131, чтобы таймер сделал до переполнения именно 125 тиков.
Ставлю делитель на 64. При этом получаю контрольный интервал примерно в 8 раз позже ожидаемого значения.
Ставлю делитель на 8 - и (грубо считая секундомером) получаю правильное срабатывание (оцениваю интервал 20 тыс мсек).
Что-то делаю не так? Влияет ли фьюз CKDIV8 на первоначальную частоту таймера?

Спасибо за ваши советы и ответы.
Прилагаю тестовый пример (AVR Studio 4.19)

Код: Выделить всё

#define F_CPU 8000000UL
#include <avr/interrupt.h>
#include <util/delay.h>  

volatile uint32_t CNT32 = 0;

uint32_t millis(void){
	unsigned long m;
	uint8_t oldSREG = SREG;
	cli();
	m = CNT32;
	SREG = oldSREG;
    return m;
}

void StartTimer0()
{	
       cli();
	   TIMSK0 &= ~(1<<TOIE0); // выключить обработку по переполнению
       TCNT0  = 131;
       //TCCR0B = (1 << CS01) | (1 << CS00); //Делитель = 64; 8000000 Hz / 64 = 125 000 Hz; 125 000 Hz / 1000 = 125 ticks
	   TCCR0B = (1 << CS01); //Делитель = 8;
       TIMSK0|= (1 << TOIE0); // включить обработку по переполнению
	   sei();
}

ISR(TIM0_OVF_vect)
{
  CNT32++;
  TCNT0 = 131; // смещаем значение счётчика так, чтобы счётчику осталось сделать 125 тиков (256 - 125) до нового переполнения
  TIMSK0|= (1<<TOIE0);	//Продолжить отсчет, (разрешить прерывания по таймеру1)
};

void setup() 
{ 
  DDRA|= 0B00000010;
  PORTA&= 0B11111101; 
  StartTimer0();
}


void main() {
 setup();
 while (1) {
	if (millis() > 20000) PORTA |= 0B00000010;
 };
 return;
};

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 05:16:37
Z_h_e
Browny писал(а): Влияет ли фьюз CKDIV8 на первоначальную частоту таймера?
Однозначно.
Browny писал(а):Смещаем стартовое значение таймера на 131, чтобы таймер сделал до переполнения именно 125 тиков.
Лучше использовать один из режимов таймера, при котором происходит прерывание при значении таймера 125 и автоматический его сброс. Так будет точнее и короче обработчик прерывания.
Ставлю делитель на 8
Может наоборот выключаете? С фузами легко запутаться.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 05:56:19
Browny
Z_h_e, спасибо, и - да, режим, про который говорите - не CTC? Когда для TOP значение задаётся в OCRA? (таблица Waveform Generation Mode Bit Description в даташите).
Фьюзы, в данном случае, насколько я понял, инверсные (в студии). В противном случае, снятый RSTDSBL и установленный SPIEN стали бы для меня проблемой :)
Extended = 0xFF
High = 0xDF
Low = 0x62

Значит, получается, что мне надо "плясать" от частоты ядра, делённой на 8.... ок.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 08:21:44
Demiurg
Новые МК идут с запрограммированным фьюзом CKDIV8. Поэтому, всегда при первом программировании МК ставим у программатора низкую частоту, выставляем фьюзы как требуется. В студии фьюзы показываются как есть. Но так как у AVR установленный фьюз это сброшенный бит, то в стороннем программном обеспечении нужно учитывать что биты инверсные. Возможно уже и есть программы, которые показывают фьюзы как есть, но я при программировании МК никогда не пользовался самопальными, сторонними программаторами и соответствующими программами. Только фирменными программаторами и только в AVR-Studio.

Пример настройки таймера на 1 мс.

Код: Выделить всё

//==================
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0Comp(void)
{
   ST_OCR += 250;
   sys_tick++;
}
//==================

//==================
void init_soft_timers (void)
{
   sys_tick = 0;
   ST_TCNT = 0;
   ST_OCR = 250;
   ST_TCCR |= ((1<<CS0) | (1<<CS1));
   set_bit (ST_TIMSK, ST_OCIE);
}
При 16 МГц 250, при 8 Мгц 125. Это самая точная настройка. Эти настройки и кварцы я использую уже несколько лет. Если требуется UART и соответствующие кварцы (7,3728 к примеру), то точная дискретность уже получается 10 мс.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 08:59:40
Engineer_Keen
Чтобы не париться насчет фьюза CKDIV8, просто пишите в инициализации:

Код: Выделить всё

C:
	CLKPR=(1<<CLKPCE)
	CLKPR=0

ASM:
	LDI	R16,(1<<CLKPCE)
	OUT	CLKPR,R16
	LDI	R16,0
	OUT	CLKPR,R16

Это программно сбросит делитель, независимо от значения CKDIV8. Справедливо для всех контроллеров в регистром CLKPR.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 09:23:52
Demiurg
Engineer_Keen писал(а):Это программно сбросит делитель, независимо от значения CKDIV8. Справедливо для всех контроллеров в регистром CLKPR.
Причем здесь регистр CLKPR и фьюз CKDIV8?

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:12:31
Browny
Engineer_Keen, Demiurg - меня пока вполне устраивает частота 8Mhz / 8. Я ставлю делитель счётчика ещё на 8 и выхожу как раз на 125 тиков в 1 мсек.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:19:12
Demiurg
Browny писал(а):Engineer_Keen, Demiurg - меня пока вполне устраивает частота 8Mhz / 8. Я ставлю делитель счётчика ещё на 8 и выхожу как раз на 125 тиков в 1 мсек.
И? Вы намеренно замедлили мк, да еще прерывания каждые 125*8. По сути мк работает на 1 мгц. Смысл?

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:24:10
akl
Для более точного отсчета времени, производитель рекомендует заносить в OCRx значение на единицу меньше требуемого. Например, выдержка 1мс.
Спойлер

Код: Выделить всё

	.INCLUDE "tn24def.inc"

.equ	Fo=8000000
;.equ	Fo=16000000

.CSEG
.ORG 0x0000
	RJMP	START
;*************************************************
.ORG 0x0009
T0_COMPA:
	RETI
;*************************************************
;*************************************************
;*************************************************
;*************************************************
;*************************************************
START:
	SBI	ACSR,ACD

	LDI	R20,1<<SE
	OUT	MCUCR,R20
GO:
	SBI	DDRB,0

	LDI	R16,Fo/1000/64-1
	OUT	OCR0A,R16

	LDI	R16,1<<OCIE0A
	OUT	TIMSK0,R16
	OUT	TIFR0,R16

	LDI	R16,1<<WGM01
	OUT	TCCR0A,R16		; режим CTC

	LDI	R16,1<<CS01|1<<CS00
	OUT	TCCR0B,R16		; Fo/64
	CLT
	SEI
;********************
WAIT:
	SLEEP
	SBI		PINB,0	; переключатель 1 мс
	RJMP	WAIT
.EXIT

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:30:06
Demiurg
akl писал(а):...
Точные отмерения времени всегда подбираются исходя из условий. Ваши -1 верны для одного случая и не верны для другого. Точность зависит от частоты кварца, режима таймера, делителя, условий реакции прерывания и так далее.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:32:05
akl
Бред!!!

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 10:49:39
Demiurg
akl писал(а):Бред!!!
Это вы мне? Если да, в каком месте бред? Предлагаю вам прежде чем высказываться, обкатывать утверждения хотя бы в симуляторе студии.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 11:10:19
Browny
Demiurg, фьюз CKDIV8 уже был установлен. Пока для моей задачи мне хватает частоты 1МГц, если будут проблемы - или уберу фьюз, или программно поменяю делитель, как советовал Engineer_Keen. А прерывание 1 раз в 1 мсек мне нужно для обратной совместимости с настройками внешних событий, которые заданы как раз в мсек. И - да, обработка TIM0_COMP_vect будет ли более производительной, чем TIM0_OVF_vect со смещением в TCNT0?
И - да, в даташите на attiny24 написано, что OCR у TMR0 таки два, так что обработчик, думаю, TIM0_COMPA или TIM0_COMPB.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 11:37:56
Demiurg
Я регистром CLKPR никогда не пользовался. Также всегда сбрасывал фьюз CKDIV8.

CKDIV8 у вас уже установлен. Если он установлен, то дальше уже зависимость значения в CLKPR от CKDIV8. Также нужно точно убедиться, как тактируется таймер. Вполне возможно, что он тактируется помимо CLKPR.
Балуясь при CKDIV8 с регистром CLKPR можно попасть в ситуацию, что программатор не сможет перепрограммировать МК. Так как частота ядра окажется слишком маленькой.

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

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 12:03:56
akl
Demiurg писал(а):
akl писал(а):Бред!!!
Это вы мне? Если да, в каком месте бред? Предлагаю вам прежде чем высказываться, обкатывать утверждения хотя бы в симуляторе студии.
ИзображениеИзображение

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 12:09:08
Demiurg
Повторяю еще раз: ваши -1 верны для: делитель 64, режим, частота кварца. Для 10 МГц уже нужно сидеть, экспериментировать, чтобы получить эти же 1 мс. Наиболее точно можно получить только на 16 битном таймере. На UART кварцах вообще точность можно получить только для 10 мс. 7372800:1024=7200. Грузим в регистр сравнения 72, получаем 10 мс.
Опять же, вы не ответили, где бред. Я же не говорил вам, что вы не правы со своими -1.
И кстати, при вашем примере, если прогнать 100 раз, какова будет точность?
При моем примере всегда стабильный результат. Строго 1 мс, +- несколько тактов. Притом, если убежит в сторону на эти несколько тактов при одном прерывании, то при следующем прерывании разница убирается. И при 100 разах будет строго 100 мс +- несколько тактов.

Пример: на 50 мс было строго 50 мс. на 51 выбег на несколько тактов. Судя по всему был запрет прерывания или команда на несколько тактов.

Изображение

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 13:11:11
Browny
Demiurg, относительно тактирования TMR0 в разрезе AtTiny24 (выдержки из даташита):

страница 24: Figure 6-1. Clock Distribution: Crystal oscillator->Clock multiplexer->System clock prescaler->AVR Clock Control Unit
На выходе AVR Clock Control Unit идёт clkI/O

страница 116: Figure 13-2. Prescaler for Timer/Counter0: на входе у "10bit prescaler" clkI/O, на выходе мультиплексора clkT0

страница 30: касательно регистра CLKPR: "....it will affect the clock frequency of the CPU and all synchronous peripherals. clkI/O, clkADC, clkCPU, and clkFLASH".

Видимо, тактирование TMR0 для attiny24 учитывает CLKPR. Но вариант убрать фьюз, конечно, проще :)

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 13:36:30
Engineer_Keen
Demiurg писал(а):Я регистром CLKPR никогда не пользовался. Также всегда сбрасывал фьюз CKDIV8.
Часто новички, особенно при повторе чужих устройств, по неопытности меняют фьюзы так, что контроллер лочится (меняют SPIEN или RSTDSBL, или шьют без предварительного чтения), хотя в большинстве случаев автор требует всего-лишь убрать делитель на 8. Чтобы лишний раз не трогать фьюзы, проще один раз в программе сделать сброс делителя, и тогда эта программа залитая на новый МК будет работать на нужной частоте.
Demiurg писал(а):CKDIV8 у вас уже установлен. Если он установлен, то дальше уже зависимость значения в CLKPR от CKDIV8.
CLKPR просто при запуске устанавливается в то значение, которое прописано в CKDIV8. (т.е. либо /1, либо /8) Кстати программно можно поставить и другие делители!
Demiurg писал(а):Также нужно точно убедиться, как тактируется таймер. Вполне возможно, что он тактируется помимо CLKPR.
Вся цепочка тактирования: встроенный RC/кварц/генератор -> CLKPR -> CLKPS таймера, CLKPR тут никуда не денется, кроме случая тактирования от внешнего источника Tn.
Demiurg писал(а):Балуясь при CKDIV8 с регистром CLKPR можно попасть в ситуацию, что программатор не сможет перепрограммировать МК. Так как частота ядра окажется слишком маленькой.
Меняя CKDIV8 да, можно, либо поставив CKDIV8 в паре с каким-либо низкочастотным источником тактирования, либо просто при ошибочной записи других бит в этот фьюз. А вот при изменении CLKPR ничего страшного не случится - данные в него загружаются после сброса при старте программы, а при введении в режим программирования программа не начинает работу по определению.
Demiurg писал(а):Если все же зачесалось, тогда курите даташит и досконально разбирайтесь, как это все работает.
Вот вот, и сами заодно его покурите, прежде чем (см. ниже)...
Demiurg писал(а): Потому что лично мне такие извращения не нужны были, и я не разбирался что такое регистр CLKPR и как он работает. Товарищ, который вам его посоветовал, походу тоже не разобрался и советует кому ни попадя.
Browny писал(а):Видимо, тактирование TMR0 для attiny24 учитывает CLKPR. Но вариант убрать фьюз, конечно, проще :)
Все верно. Если нужно менять еще какие-либо фьюзы (например BOD или EESAVE), то да имеет смысл поменять фьюз, а если нужен только CKDIV8, то ИМХО проще программно, один раз.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 13:43:51
Z_h_e
Demiurg писал(а):Причем здесь регистр CLKPR и фьюз CKDIV8?
The CKDIV8 Fuse determines the initial value of the CLKPS bits. If CKDIV8 is unprogrammed,
the CLKPS bits will be reset to “0000”. If CKDIV8 is programmed, CLKPS bits are reset to
“0011”, giving a division factor of eight at start up.
Browny писал(а):режим, про который говорите - не CTC?
Он. Но можно использовать FAST PWM 7ой режим. Тогда еще от этого же таймера можно ШИМ задействовать, если конечно частота ШИМ будет устраивать.

Re: Нужна помощь: таймер TIM0, AtTiny24

Добавлено: Чт апр 28, 2016 14:34:38
Demiurg
Engineer_Keen писал(а):Вот вот, и сами заодно его покурите, прежде чем (см. ниже)...
Если вы посмотрите историю моих сообщений, вы не увидите от меня вопросов, которые касаются азов. Прежде чем использовать что-то, что я до этого не использовал, я всегда предварительно изучу тему. Буду читать даташиты, различные материалы.
Если вы хотели ткнуть меня носом, то позвольте заметить, использовать фьюз делитель на 8, чтобы добиться 1 мс, это уже извращение. А ваш совет использовать регистр не сбрасывая фьюз - извращение вдвойне.
Если кто-то хочет экспериментировать, то пусть это делает не компостируя другим мозги.
В случае с ТС нет никаких моментов, которые вынуждали бы его использовать как делитель на 8 так и регистр.