Почему не работает?

AVS
Offline
Зарегистрирован: 11.12.2017
int read_voltage() {
  ADCSRA = (1 << ADEN);
  delay(10);
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0);
  delay(10);
  ADCSRA |= (1 << ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  uint8_t low  = ADCL; 
  uint8_t high = ADCH; 
  long result = (high << 8) | low;
  Serial.println(result);
  return result;


}

Приветствую, вот функция для определения напряжения на пине ADC3 относительно напряжения питания. К сожалению ф-я выдает только 1023, в то время как стандаратная ф-я analogread(А3) выдает корректное значение. В чем загвоздка? Микроконтроллер atmega328

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Даже не спрашиваю, чем Вас не устраивает analgRead (догадываюсь).

А так, Вы не задали делитель частоты (биты ADPS2-0 регистра ADSRA). Когда там нули, он уж больно крутой.

Для частоты 16М нужно взвести в 1 все три бита. А вообще, для максимальной точности измерения делитель определяется так:

	#if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
	ADCSRA = (bit(ADPS2) | bit(ADPS1) | bit(ADPS0));
	#elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
	ADCSRA = (bit(ADPS2) | bit(ADPS1));
	#elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
	ADCSRA = (bit(ADPS2) | bit(ADPS0));
	#elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
	ADCSRA = bit(ADPS2);
	#elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
	ADCSRA = (bit(ADPS1) | bit(ADPS0));
	#else // 128 kHz / 2 = 64 KHz
	ADCSRA = bit(ADPS0);
	#endif

Ну, и по коду.

1) ВСЕ записи типа (0 << N) - лишние, только засоряют текст.

2) если фунция у Вас возвращает int, нафига Вы объявили переменную result как long?

3) Отрадно, что Вы слышали про порядок чтения 16-битных регистров, но не надо мудрствовать лукаво. Строки №№ 8-10 спокойно заменяются на

const int result = ADC;

Больше ничего не нужно.

Green
Offline
Зарегистрирован: 01.10.2015

1) Это на любителя. Часто для наглядности. На мой взгляд засоряют скобки.
Ниже наглядно показывает что есть что. И позволяет оперативно изменять при необходимости, с минимумом телодвижений.
 

  ADMUX = 0<<REFS1 | 1<<REFS0 | 0<<MUX3 | 0<<MUX2 | 1<<MUX1 | 1<<MUX0;

 
AVS
Offline
Зарегистрирован: 11.12.2017

не понимаю как так, но уже далеко не первый раз замечаю, что после перезагрузки программмы/компьютера тот или иной скетч начинает работть, хотя до этого никак..тут так и вышло...

насчет прескаллера, я думал, что он необходим только для большей точности. А так данные теперпь получаются при наличии этой строки "ADCSRA = (bit(ADPS2) | bit(ADPS1));" и без нее

1)это как раз таки  для наглядности, можно и в 3-х соснах заблудиться)

2) Да, нужно привести к 1 типу

3) Нет, все куда прозаичнее, конкретно эту часть я взял из чужого скетча, но ваше написание, безусловно проще

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

С перскэйлером осторожнее. То, что я привёл - это рекомендация производителя контроллера  для обеспечения нормальной 10 бит точности.

Green
Offline
Зарегистрирован: 01.10.2015

AVS пишет:

насчет прескаллера, я думал, что он необходим только для большей точности. 

Если точность не нужна, а нужна скорость, ADPS можно высталять на минимальный коеффициент. Актуально для регулирующих систем с обратной связью, где важно относительное значение.

AVS
Offline
Зарегистрирован: 11.12.2017

Большое спасибо за разъяснения, завтра поиграюсь с этим делителем