АЦП и кнопки. Прерывание не срабатывает. mega16.

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
Maxxon
Открыл глаза
Сообщения: 43
Зарегистрирован: Пт апр 09, 2010 12:54:00
Откуда: Санкт-Петербург

АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение Maxxon »

Добрый день.

Стало не хватать портов в девайсе, решил заюзать АЦП для 8 кнопок. Сделал делитель напряжения (пара кнопок), набросал макет в протеусе. Согласно даташиту на mega16 проинициализировал регистры, использую одиночные преобразования. Прерывание не срабатывает, хоть тресни. Пошарил по форумам (в том числе и этом), в гугле (в том числе и на буржуйских сайтах), у всех все работает, в большинстве примеров используется mega8535. Потратил часов 6, однако проблему у себя так и не решил. Нутром чувствую, что проблема в какой-нибудь ерунде, но зациклился и не могу понять. Пишу в AVR Studio+WinAVR.
В протеусе модель тактуется от внутреннего 1MHz осциллятора, в железе - 16МГц (знаю, для кнопок это много, но суть сейчас не в этом). Данные из регистров пока не читаю, надо лишь убедиться что прерывание срабатывает.

Код (упрощен до минимума) ниже

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

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

unsigned char tmp;

ISR(ADC_vect) {
    //выставляем tmp в 1 чтобы поморгать светодиодом
    tmp=1;
    //запускаем очередное преобразование
    ADCSRA |= (1<<ADSC);
}


int main () {
    tmp=0;
    //На PC болтается 8 светодиодов, на схеме показан только один
    DDRC = 0xFF;
    PORTC = 0x00;
    
    //Используем PA0 для кнопок
    DDRA = 0xFE;
    PORTA = 0x00;
    //Инициализируем по даташиту.
    //AVCC соединен с AREF напрямую, поэтому в REFS1=REFS0=0
    //ADLAR=1 - используем сдвиг влево
    //MUX4..MUX0 - 0, т.к. используется PA0
    ADMUX = (0<<REFS1)|(0<<REFS0)|(1<<ADLAR)|(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
    //включаем АЦП, преобразование выключено, триггеры не используем, делитель частоты максимальный
    ADCSRA = (1<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
   //прерывания разрешены
    sei();

    //Согласно даташиту
    //A single conversion is started by writing a logical one to the ADC Start Conversion bit, ADSC.
    //This bit stays high as long as the conversion is in progress and will be cleared by hardware
    //when the conversion is completed.
    ADCSRA |= (1<<ADSC);
    for (;;) {
        if (tmp==1) {
                //Если прерывание сработало, моргаем светодиодом и очищаем tmp
                PORTC |= 1<<0;
                _delay_ms(200);
                PORTC &= ~(1<<0);
                tmp=0;
        }
    }
    return 0;
}
Заметил, что если вставлять какие-нибудь задержки в обработчик прерывание, то прерывание зацикливается (т.е. после окончания обработчика, сразу же срабатывает снова).

Схема ниже:
Изображение

Не работает ни в протеусе, ни в железе (даже если выставить фьюзы для внутреннего осциллятора). мега не битая, все остальные порты с периферией общаются на ура.
Реклама
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение ibiza11 »

фьюз JTAG отключен?
Ставим плюсы: )
Реклама
Аватара пользователя
Maxxon
Открыл глаза
Сообщения: 43
Зарегистрирован: Пт апр 09, 2010 12:54:00
Откуда: Санкт-Петербург

Re: АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение Maxxon »

Да, конечно. Да и влияет он только на PC2-PC5...
inkHunter
Грызет канифоль
Сообщения: 287
Зарегистрирован: Сб авг 21, 2010 20:44:27
Откуда: Ростов
Контактная информация:

Re: АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение inkHunter »

Для меги 8
#include <avr/io.h>
#include <avr/interrupt.h>

int adc;
volatile int i=0;
ISR(SIG_ADC)
{
adc=ADCW;
ADCSR|=0x40;
}
void main (void)
{
ADMUX=0;
ADCSR =0b10001101;
ADCSR|=0x40;
sei();


while (1)
{
i++;
if (i==100)
{i=0;}

}
}

Все работает
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Maxxon
Открыл глаза
Сообщения: 43
Зарегистрирован: Пт апр 09, 2010 12:54:00
Откуда: Санкт-Петербург

Re: АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение Maxxon »

Странно, ведь у нас код по сути отличается только коэффициентом делителя и директивой volatile для переменной. Делитель тут явно не причем, у меня выбран максимальный чтобы за кнопками уследить, volatile используется для переменных, которые могут изменять несколько тредов или для игнорирования компилятором при оптимизации. Господа, поправьте меня, если я что-то не так понимаю... Но мой код по прежнему не работает :(

P.S.: если я ставлю volatile у меня начинает бесконтрольно срабатывать прерывание.
Реклама
Аватара пользователя
Maxxon
Открыл глаза
Сообщения: 43
Зарегистрирован: Пт апр 09, 2010 12:54:00
Откуда: Санкт-Петербург

Re: АЦП и кнопки. Прерывание не срабатывает. mega16.

Сообщение Maxxon »

Плюнул, убрал переменную tmp. Лучше уж прямо из прерывания дергать функции. Работает.
Возможно, в том случае требуется делать задержки на какое-то количество тактов, иначе АЦП не успевает сбросить регистры для следующей конверсии.

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

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

ISR(ADC_vect) {
		if(ADCH > 128) { 
				PORTC |= 1<<0;
				_delay_ms(500);
				PORTC &= ~(1<<0);
				_delay_ms(500);
		}
		ADCSRA |= (1<<ADSC);
}


int main () {

	DDRC = 0xFF;
	PORTC = 0x00;

	DDRA = 0xFE;
	PORTA = 0x00; 

	ADMUX = (0<<REFS1)|(0<<REFS0)|(1<<ADLAR)|(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
	ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
	sei();

	for (;;) {	}
	return 0;
}


В качестве послесловия. Удалось добиться уверенной работы с помощью volatile (да да, вернул обратно), точной подстройки порогов и фильтрации дребезга. Дело в том, что компилятор все-таки оптимизирует на свое усмотрение и переменную tmp, объявленную без volatile, из обработчика прерывания изменить никогда не удастся (как и в C++ для нескольких тредов).

Таким образом проблема решилась полностью, программа уже в железе.
Реклама
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»