Repository navigation
Аналого-цифровой преобразователь. Изучение режимов работы аналого-цифрового преобразователя
- Цель работы: изучить режимы работы аналого-цифрового преобразователя
Задачи:
- Настройка АЦП: включение; выбор канала АЦП; выбор источника и уровня опорного напряжения; выбор делителя АЦП.
- Написать код в Atmel, позволяющий изменять тип выравнивания (левостороннее и правостороннее) и коэффициент усиления;
- Вывести на семисегментный индикатор напряжение;
- Построить схему в Proteus, проверив в нём работоспособность программы.
Код программы в Atmel Studio
#include <avr/io.h>
volatile float voltage;
volatile int ADC_result;
volatile int koef_usil;
volatile int voltXdot0;
volatile int volt0dotX;
void setup_timer0() // Задаём таймер для переключения индикаторов
{
TCCR0B |= (1 << CS00) | (1 << CS01) | (0 << CS02); // Прескейлер таймера 64. Период таймера 16,3 мс
}
uint8_t digit_codes[] =
{
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
void adc_setup()
{
ADMUX |= (1<<REFS0); // Выбор источника опроного напряжения
ADMUX &= 0xF0; // Выбор канала ADC0
ADCSRA |= (1<<ADEN); // Включение АЦП
ADCSRA |= (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2); // Прескейлер АЦП, коэф. деления 128
}
uint16_t adc_read()
{
ADCSRA |= (1 << ADSC); // Начало преобразования
ADCSRA |= (1 << ADATE); // АЦП автоматически запускает следующее преобразование, после завершение предыдущего
return ADC; // adc_read() возвращает результат работы АЦП
}
void change_ADLAR()
{
if (PIND & (1 << PD7)) // Порт PD7 управляет режимом выравнивания АЦП
{
ADMUX &= ~(1 << ADLAR); // Правостороннее выравнивание
ADC_result = adc_read();
}
else
{
ADMUX |= (1 << ADLAR); // Левостороннее выравнивание
ADC_result = (adc_read() >> 6); // Смещаем резуальтат на 6 разрядов вправо
}
}
int change_Koef()
{
if (PIND & (1 << PD6)) // Порт PD6 устанавливает коэффициент усиления
{
return koef_usil = 10;
}
else
{
return koef_usil = 5;
}
}
int main(void)
{
adc_setup(); // Устанавливаем параметры АЦП
setup_timer0(); // Устанавливаем параметры таймера
DDRB |= 0xFF; // Порт B - вывод сигнала на индикатор
DDRD |= (1 << PD1) | (1 << PD2); // Порт D - выбор индикатора (инвертированный, при 0 на PDX выбран X индикатор)
while(1)
{
change_ADLAR();
change_Koef();
voltage = ADC_result * koef_usil / 1023.0; // Масштабирование сигнала
voltXdot0 = (int)voltage; // Единицы вольт
volt0dotX = (int)(voltage * 10.0) % 10; // Десятые вольт
if (TCNT0 < 0x80) // Половину периода таймера горит 1 индикатор
{
PORTD = (1 << PD2); // Выключаем 2 индикатор
// Записываем преобразованное для индикатора значение единиц вольт в порт B и добавляем точку
PORTB = digit_codes[voltXdot0] + (1 << PB7);
}
else
{
PORTD = (1 << PD1);
PORTB = digit_codes[volt0dotX];
}
}
}
Демонстрация работы схемы в Proteus
Порты PB0-PB7 формируют сигналы на семисегментном индикаторе. За выбор активного индикатора отвечают порты PD1 и PD2, подающие сигнал высокого или низкого уровня на порты индикатора 1 и 2. Переключение происходит с частотой 122,7 Гц, что позволяет не замечать мерцание человеческому глазу.
На порт PC0 поступает напряжение с потенциометра RV1, оно преобразуется в 10-битное число, хранимое в 16-разрядном регистре. Формат записи – левосторонняя или правосторонняя, задаётся переключателем DSW (3-2). Коэффициент усиления задаётся переключателем DSW (4-1)
