Attiny13 и ADC

Среда разработки: Atmel Studio 7

Симуляция в протеус 8. Ошибка звучит так:

PC=0x00F0. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]
PC=0x00F2. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]
PC=0x00F6. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]
PC=0x00F0. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]
PC=0x00F4. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]

Минимальная схема и код повторяющий ошибку:

Код:

#define	 F_CPU			1200000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile uint16_t analogData;

ISR (ADC_vect) {
	analogData = (ADCH<<8) + ADCL;
}

int main(void) {

	DDRB  &= ~(1<<PORTB4);								// PB4 на вход
	
	// Настраиваем работу с ADC (АЦП)
	ADMUX  |= (1<<REFS0) | (1<<ADLAR) | (1<<MUX1);  				// опорное напряжение - Internal, левое ориентирование данных, выбран вход ADC2 (на него подается измеряемое напряжение)
	ADCSRA |= (1<<ADEN)  | (1<<ADSC)  | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2);	// АЦП включен, запуск преобразования, режим автоизмерения, прерывание по окончанию преобразования, частота CLK/4
	ADCSRB  = 0x00;									// режим автоизмерения: постоянно запущено

	DIDR0 |= (1<<ADC2D);	// запрещаем цифровой вход на ноге аналогового входа
	
	sei(); //разрешаем глобально прерывания
		
	while (1) {
	}
}

Что я забыл или сделал не так? :frowning:

ЗЫ: Даташит

А если код в самом протеусе набить ? Или там только asm под 13 …

Не знаю, никогда так не делал. Сейчас попробую посмотреть…

ADCL must be read first, then ADCH

P.S. А можно просто
analogData = ADC;

Спасибо, исправил. Но результат тот же.

#define	 F_CPU			1200000UL

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

volatile uint16_t analogData;

ISR (ADC_vect) {
	analogData = ADCL + (ADCH<<8);
}

int main(void) {

	DDRB  &= ~(1<<PORTB4);								// PB4 на вход
	
	// Настраиваем работу с ADC (АЦП)
	ADMUX  |= (1<<REFS0) | (1<<ADLAR) | (1<<MUX1);  				// опорное напряжение - Internal, левое ориентирование данных, выбран вход ADC2 (на него подается измеряемое напряжение)
	ADCSRA |= (1<<ADEN)  | (1<<ADSC)  | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2);	// АЦП включен, запуск преобразования, режим автоизмерения, прерывание по окончанию преобразования, частота CLK/4
	ADCSRB  = 0x00;									// режим автоизмерения: постоянно запущено

	DIDR0 |= (1<<ADC2D);	// запрещаем цифровой вход на ноге аналогового входа
	
	sei(); //разрешаем глобально прерывания
	
	while (1) {
	}
}

Установил компилятор WinAVR и закинул код в сам протеус. Результат не изменен:

PC=0x0096. [AVR AD CONVERTER] Result is not written to the ADC register because it has been locked. [U1]

строку 17 закомментируй, коль намёков не понимаешь
пин на вход это ADMUX

Компилятор сначала в скобках сделает

byte lowb, highb;

lowb = ADCL;
highb = ADCH;

Да не думаю, что в этом дело.
Сделал вот так:

ISR (ADC_vect) {
	uint8_t lowb, highb;

	lowb = ADCL;
	highb = ADCH;
	analogData = (lowb + (highb<<8));
}

Ошибка осталась.

Result is not written to the ADC register because it has been locked

Какого фига он заблокирован? Кем он заблокирован? Как узнать? Я не понимать… ))

//highb = ADCH;
analogData =(ADCH<<8) | (lowb);

Не знаю, вариант рабочий. Попробуй просто analogData = ADC;
У меня оба варианта работают

Да пробовал я, ничего не меняется)))
Да и как изменится, ошибка же не в чтении из регистров, а в записи в них )))

не, читать надо сначал L потом H, подозреваю, что надо вытащить процедуру чтения из прерывания

Так 14 стр. закоментил, как ua6em сказал?

На кой х$р?
Какая-то “ромашка” началась. Давайте перестанем тыкать в небо пальцем, я так и сам могу (но не хочу).

мы увидели, объясни нахрена ты цифровой пин на вход включаешь, а потом пытаешься это героически преодолеть, ADC2 (PB4) включил в ADMUXе

Сам так никогда не делал, но подкинул сейчас на ATtiny24 в Протеусе - не блокирует. Что-то ещё.
Кстати, исходный вариант

analogData = (ADCH<<8) + ADCL;

Как раз блокирует

В общем какая-то “байда” творится с ADCL.
Если его вообще не читать, то все работает нормально (правда разрядность уже не 10 бит, а всего 8).

Вот так работает, но надо до 10 бит добить.

#define	 F_CPU			1200000UL

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

volatile uint16_t analogData;

ISR (ADC_vect) {
//	uint8_t lowb, highb;

//	highb = ADCH;
//	lowb  = ADCL;
//	analogData = (lowb + (highb<<8));

	analogData = ADCH;
}

int main(void) {

	DDRB  &= ~(1<<PORTB4);								// PB4 на вход
	
	// Настраиваем работу с ADC (АЦП)
	ADMUX  |= (1<<REFS0) | (1<<ADLAR) | (1<<MUX1);  				// опорное напряжение - Internal, левое ориентирование данных, выбран вход ADC2 (на него подается измеряемое напряжение)
	ADCSRA |= (1<<ADEN)  | (1<<ADSC)  | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1);	// АЦП включен, запуск преобразования, режим автоизмерения, прерывание по окончанию преобразования, частота CLK/16
	ADCSRB  = 0x00;									// режим автоизмерения: постоянно запущено

	DIDR0 |= (1<<ADC2D);	// запрещаем цифровой вход на входе ADC2 (PB4)
	
	sei(); //разрешаем глобально прерывания
	
	while (1) {
	}
	
	return 0;
}

а его код в протеус закинь

Я же говорю, тот что #1 - блокирует.
А мои варианты не блокирует.
Извиняюсь, отвечал ua6em

Какой именно?

У меня все что выше предлагалось блокирует. Не блокирует только если ADCL не читать вообще.