АЦП или Аналого Цифровое Преобразование. Как ни странно, преобразует аналоговое значение напряжения в цифровое, с которым удобнее работать микроконтроллеру. Он это делает на подобие компаратора, сравнивая напряжение на выходе с некоторым опорным напряжением.
От разрешения АЦП зависит его точность. к примеру если опорное напряжение 5 Вольт, АЦП 10 битный. то на каждый бит приходиться 5 / ( 2^10 - 1 ) = 0.00489 или 5 мВ. Точнее замерить нельзя.
Готовый проект в протеусе
От разрешения АЦП зависит его точность. к примеру если опорное напряжение 5 Вольт, АЦП 10 битный. то на каждый бит приходиться 5 / ( 2^10 - 1 ) = 0.00489 или 5 мВ. Точнее замерить нельзя.
За настройку АЦП отвечает регистр ADSCRA
7 ADEN включение АЦП
1 ON
0 OFF
6 ADSC отвечает за запуск АЦП, если настроено однократное преобразование, то по выполнении ставиться 0, нужно вручную ставить 1 чтобы снова запустить АЦП.
5 ADFR выбор режима работы АЦП
0 – режим однократного преобразования
1 – режим непрерывного преобразования
4 ADIF флаг прерывания, выставляется 1 при завершении преобразования.
3 ADIE разрешение прерывания
0 – прерывание запрещено
1 – прерывание разрешено
2 1 0 ADPS выбор частоты работы АЦП
CK = тактовая частота микроконтроллера
000 СК/2
001 СК/2
010 СК/4
011 СК/8
100 СК/16
101 СК/32
110 СК/64
111 СК/128
За выбор опорного напряжения и выбора выводов АЦП отвечает ADMUX
7-6 REFS выбор опорного напряжения, максимальное напряжение которое может измерить АЦП. Изменения происходят после завершения текущего преобразования.
00 AREF
01 AVcc, с внешним конденсатором на AREF
10 Зарезервировано, не используется.
11 Внутренний 2.56В источник, с внешним конденсатором на AREF
5 ADLAR определяет как значение АЦП запишется в регистры ADCL и ADCH. Т.к АЦП 10 битный 1 регистра мало. Значение обоих регистров хранится в ADCW.
4-0 MUX# определяет вывод МК откуда будет считываться значение АЦП. (ATmega8)
0000 ADC0
0001 ADC1
0010 ADC2
0011 ADC3
0100 ADC4
0101 ADC5
0110 ADC6
0111 ADC7
Готовый проект в протеусе
#include <avr io.h> #include <avr interrupt.h> //прерывание ISR(ADC_vect) { unsigned int ADCdata, voltage_0, voltage, voltage_2, voltage_3; ADCdata = ADCW; // В ADCW хранится напряжение в двоичном коде voltage_0 = ADCdata * 48875 / 10000; // 5 вольт / 1023 = 4.8875 voltage = voltage_0 % 10000 / 1000; voltage_2 = voltage_0 % 1000 / 100; voltage_3 = voltage_0 % 100 / 10; PORTC = voltage; PORTD = voltage_2; PORTB = voltage_3; ADCSRA = ADCSRA | 0x40;// Регистр для начала нового преобразования 0b01000000 } int main (void) { DDRB = 0xFF; DDRD = 0xFF; DDRC = 0xFF; ADMUX = 0x00; // PA0 ADCSRA = 0b11001110; PORTB = 0x00; PORTD = 0x00; PORTC = 0x00; sei(); while(1); }Как выглядит схема в Proteus
Подаем напряжение на PA0. Затем преобразуем его в цифровое, и выдаем нужные значения в порты в двоичном коде. Целые в Port B, десятые в Port C и сотые в Port D.
То есть у нас 2,35 Вольта.
Теперь нужно преобразовать значение из ADCW ( здесь храниться значение напряжения ) в информацию с которой легко работать..
АЦП (в моём случае) сравнивает значение аналогового входа с напряжением питания.
АЦП 10 битный, значит когда на входе 5 Вольт, в ADCW 2^10-1 = 1023.
Теперь нужно воспользоваться формулой
Вольты = ADCW * Напряжение с которым сравниваем / разрешение
В нашем случае
Вольты = ADCW * 5 / 1023
Я где-то прочитал что лучше не писать дроби а записывать таким образом:
5 / 1023 = 0.0048876 = 48876 / 10000000
Но мне нужны десятые и сотые доли вольта, поэтому я умножаю 5 на 1000 чтобы были не дроби а целые числа.
5000 / 1023 = 4.8875 = 48875 / 10000
Еще советуют ADCW засунуть в unsigned int
В конце выглядит так
unsigned int ADCdataADCdata = ADCW
voltage_0 = ADCW * 48875 / 10000
Значит у нас уже в переменной хранится четырёхзначное число обозначающее вольты к примеру 3524 что равно 3,524 вольта.
нам остается из него выделять то что нужно нам.
voltage = voltage_0 % 10000 / 1000
voltage_0 наше чертырёхзначное число.
берём из него остаток при делении на 10000, у нас получилось бы 3524
дальше делим это на 1000, т.к это int у нас будет целое число то есть 3.
В итоге voltage = 3
Выводим 3 в двоичном коде на нужный нам порт.
Проделываем то же самое с десятичной и сотой частью.
Информация:
samou4ka.net
avrlab.com
chipenable.ru
radioparty.ru
my-avr.at.ua
myrobot.ru
avr-tutorials.com
Скан книги "Шпак Ю.А. - Программирование на языке C для AVR и PIC" С хорошим примером работы АЦП.
Можно так записать?
ОтветитьУдалить//прерывание
ISR(ADC_vect)
{
unsigned int voltage_0, voltage, voltage_2, voltage_3;
voltage_0 = ADCW * 48875 / 10000;
voltage = voltage_0 % 10000 / 1000;
voltage_2 = voltage_0 % 1000 / 100;
voltage_3 = voltage_0 % 100 / 10;
PORTC = voltage;
PORTD = voltage_2;
PORTB = voltage_3;
ADCSRA = ADCSRA | 0x40;
}
т.е. сделать вычисление сразу voltage_0 = ADCW * 48875 / 10000;
а не
ADCdata = ADCW;
voltage_0 = ADCW * 48875 / 10000;