Стало не хватать портов в девайсе, решил заюзать АЦП для 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;
}
Схема ниже:

Не работает ни в протеусе, ни в железе (даже если выставить фьюзы для внутреннего осциллятора). мега не битая, все остальные порты с периферией общаются на ура.


