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

Не работает прерывание

Добавлено: Пт фев 07, 2014 12:04:53
Грендайзер
Здасте Всем :) Пишу программу для ATmega16A. При нажатии на кнопочку (INT0) должно измениться направление движения огонька светодиодика. Вот код

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

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

#define F_CPU 1000000UL // 1MHz
#include <util/delay.h>

char trig = 1;
char a = 1;

ISR(INT0_vect) // прерывание по вектору INT0
{
	trig = (~trig) & 1; // если кнопка нажата меняем направление движения огонька
}


int main(void)
{
	
	SREG = 128;
	GICR |= _BV(INT0);
	
	DDRA = 0;		// порт A на ввод
	PORTA = 0xFF;   // подтянуть внутренние резисторы
	
	DDRB = 0;		// порт B на ввод
	PORTB = 0xFF;	// подтянуть внутренние резисторы
	
	DDRD = 0;		// порт D на ввод
	PORTD = 0xFF;	// подтянуть внутренние резисторы
	
	DDRC = 0xFF;	// порт C на вывод
	PORTC = 0xFF;	// потушить светодиоды
	
	while(1)
	{
		
		//_delay_ms(100);
		
		if (trig) // усли кнопка не надата работаем
		{
			if (a)
			{
				a = a << 1;
			}
			else
			{
				a = 1;
			}
		}
		else // если нажата кнопка то trig изменит своё значение и движение огонька изменится
		{
			if(a)
			{
				a = a >> 1;
			}
			else
			{
				a = 128;
			}
		}
	}
}

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 12:09:13
Грендайзер
Да, так вот.. Прерывание не происходит, хотя что я уже ни делал. И ещё, странно себя ведут циклы. Они почему то с первого раза не видят, что переменные "trig" и "a" больше 0 и при моделировании при проходе первый раз циклы считают, что эти переменные не "1" а "0" ничего не понимаю :dont_know:

P.S. Моделировал в AtmelStudio6.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 12:19:30
WiseLord
Попробуйте объявить char trig = 1; как volatile char trig = 1;

Так, и ещё разрешить глобально прерывания функцией sei();

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 12:55:53
Грендайзер
Скажите, а выражение

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

ISR(INT0_vect) // прерывание по вектору INT0
{
   trig = (~trig) & 1; // если кнопка нажата меняем направление движения огонька
}
разве не должно само по себе всё организовать... В примерах которые я смотрел, никто в ручную глоб. прерывания не выставлял...

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 13:09:35
Engineer_Keen
Это выражение только лишь определяет нужный вектор и вставляет в него переход на подпрограмму-обработчик. А вот флаг I нужно выставлять при инициализации вручную. Примеры без этого "в студию". (выставить этот флаг можно не только командой SEI, но и записью 1 в соответствующий бит SREG или непосредственно вызовом любого обработчика прерывания, но это хитрое хакерство)

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 13:11:27
BCluster
Надо включить глобально прерывания.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 13:18:00
Грендайзер
Engineer_Keen писал(а):Это выражение только лишь определяет нужный вектор и вставляет в него переход на подпрограмму-обработчик. А вот флаг I нужно выставлять при инициализации вручную. Примеры без этого "в студию".
Опаньки, не доглядел, команда sei() и впрямь есть. Моя вина. Пример же вот
http://www.avr-tutorials.com/interrupts ... rogramming

Что же касается работы, всёравно ничерта не выходит. Прерывание не выполняется, циклы один хрен ничё не видят. Компилято правда такое вот сообщение выдаёт:
Целевой объект "PreBuildEvent" пропущен из-за невыполненного условия; выражение ('$(PreBuildEvent)'!='') равно (''!='').
Может студия криво встала. Дома у меня стоит AVRStudio 4.19. Так на ней циклы себя нормально вели.

Прошу прощения, моя вина. Не правильно интерпритировал действия отладчика. Он почему то как то не совсем ясно указывает на текущий выполняемый оператор (стрелка как то слишком шустро прыгает в какие то непонятные места). Это что касается циклов. Что же касается прерывания то оно работает почему то по спадающему фронту, хотя должно (если верить даташиту) если нога в нуле.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 14:04:43
WiseLord
Для ATMega16 тип срабатывания прерывания зависит от битов ICS01 и ICS00 регистра MCUCR
00 - по низкому уровню (по умолчанию)
01 - по любому изменению фронта
10 - по спаду
11 - по фронту

В принципе, особой разницы между 00 и 10 я как-то не вижу.

Опять же, повторюсь по поводу объявления trig как volatile. Без этого оптимизатор компилятора может в основном цикле просто оптимизировать trig, не учтя возможных изменений этой переменной в функции прерывания, которая напрямую в main не вызывается, и оптимизатор не подозревает о том, что что-то может изменить её "в другом потоке".
volatile как раз запрещает компилятору как-либо оптимизировать переменную.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 14:10:47
Engineer_Keen
WiseLord писал(а):В принципе, особой разницы между 00 и 10 я как-то не вижу.
Если закоротить ногу на землю, то в первом случае прерывание будет вызываться постоянно - пока нога на земле, а во втором один раз.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 14:14:53
Грендайзер
WiseLord писал(а):Для ATMega16 тип срабатывания прерывания зависит от битов ICS01 и ICS00 регистра MCUCR
00 - по низкому уровню (по умолчанию)
01 - по любому изменению фронта
10 - по спаду
11 - по фронту

В принципе, особой разницы между 00 и 10 я как-то не вижу.
Ну на мой взгляд 00 - это когда я нажал кнопку и процессор не сможет вернуться к выполнению основной программы пока я кнопку не отпущу. Он вышел из прерывания и сразу в него вернклся...
А вот 10 это уже проверка фронта. Т.е. нажал я процессор отработал прерывание и опять к выполнению основной программы. Так вот 00 - это по умолчанию, а уменя по умолчанию даже не по спадающему фронту, а по обоим фронтам моделировать начал, лишь после того как я явно указал MCUCR = 0 симмулятор начал срабатывать... по спадающему фронту :shock: :evil: Вообщем вечерком проверю в железке...
WiseLord писал(а): Опять же, повторюсь по поводу объявления trig как volatile. Без этого оптимизатор компилятора может в основном цикле просто оптимизировать trig, не учтя возможных изменений этой переменной в функции прерывания, которая напрямую в main не вызывается, и оптимизатор не подозревает о том, что что-то может изменить её "в другом потоке".
volatile как раз запрещает компилятору как-либо оптимизировать переменную.
Да, спасибо, я именно так и сделал.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 15:24:20
WiseLord
Engineer_Keen писал(а):Если закоротить ногу на землю, то в первом случае прерывание будет вызываться постоянно - пока нога на земле, а во втором один раз.
Т.е. как только функция-обработчик прерывания завершится, она снова начнёт выполняться снова (если флаги прерываний не были изменены в самом этом прерывании)?

ОК, буду знать.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 15:39:13
Engineer_Keen
Да, выполнит одну команду и вернется в обработчик.

Re: Не работает прерывание

Добавлено: Пт фев 07, 2014 18:19:41
nirq
При нажатии на кнопочку (INT0) должно измениться направление
Дребезг.
Читать лень.