Запуск Таймера-счетчика из прерывания INT0

Обсуждаем контроллеры компании Atmel.
Ответить
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Вы бы сначала определились на каком МК проект будете выполнять. Я не с 26 не с 261 не работал. Они несколько отличаются от "классических" avr. Глянул ДШ между 26 и 261 (ну или 461) есть существенные отличия. Хотя бы у 26 таймер1 8битный, а у 261 10битный. У последнего таймер имеет больше режимов.

В протеусе я не увидел наличие модели для 26. У Вас проект для какого МК компилируется?

Попробуйте в реальный МК залить. Говорю ж есть глюки в протеусе с прерываниями по сравнению.

Добавлено after 30 minutes 27 seconds:
Попробовал я вот такой код для 261.

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

ISR(TIMER1_COMPA_vect){ //timer
	
	PINA=1;
}

//*****************************************8
int main(void)
{
	DDRA=1<<PA0;
	//PINA=1;
	
	//TC1H=0; 
	OCR1A=0x80;
	TCCR1B=1<<CS13;
	TIMSK=1<<OCIE1A;
	
	asm("sei");
	while(1);
}
В студии срабатывает прерывание, в протеусе, как я и говорил, нет.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Железо будет на 26тиньке, а всю отладку программы пока пишу и компилирую на 461.

Добавлено after 35 seconds:
Эхх шпротеус такой шпротеус. )
andrei23061996@gmail.com
.................................................................................................................
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

7seg писал(а):Железо будет на 26тиньке, а всю отладку программы пока пишу и компилирую на 461.
Мощно. Почему бы не сделать отладку на Меге для tiny26 :) ?
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

А какую мегу лучше выбрать чтобы потом было проще интерпретировать в 26 тиню ?
andrei23061996@gmail.com
.................................................................................................................
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

Пошутил же я. Пишите сразу для целевого мк. Ну или сразучитайте оба дш и сравнивайте, чтобы сразу понимать разницк
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Эхх с юмором тяжковато с таким головником :))) :)))

Пока для себя тоже решил что буду сразу на железе испытывать и писать на 26тиню. )

пока что отказался от вектора сравнения, пробую сделать на векторе переполнения прерывания для активации триака.

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

мб кто подскажет где ошибочка ? :oops: :oops:
Спойлер

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

#define F_CPU   8000000          //Hz

#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>

#define T0_TICK_RATE    1000     // Hz
#define T0_CLK  ((F_CPU)/1024)
#define T0_TICKS  (0x100 - T0_CLK / T0_TICK_RATE)

#define DEBOUNCE_TIME 			20

#define BUTTON_PIN 				PINB
#define POWER_BIT				PB3
#define UP_BIT					PB4
#define DOWN_BIT				PB5

#define KEY_POWER			0b00001000
#define KEY_DOWN			0b00100000
#define KEY_UP				0b00010000



#define  En_INT0      GIMSK|=(1<<6);
#define  Dis_INT0     GIMSK&=~(1<<6);     // выключаем прерывание INT0




volatile unsigned char data1=0;
volatile unsigned char data2=0;
volatile unsigned char value;
volatile int _buzzer = 0;
volatile int _pressed = 0;

volatile unsigned char sw=0;

void init_io();
void segchar(unsigned char seg);
void handle_button(int key);
void handle_buttons();
void process_power();
void process_up();
void process_down();

//настройка внешнего прерывни§ INT0
void int0_init( void )
{
	//настраиваем на срабатывание INT0 по переднему фронту
	MCUCR |= (1<<ISC01)|(0<<ISC00);
	//разрешаем внешнее прерывание INT0
	En_INT0
}


ISR(INT0_vect)
{
	sw=1;
	static unsigned char count = 0;
	//гасим оба разр§да
	PORTB |=(1<<PB0);
	PORTB |=(1<<PB2);
	PORTA = 0b11111110;
	//зажигаем следующий разр§д
	if (count == 0)
	{
		segchar(data2);
		PORTB &= ~(1<<2);
	}
	if (count == 1)
	{
		segchar(data1);
		PORTB &= ~(1<<0);
	}
	count++;
	if (count == 2) count = 0;

}

int main(void)
{
	value=0;
	init_io();
	sei();
	int0_init();
	while(1)
	{
		handle_buttons();
	}
	return 0;
}


void segchar (unsigned char seg)
{
	switch (seg)
	{
		case 1: PORTA = 0b01111100; break;
		case 2: PORTA = 0b10000100; break;
		case 3: PORTA = 0b01000100; break;
		case 4: PORTA = 0b01101000; break;
		case 5: PORTA = 0b01000010; break;
		case 6: PORTA = 0b00000010; break;
		case 7: PORTA = 0b01110100; break;
		case 8: PORTA = 0b00000000; break;
		case 9: PORTA = 0b01000000; break;
		case 0: PORTA = 0b00010000; break;
	}
}

void init_io()
{
	//порт, к которому подкл. сегменты
	PORTA = 0xff;
	DDRA = 0xff;
	//порт, к которому подкл. катод
	DDRB |=(1<<0)|(1<<1)|(1<<2);
	PORTB =0x00;
	//инициализаци§ таймера У0
	TIMSK = (1<<TOIE1);
	TCCR1B=(1<<CS10)|(1<<CS11)|(1<<CS12);   // правка на 461
	TCNT1=0xF3;  //правка на  461
	//иницилизаци§ прерываний
	
}

volatile unsigned char lvl=0;
ISR(TIMER1_OVF1_vect)  
{
	//cli();
	TCNT1=0xF3;
	if (sw==1)
	{
		lvl++;
		if (lvl==(value))
		{
			for(int k=0; k<5; k++)
			{
				PORTB |= (1<<1);
				_delay_us(9);
				PORTB &= ~(1<<1);
				_delay_us(1);
			}
			sw=0;
		}
		
	}
}

void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_POWER: bit = POWER_BIT; break;
		case KEY_UP: 	bit = UP_BIT; break;
		case KEY_DOWN: 	bit = DOWN_BIT; break;
		default: return;
	}

	if (bit_is_clear(BUTTON_PIN, bit))
	{
		if (_pressed == 0)
		{
			_delay_ms(DEBOUNCE_TIME);
			if (bit_is_clear(BUTTON_PIN, bit))
			{
				_pressed |= key;
				
				// key action
				switch (key)
				{
					case KEY_POWER: process_power(); break;
					case KEY_UP: 	process_up(); break;
					case KEY_DOWN: 	process_down(); break;
				}
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}

void handle_buttons()
{
	handle_button(KEY_POWER);
	handle_button(KEY_DOWN);
	handle_button(KEY_UP);
}

void process_power()
{

}
void process_up()
{
	if (value < 99)
	{
		value++;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}
void process_down()
{
	if (value > 0)
	{
		value--;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}
Добавлено after 8 minutes 6 seconds:
Пока что понял что у меня ошибка как минимум в работе вектора переполнения, походу не совсем правильно рассчитал его. поэтому живой осциллограф показывает что синхра на оптрон приход раз в несколько полу периодов.

Добавлено after 46 minutes 22 seconds:
А может кто подсказать формулу для расчета пределителя и TCNT1

Добавлено after 5 minutes 51 second:
Еще нашел кое что )) переменную lvl то я не обнуляю не фига..
andrei23061996@gmail.com
.................................................................................................................
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18678
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

7seg писал(а):А может кто подсказать формулу для расчета пределителя и TCNT1
а в чем проблема-то?
я бы вообще не советовал слишком увлекаться формулами, потому как в Си некоторые формулы вычисляются несколько неожиданно для многих... лично я всегда рассчитываю конкретные значения сам (при помощи калькулятора Windоws) и вбиваю в проект уже готовые констаты.

кстати о константах: категорически советую убрать из вашего файла #define F_CPU 8000000, а вместо этого задавать частоту в настройках проекта, как положено.

а теперь о расчете таймера.

нам известна частота тактирования МК и частота прерываний, которую мы хотим получить. отношение этих частот - это коэффициент деления, который надо реализовать. допустим, при тактовой 8 МГц мы хотим получить прерывания с частотой 1000 Гц. Значит, нам над обеспечить коэффициент деления 8000.

этот коэффициент может обеспечиваться разными способами. проверим, что будет, если мы напрямую затактируем таймер и будем работать по прерываниям по переполнению: 8000000 / 256 = 31250 - это в 31.25 раз больше, чем мы хотим. к сожалению, поделить на 31.25 невозможно никак, поэтому как бы мы ни старались, при работе по переполнению таймера (8-битного я взял, для 16-битного все чуть иначе, но принцип тот же) получить 1000 Гц невозможно.

В сущности задача сводится к подбору множителей для получения желаемого значения 8000: среди этих множителей могут быть значения предделителя таймера и значения для счетчика в режиме CTC таймера. Вы же помните, что в режиме СТС таймер считает до меньшего, чем его "размер" значения? т.е. можно поделить частоту на любое целое значение, умещающееся в разрядность таймера. например 8000 = 8 * 1000 (8 - стандартный предделитель, а вот 1000 влезет только в 16-битный таймер). 8000 = 125 * 64 - это нас устраивает! 64 - стандартный предделитель, а 125 мы будем использовать для режма CTC таймера!

вот оно - решение: для 8-битного таймера в режиме СТС надо указать значение для счета TOP=125, задать предделитель 64 и тогда прерывание ПО СОВПАДЕНИЮ (не по переполнению!!!) будет возникать ровно 1000 раз в секунду!

Аналогично рассуждая вы должны легко получить любые желаемые частоты прерываний при своих параметрах проекта. Если целое значение частоты недостижимо, стремитесь к максимально близкому достижимому целому, либо меняйте алгоритм...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

[uquote="ARV",url="/forum/viewtopic.php?p=3103268#p3103268"]кстати о константах: категорически советую убрать из вашего файла #define F_CPU 8000000, а вместо этого задавать частоту в настройках проекта, как положено.[/uquote]

Частота я как понял задаётся фьюзами. а этот дефайн как я где то читал нужен для библиотеки delay.h. Хотя мб я просто не понял про настройки проекта.

а за объяснение расчетов большое спасибо.
andrei23061996@gmail.com
.................................................................................................................
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18678
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

F_CPU требуется для корректной работы delay.h - это верно.
Но правильно задавать эту константу не в одном или нескольких файлах исходников, а глобально для всего проекта. Глобально это делается заданием опции -DF_CPU=8000000UL для компилятора - и это есть единственно правильный вариант. А опция эта автоматически добавится компилятору, если вы правильно настроите свойства проекта в IDE - я не знаю, какая у вас она, но если она этого не умеет, сделать это придется в makefile.

Внутри файлов исходников эта константа не должна определяться!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Сообщение ozonn »

разве F_CPU влияет еще на что-то, кроме delay?
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Среда то AtmelStudio 6. как только заставлю работать этот димер так начну разбираться в настройках IDE ) а пока что весь проект из одного .с файла думаю это не критично.
andrei23061996@gmail.com
.................................................................................................................
akl
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

По мне, проще работать во временной области. Например, как Ваша задача будет в ней выглядеть
OCR1A=100*F_CPU/8/1000000-1 задание 100 мкс интервала таймера в режиме CTC или TCNT0=(-100*F_CPU/8/1000000) для таймера, не поддерживающего режим CTC; в каждом прерывании по переполнению значение TCNT0 нужно устанавливать.
Собутыльник Кота
Аватара пользователя
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Сообщение Z_h_e »

7seg, замечу что в режиме СТС прерывания по сравнению в Протеусе будут работать.

Еще раз замечу, что контроллеры 26 и 261 разные.

У 26ого оба таймера 8 битные. Таймер 0 только нормальный режим, Таймер 1 имеет другие режимы работы, в том числе СТС.

У 261 Т0 - 16битный, Т1-10 битный. У Т1 режима СТС что-то я не нашел.

Т.е. отладив на 461, портировать на 26 может быть сложная или невозможная задача.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Спасибо за советы, я тоже сделал вывод что если в наличии 26ойМК то на него сразу и надо писать. Завтра попробую свой Старый код где задержка включения была реализована через _delay_us переписать на режим СТС.
andrei23061996@gmail.com
.................................................................................................................
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 303
Зарегистрирован: Ср май 03, 2017 03:22:26

Сообщение 7seg »

Можете помочь разобраться в дш 26тиньки.

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

The Output Compare Register C is an 8-bit read/write register.
The Timer/Counter Output Compare Register C contains data to be continuously compared with Timer/Counter1. 
A compare match does only occur if Timer/Counter1 counts to the OCR1C value. 
A software write that sets TCNT1 and OCR1C to the same value does not generate a compare match.
If the CTC1 bit in TCCR1B is set, a compare match will clear TCNT1 and set an Overflow Interrupt Flag (TOV1).
 The flag is set after a synchronization delay following the compare event.
This register has the same function in normal mode and PWM mode.

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

The Output Compare Register B is an 8-bit read/write register.
The Timer/Counter Output Compare Register B contains data to be continuously compared with Timer/Counter1.
 Actions on compare matches are specified in TCCR1A.
 A compare match does only occur if Timer/Counter1 counts to the OCR1B value.
 A software write that sets TCNT1 and OCR1B to the same value does not generate a compare match.
A compare match will set the compare interrupt flag OCF1B after a synchronization delay following
the compare event.

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

The Output Compare Register A is an 8-bit read/write register.
The Timer/Counter Output Compare Register A contains data to be continuously compared with
Timer/Counter1. Actions on compare matches are specified in TCCR1A. A compare match does
only occur if Timer/Counter1 counts to the OCR1A value. A software write that sets TCNT1 and
OCR1A to the same value does not generate a compare match.
перевод:

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

Регистр сравнения вывода C представляет собой 8-разрядный регистр чтения / записи.
Регистр сравнения выходных данных таймера / счетчика C содержит данные, которые необходимо непрерывно сравнивать с таймером / счетчиком1.
Сравнение сопоставления происходит только в том случае, если таймер / счетчик1 подсчитывает значение OCR1C.
Программная запись, которая устанавливает TCNT1 и OCR1C в одно и то же значение, не генерирует сравнение.
Если бит CTC1 установлен в TCCR1B, сравнение сравнивает TCNT1 и устанавливает флаг прерывания переполнения (TOV1).
  Флаг устанавливается после задержки синхронизации после события сравнения.
Этот регистр имеет такую же функцию в нормальном режиме и режиме ШИМ.
Как я понял таймер1 умеет производить прерывания при сравнение OCR1C и TCNT1 .
И режим СТС1 есть только у OCR1C а про OCR1A/OCR1B не имеют такой возможности.

регистры OCR1A\OCR1B настраивается в TCCR1A. который не имеет как раз функции СТС.

Значит для вызова прерываний по сравнению надо брать TCCR1B и настроить его как (1<<CTC1) ,+ пределитель .
Также разрешить в TIMSK (1<<OCIE1B).

А время срабатывания прерывания TIMER1_CMPB_vect регулировать изменением OCR1B от 00 до 255.

Еще не могу понять как запустить счет таймера TCNT1 из прерывания ИНТ0 ?. чтобы можно было контролировать вызов прерывания TIMER1_CMPB_vect . регистром OCR1C из прерывания по ИНТ0.

Может кто подсказать ? или привести пример кода с коментами, а то что то совсем запутался .

Добавлено after 52 minutes 6 seconds:
Пока что работает полностью этот код:
Спойлер

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

#define F_CPU   8000000          //Hz

#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>

#define DEBOUNCE_TIME 			10

#define BUTTON_PIN 				PINB
#define POWER_BIT				PB3
#define UP_BIT					PB4
#define DOWN_BIT				PB5

#define KEY_POWER			0b00001000
#define KEY_DOWN			0b00100000
#define KEY_UP				0b00010000

#define  En_INT0      GIMSK|=(1<<6);
#define  Dis_INT0     GIMSK&=~(1<<6);     // выключаем прерывание INT0

volatile unsigned char data1=0;
volatile unsigned char data2=0;
volatile unsigned char value;
volatile int _buzzer = 0;
volatile int _pressed = 0;

volatile unsigned char sw=0;

void init_io();
void segchar(unsigned char seg);
void handle_button(int key);
void handle_buttons();
void process_power();
void process_up();
void process_down();



//настройка внешнего прерывния INT0
void int0_init( void )
{
	//настраиваем на срабатывание INT0 по переднему фронту
	MCUCR |= (1<<ISC01)|(0<<ISC00);
	//разрешаем внешнее прерывание INT0
	En_INT0
}

ISR(TIMER1_CMPA_vect)
{ 
	if (sw==1)
	{
		PORTB |= (1<<1);
		_delay_us(9);
		PORTB &= ~(1<<1);
		_delay_us(1);
		PORTB |= (1<<1);
		_delay_us(9);
		PORTB &= ~(1<<1);
		_delay_us(1);
	}
	sw=0;
}
//Прерывания по инт0 от синхра импулса
ISR(INT0_vect)
{
	OCR1A =(158-value);
	TCNT1 = 0;
	sw=1;
	static unsigned char count = 0;
	//гасим оба разр§да
	PORTB |=(1<<PB0);
	PORTB |=(1<<PB2);
	PORTA = 0b11111110;
	//зажигаем следующий разр§д
	if (count == 0)
	{
		segchar(data2);
		PORTB &= ~(1<<2);
	}
	if (count == 1)
	{
		segchar(data1);
		PORTB &= ~(1<<0);
	}
	count++;
	if (count == 2) count = 0;

}

int main(void)
{
	value=0;
	init_io();
	sei();
	int0_init();
	while(1)
	{
		handle_buttons();
	}
	return 0;
}

//Коды сегментов
void segchar (unsigned char seg)
{
	switch (seg)
	{
		case 1: PORTA = 0b01111100; break;
		case 2: PORTA = 0b10000100; break;
		case 3: PORTA = 0b01000100; break;
		case 4: PORTA = 0b01101000; break;
		case 5: PORTA = 0b01000010; break;
		case 6: PORTA = 0b00000010; break;
		case 7: PORTA = 0b01110100; break;
		case 8: PORTA = 0b00000000; break;
		case 9: PORTA = 0b01000000; break;
		case 0: PORTA = 0b00010000; break;
	}
}

void init_io()
{
	//порт, к которому подкл. сегменты
	PORTA = 0xff;
	DDRA = 0xff;
	//порт, к которому подкл. катод
	DDRB |=(1<<0)|(1<<1)|(1<<2);
	PORTB =0x00;
	//Иницилизация прерываний по совпадению Т1.
	TIMSK |=(1<<OCIE1A);
	TCCR1B |=/*(1<<CTC1)*/(0<<CS10)|(1<<CS11)|(0<<CS12)|(1<<CS13);   
	OCR1A=0xFF;
}
//Обраюотчик кнопок
void handle_button(int key)
{
	int bit;
	switch (key)
	{
		case KEY_POWER: bit = POWER_BIT; break;
		case KEY_UP: 	bit = UP_BIT; break;
		case KEY_DOWN: 	bit = DOWN_BIT; break;
		default: return;
	}

	if (bit_is_clear(BUTTON_PIN, bit))
	{
		if (_pressed == 0)
		{
			_delay_us(DEBOUNCE_TIME);
			if (bit_is_clear(BUTTON_PIN, bit))
			{
				_pressed |= key;
				
				// key action
				switch (key)
				{
					case KEY_POWER: process_power(); break;
					case KEY_UP: 	process_up(); break;
					case KEY_DOWN: 	process_down(); break;
				}
			}
		}
	}
	else
	{
		_pressed &= ~key;
	}
}

void handle_buttons()
{
	handle_button(KEY_POWER);
	handle_button(KEY_DOWN);
	handle_button(KEY_UP);
}

void process_power()
{
	value=90; //временная переменная для отладки.
}
void process_up()
{
	if (value < 99)
	{
		value++;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}
void process_down()
{
	if (value > 0)
	{
		value--;
		unsigned char tmp;
		tmp = value % 10;
		data1 = tmp;
		tmp = value/10;
		data2= tmp;
	}
}

Но почему-то я сомневаюсь что это правильное решение .

Добавлено after 22 minutes 36 seconds:
Снял показания прибором, не совсем хорошо получается(( изменение выходного напряжения на симисторе идет от 0 до 200 вольт.

Добавлено after 2 minutes 30 seconds:
Как думаете сделать массив для OCR полезных значений будет ли выходом. или все таки надо режим СТС прикручивать и под него уже делать расчеты ?
andrei23061996@gmail.com
.................................................................................................................
Ответить

Вернуться в «AVR»