T/C2

Здесь все вопросы по языку программирования С
AVRIK
Сообщения: 146
Зарегистрирован: 24 сен 2016, 11:25
Откуда: Тбилиси

T/C2

Сообщение AVRIK » 24 сен 2016, 11:58

Приветствую вас! Есть задача и желание разобраться с таймером, но столкнулся с проблемой на решение которого не хватает опыта или информации. Подскажите кто сталкивался и разобрался с такой задачей.
По существу: В "теле" прерывания INT0 нужно произвести два действия по прерыванию от T/C2. В начале "тела" прерывания INT0 устанавливаем ПИНС.0 в лог"0", а по прерыванию от T/C2 установить ПИНС.0 в лог"1".
Среда разработки ATMEL STUDIO 6. Язык:"СИ". Камень ATMEGA8.


/*
* Atmega8_decoder_zvonok.c
*
* Created: 14.09.2016 21:42:57
* Author: SUN
*/

#define F_CPU8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

//**********************************************************************8


void int0_set(void)
{
MCUCR &= ~( (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00) ); //сбрасываем все биты ISCxx
MCUCR |= (1<<ISC01)|(1<<ISC00); //настраиваем на срабатывание INT0 по переднему фронту
GICR |= (1<<INT0); //разрешаем глобальное прерывание
GIFR|=(1<<INTF0); //опрос вектора на разрешения запрета прерывания

}

void pauza_set (void)
{
TCNT2=50; //число/старт отсчета до числа OCR2
TIMSK|=(1<<OCIE2); // по совпадению
OCR2=150; // число по совпадению TCNT2=OCR2
TCCR2|=(1<<WGM21); // режим CTC;
TCCR2|=(1<<CS20); // prescaler
}

void puls_set(void)
{

TCNT2=0; //число/старт отсчета до числа OCR2
TIMSK|=(1<<OCIE2); // по совпадению
OCR2=200; // число по совпадению TCNT2=OCR2
TCCR2|=(1<<WGM21); // режим CTC;
TCCR2|=(1<<CS20); // prescaler
}

ISR( INT0_vect )
{
pauza_set (); // инициировали и запустили условия pauza_set();
}

ISR(TIMER2_COMP_vect) //при pauza_set=0; т.е. по истечении времени обусловленного pauza_set();
{
PORTC|=(1<<1); // тестовый импульс на ПИНС0 для контроля срабатывания INT0
PORTC&=~(1<<1); //"------------------------------------------------------------------------------------"
unsigned char pauza; // инициализация локалной переменной (иначе ругается)!
if (!pauza) // если pauza=0
{
PORTC|=(1<<0); // лог"1"
pauza++; // pauza=1;
puls_set(); // запускаем условия puls_set; (отсчитав обусловленное время, возврашается к условию if)
}
else
{
PORTC&=~(1<<0); // проверив условие if, т.к.pauza=1, сработает условие else. (НЕ СРАБАТЫВАЕТ!!!!)
}
TCCR2=0;
TIMSK=0;
}

int main(void)
{
DDRD&=0x00; //0;//все пины на вход, в том числе и пин на котором прерывание
PORTD&=0x00;
PORTD|=(1<<2); //подтягивоющий резистор.
DDRB|=0xFF;
PORTB&=0x00;
DDRC|=0xFF;
PORTC&=0x00;
int0_set(); //запустили инициализацию прерывания.
sei(); //глобально разрешили прерывания

while(1)
{
asm("nop");
}

}

Проблема в том, что после срабатывания таймера по условию PORTC&=~(1<<0); вторая часть, условие при котором PORTC|=(1<<0); не работает, не отражает величины TCNT2 / OCR2.
Тут ниже для наглядности картинка с протеуса. INT0-работает, pauza_set(); отрабатывает свое время(ПИНС.1)
А puls_set(); только отмечается!




Снимок.PNG
17 часов назад Жалоба
Вложения
Снимок.PNG
Снимок.PNG (3.23 КБ) 5892 просмотра

Аватара пользователя
gurvinok
Сообщения: 1539
Зарегистрирован: 02 мар 2013, 09:18
Откуда: Москва

Re: T/C2

Сообщение gurvinok » 25 сен 2016, 12:53

Для начала нужно заглянуть в документацию на микросхему на страницу 44 и посмотреть карту векторов прерывания.
interrup.jpg
И убедиться что вектор INT0 стоит вторым после RESET по приоритету, а это значит что пока МК сидит в теле прерывания INT0, прерывания от таймера никогда не произойдет. Для решения задачи нужно просто в теле INT0 выставлять флаг, а по флагу дрыгать ногами в теле обработчика прерывания таймера.
Если долго мучиться, может быть получится.

AVRIK
Сообщения: 146
Зарегистрирован: 24 сен 2016, 11:25
Откуда: Тбилиси

Re: T/C2

Сообщение AVRIK » 25 сен 2016, 20:54

Спасибо большое за отзыв! С этой проблемой я уже около недели в стопоре! По поводу вашей подсказки. В части MCUCR в регистре GIFR, 6-ой бит, INTF0 регулирует состояние флага прерываний. В прописанном, (представленном выше), коде, GIFR|=(1<<INTF0). На всякий случай я протестировал и вариант где GIFR&=~(1<<INTF0); однако желаемого результата не достиг, а именно, не регулируется временная ширина PORTC|=(1<<0); условиями TCCR2 и OCR2 в puls_set();
Если вас не затруднит, подскажите пожалуйста конкретнее суть решения задачи.
Благодарю.

Аватара пользователя
gurvinok
Сообщения: 1539
Зарегистрирован: 02 мар 2013, 09:18
Откуда: Москва

Re: T/C2

Сообщение gurvinok » 26 сен 2016, 15:48

Ща ченить сообразим.
Если долго мучиться, может быть получится.

Аватара пользователя
gurvinok
Сообщения: 1539
Зарегистрирован: 02 мар 2013, 09:18
Откуда: Москва

Re: T/C2

Сообщение gurvinok » 26 сен 2016, 16:30

Ну типа того.

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


#define F_CPU	7372800UL
#define F_CPU_64	(F_CPU/64)

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

volatile unsigned int count = 0;

// Настройка INT0
void INT0_init(void)
{
	// INT0 по переднему фронту
	MCUCR |= (1<<ISC01)|(1<<ISC00);
	
	// Разрешение прерывания INT0
	GICR |= (1<<INT0);
}

void T0_init(void)
{
	// Предделитель
	TCCR2 |= (1 << CS21)|(1 << CS20);		
	// Значение сравнения
	OCR2 = (char)(0.001*F_CPU_64);		
	// Обнулить регистр счета
	TCNT2 = 0x00;				
	// Разрешение прерывания Т2 по совпадению
	TIMSK |= (1 << OCIE2);		
}

// Обработчик прерывания INT0
ISR(INT0_vect)
{
	// Включить светодиод
	PORTB |= (1 << PORTB2);
	// Сброс счетчика
	count = 0;
}

// Обработчик таймера раз в 1 миллисекунду
ISR(TIMER2_COMP_vect)
{
	if(count >= 1000)
	{
		// Сброс счетчика
		count = 0;		
		// Выключить светодиод
		PORTB &= ~(1 << PORTB2);		
	}
	else
	{
		// Увеличить счетчик
		count++;
	}
	// Сброс таймера
	TCNT2=0x00;
}

int main(void)
{
	// Инициализация пина для вывода
	DDRD |= (1 << PORTB2);
	
	INT0_init();
	T0_init();
	
	// Разрешаем прерывания
	sei();
	
    while(1)
    {
        
    }
}
Если долго мучиться, может быть получится.

AVRIK
Сообщения: 146
Зарегистрирован: 24 сен 2016, 11:25
Откуда: Тбилиси

Re: T/C2

Сообщение AVRIK » 26 сен 2016, 17:31

Спасибо большое, буду разбираться! Надеюсь заработает!

Аватара пользователя
gurvinok
Сообщения: 1539
Зарегистрирован: 02 мар 2013, 09:18
Откуда: Москва

Re: T/C2

Сообщение gurvinok » 26 сен 2016, 20:44

Я на железе проверял, работает.
Если долго мучиться, может быть получится.

AVRIK
Сообщения: 146
Зарегистрирован: 24 сен 2016, 11:25
Откуда: Тбилиси

Re: T/C2

Сообщение AVRIK » 27 сен 2016, 13:15

Здравствуйте! Позволю себе обратиться к вам с просьбой при наличии свободного времени и желания, просмотреть составленный мной код и внести коррективы. Для ясности, поясню поставленную задачу.
Задача исключить ложное срабатывание без проводного электро звонка. Для этого нужно программно нужно прописать код определяющий СВОЙ/ЧУЖОЙ.
Алгоритм кода: При получении сигнала на приемник ( китайский ФМ модуль 433кгц), срабатывает прерывание INT0, и оператором "for" запускается отсчет времени до замера лог. уровня принятого сигнала. Определенный уровень записывается в переменную "А". (код прописан до этого шага). В зависимости от лог. уровня "А", пошагово записывается бит за битом до составления байта или массива. От результата сравнения принятого байта или массива с прописанным в EEPROM кодом(ключом), зависит срабатывание реле звонка. КОД:

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

#define F_CPU8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned char A;                                                 // обявление глобальной переменной

void int0_set(void)
{
	MCUCR &= ~( (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00) );   //сбрасываем все биты ISCxx
	MCUCR |= (1<<ISC01);                                         //настраиваем на срабатывание INT0 по спадающему фронту
	GICR |= (1<<INT0);                                           //активируем прерывание по INT0;
}

ISR(INT0_vect)
{		
	for (unsigned char i=0;i<=115;i++){}                           // инициализируем и запускаем счетчик (частоту "тиков" определяет F_CPU;)
	PORTC|=(1<<0);                                                // тестовое условие -для наглядности результата срабатывания "for".
	PORTC&=~(1<<0);                                               // тестовое условие
	PORTC&=0b00000010;	                                          // определяем лог.состояние ПИНС.1 в точке по условию"for".
	A=PORTC;                                                      // присваивае результат переменной "А".
	
	 switch (A)                                                   // тестовое условие для определения лог.величины "А" -активируем оператор "switch".
	   {
		   case 1:                                                
		   PORTB|=(1<<0);                                         // условие при состоянии лог."1" переменной "А". 
		   break;                                                 
		   case 0:
		   PORTB&=~(1<<0);                                        // условие при состоянии лог."0" переменной "А"
		   break;
	   }
}

int main(void)
{
	 
	 DDRD&=0x00;                                        //все пины на вход, в том числе и пин на котором прерывание
	 PORTD&=0x04;
	 DDRB|=0xFF;
	 PORTB&=0x00;
	 DDRC|=0xFD;
	 PORTC&=0x00;	 	 
	 int0_set();                                        //запустили инициализацию прерывания.
	 sei();                                             //глобально разрешили прерывания
	 
    while(1)
    { }
}
Здесь остановился потому что PORTB в протеусе не отображает лог.уровень "А".
Вложения
Снимок.PNG

AVRIK
Сообщения: 146
Зарегистрирован: 24 сен 2016, 11:25
Откуда: Тбилиси

Re: T/C2

Сообщение AVRIK » 27 сен 2016, 13:20

Для наглядности в тестовом режиме в "for", PORTC|=(1<<0); в протеусе ПИНС.0 показывает место замера лог.уровня входящего сигнала(код). а результат PORTC&=0b00000010; записанный в "А", не отображается на PORTB.
В чем ошибка?

Аватара пользователя
gurvinok
Сообщения: 1539
Зарегистрирован: 02 мар 2013, 09:18
Откуда: Москва

Re: T/C2

Сообщение gurvinok » 27 сен 2016, 14:20

А не проще это на UART повесить и не изобретать велосипед? Передатчик гонит данные с линии TX, а приемник принимает на RX. Всю рутину по тайменгам берет на себя железо. Так например работают ИК передатчики.
В чем ошибка?
В том что Свитч проверяет на 0 и 1, а в "А" лежит 2.
Если долго мучиться, может быть получится.

Ответить