Измерение Vcc с внутренним источником опорного напряжения 1,1 В не работает на Atmega328 с питанием 3,3 В.

arduino-ide atmega328 battery analogreference

Мне нужно контролировать аккумулятор, подключенный к ATmega, работающему в автономном режиме.

Я использую загрузчик «ATmega на макетной плате (внутренняя тактовая частота 8 МГц)». Подробнее здесь

Когда ATmega питается от напряжения 5 В, скетч выдает хорошие значения: около 5100 мВ.

Но когда я подаю на него напряжение 3,3 В, скетч дает странные значения: около 178619 мВ.

Вот мой код: Взято отсюда

void setup() 
{ 
  Serial.begin(9600);
  Serial.println(F("Internal Voltage Sensor"));
}

void loop() 
{ 
  Serial.println( readVcc()); 
  delay(1000); 
} 

long readVcc() 
{
  long voltage=0;
  uint8_t wADC;

  // Чтение опорного напряжения 1,1 В относительно AVcc
  // устанавливаем опорное значение Vcc, а измерение — внутреннее опорное напряжение 1,1 В
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRA |= _BV(ADEN);  // включаем АЦП

  delay(20); // Подождем, пока Vref установится

  ADCSRA |= _BV(ADSC); // Начать преобразование
  while (bit_is_set(ADCSRA,ADSC)); // измерение

  // Регистр чтения «ADCW» сначала заботится о том, как читать ADCL, а затем ADCH.
  wADC = ADCW;

  voltage = 11253000L / wADC; // Вычисляем Vcc (в мВ); 1125,3 = 1,1*1023*1000
  return voltage; // Vcc в милливольтах
}

Я не понимаю, что происходит. Возвращаемое значение при Vcc=3,3 В должно быть ниже, чем при VCC=5 В. Что-то вроде 3300 мВ!

, 👍2

Обсуждение

Попробуйте добавить в свой код еще несколько Serial.printlns. Например, Serial.println(wADC);, @Gerben

ADCL — это младший байт, ADCH — старший байт, и сначала необходимо прочитать ADCL, а затем ADCH. ADCW сообщает компилятору прочитать два байта в правильном порядке. Использование ADCW, конечно, проще и даже лучше, потому что оно не может пойти не так... если только вы не попытаетесь поместить 16 бит ADCW в байт и выбросить старший байт. Сделайте wADC uint16_t., @Jot


1 ответ


2

Спасибо за ваши ответы! Джот дал решение: wADC должен быть uint16_t.

Вот исправленный код:

void setup() 
{ 
  Serial.begin(9600);
  Serial.println(F("Internal Voltage Sensor"));
}

void loop() 
{ 
  Serial.println(readVcc()); 
  delay(1000); 
} 

long readVcc() 
{
  long voltage=0;
  uint16_t wADC;

  // Чтение опорного напряжения 1,1 В относительно AVcc
  // устанавливаем опорное значение Vcc, а измерение — внутреннее опорное напряжение 1,1 В
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRA |= _BV(ADEN);  // включаем АЦП

  delay(20); // Подождем, пока Vref установится

  ADCSRA |= _BV(ADSC); // Начать преобразование
  while (bit_is_set(ADCSRA,ADSC)); // измерение

  // Регистр чтения «ADCW» сначала заботится о том, как читать ADCL, а затем ADCH.
  wADC = ADCW;

  voltage = 1125300L / wADC; // Вычисляем Vcc (в мВ); 1125300 = 1,1*1023*1000
  return voltage; // Vcc в милливольтах
}
,