Поставил себе задачу сделать контроль напряжения на батарее аккумуляторов с помощью микроконтроллера. Под рукой оказался только AtMega32. Сделал делитель напряжения 10:1 для батареи, повесил его на вход ADC1 (PA1). Написал следующий код:
Спойлер
Код: Выделить всё
/*
* ADC_Voltmeter.cpp
*
* Created: 18.05.2014 19:34:44
* Author: x-8973
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
#define F_CPU 8000000UL
#include <util/delay.h>
unsigned int voltage, adc_counter;
volatile unsigned long voltage_value;
void USART_Transmit(unsigned char data) //Функция отправки данных USART
{
while (!(UCSRA&(1<<UDRE))); //Ожидание опустошения буфера приема
UDR = data; //Начало передачи данных
}
void funcUSARTInit(unsigned int baudrate) //Функция инициализации USART
{
UBRRH = (baudrate >> 8);
UBRRL = (baudrate & 0xFF);
UCSRA = 0; //Удвоение скорости отключено
UCSRB = _BV(RXEN) | _BV(TXEN); //Разрешение на прием и на передачу через USART
UCSRC = _BV(URSEL) | _BV(UCSZ0) | _BV(UCSZ1); //Формат кадра: 8 бит данных, 1 стоп-бит.
}
ISR(ADC_vect)
{
ADCSRA = 0; // Выключаем АЦП
voltage_value = voltage_value + ADC; // Суммируем измеренные значения напряжения и помещаем в буфер
adc_counter++; // Увеличиваем счетчик выборок АЦП на 1
ADCSRA |= _BV(ADEN)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)|_BV(ADIE); // Включаем АЦП
}
int main(void)
{
ADMUX |= _BV(REFS1) | (1 << REFS0); // Внутренний ИОН на 2,56В
ADMUX |= (1 << MUX0); // Подключаем канал ADC1
ADCSRA |= (1 << ADEN) // разрешение АЦП
|(1 << ADSC) // запуск преобразования
|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0) // предделитель на 128
|(1 << ADIE); // разрешение прерывания от АЦП
sei(); // Глобально разрешаем прерывания
funcUSARTInit(51);
while(1)
{
if (adc_counter > 400)
{
ADCSRA = 0; // Выключаем АЦП
// преобразуем данные в реальное значение напряжения
voltage = (voltage_value/adc_counter);
USART_Transmit(voltage);
adc_counter = 0; // Обнуляем счетчик выборок АЦП
voltage_value = 0; // Обнуляем буфер значений напряжения
ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE); // Включаем АЦП
}
_delay_ms(1000);
//TODO:: Please write your application code
}
}
На основе этого у меня два вопроса: что я не учел при написании прошивки, и почему, собственно, число в регистре ADC постепенно уменьшается, хотя напряжение на входе остается неизменным (проверено китайским тестером).


