Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр

Автор: g1ar от 22-03-2013, 15:01

Всем привет. Сегодня мы затронем серьезную тему под названием АЦП. Как всегда начну с характеристик АЦП, на примере, ATmega8. И так на борту имеется 6-канальный аналого-цифровой преобразователь(АЦП) который имеет 4 канала с 10-разрядной точностью и 2 канала с 8-разрядной точностью.
И так что-же значит «10-разрядной точностью». Это значит что измерение будет разбито на 210 частей, и для того что бы определить шаг измерения нужно поделить напряжение АЦП на 210=1023(т.к. отсчет с 0), например, если измеряемое напряжение равно 2.56В, то наш шаг составит 2.56/1023=0,0025В. Далее нужно будет просто умножить шаг на значение регистра ADCH(старший бит) и ADCL(младший бит), где хранится результат преобразования.
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр

Теперь подробнее:
Для управления АЦП нам нужно записать нужные числа в регистры управления АЦП под названиями ADMUX и ADCSRA(ADCSR)
ADMUX – регистр мультиплексора АЦП.
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр


Биты 7:6 (REFS1:REFS0) - биты выбора опорного напряжения. Если мы будем менять эти биты во время преобразования, то изменения вступят в силу только после текущего преобразования. В качестве опорного напряжения может быть выбран AVcc (напряжение источника питания), AREF или внутренний источник опорного напряжения 2.56В.

Биты 7:6
REFS1:REFS0
00 AREF
01 AVcc, с внешним конденсатором на AREF
10 Резерв
11 Внутренний 2.56В источник, с внешним конденсатором на AREF

Бит 5 – ADLAR. Определяет как результат запишется в регистры
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр

Биты 3:0 – MUX3:MUX0 – Биты выбора канала.
MUX3:0
0000 ADC0
0001 ADC1
0010 ADC2
0011 ADC3
0100 ADC4
0101 ADC5
0110 ADC6
0111 ADC7

Следующий регистр – ADCSRA где хранятся главные настройки АЦП
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр


Бит 7 – ADEN. Разрешение АЦП.
0 – АЦП выключен
1 – АЦП включен

Бит 6 – ADSC. Запуск преобразования (в режиме однократного преобразования)
0 – преобразование завершено
1 – начать преобразование

Бит 5 – ADFR. Выбор режима работы АЦП
0 – режим однократного преобразования
1 – режим непрерывного преобразования

Бит 4 – ADIF. Флаг прерывания от АЦП. Бит устанавливается, когда преобразование закончено.

Бит 3 – ADIE. Разрешение прерывания от АЦП
0 – прерывание запрещено
1 – прерывание разрешено
Прерывание от АЦП генерируется (если разрешено) по завершении преобразования.

Биты 2:1 – ADPS2:ADPS0. Тактовая частота АЦП, а точнее делитель тактовой частоты МПС
ADPS2:0
000 2
001 2
010 4
011 8
100 16
101 32
110 64
111 128

Чем больше частота - тем быстрее преобразование, но больше погрешность.

Вот так происходит преобразование
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр


Ну и в качестве примера сделаем вольтметр на 10В.
Расчетная часть будет выглядеть так:
Будем использовать старший байт ADCH поэтому количество измерений будет 28=255. Опорное напряжение – внутренний источник на 2.56В. Далее рассчитываем шаг 2.56/255=1мВ. Для того что бы измерить наши 10В нужно поставить делитель напряжения, несложными расчетами подбираем наиболее правдоподобные резисторы на 56КОм и 15КОм, тогда наш коэффициент равен 4.73. Окончательная формула выглядит так
Значение в Вольтах = ADCH*0.01*4.73;
Изучаем микроконтроллеры AVR. АЦП, делаем вольтметр

Имеется погрешность в одну десятую т.к. делитель подобран не идеально (если кто то захочет собрать схему можно поставить подстроечник). Только не забывайте ставить емкостно-индуктивный фильтр.

Теперь программная часть:
Как всегда создаем проект в кодвижине (CodeVision) удаляем все и пишем:

// с библиотеками всё понятно
#include <mega8.h>
#include <delay.h>
#include <lcd.h>
#include <stdio.h>  
#include <string.h>
//наши переменные
char result[5];
unsigned char volt;
//выбор порта для ЖКИ-порт В
#asm  
.equ __lcd_port=0x18 ;
#endasm
//Функция инициализации
void ADC_init()
{
         ADMUX = 0xf0; //если более понятно пишем 0b11110000
         ADCSRA = 0x8d; //0b10001101
}
//Функция измерения
unsigned char ADC_result(unsigned char adc_input)
{
         ADMUX=adc_input | (ADMUX & 0xF0); //выставляем канал
         delay_us(30); //задержка для стабилизации
         ADCSRA |= 0x40;
         while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
         ADCSRA|=0x10;
         return ADCH;//Возвращаем старший байт
}
//Наша главная функция
void main()
{  
    ADC_init();  
    volt=ADC_result(0)*0.01*4.73*10; //умножение на 10 для точности до десятых
    sprintf(result,"V=%i.%u",volt/10,volt%10);
    lcd_init(16);
    lcd_gotoxy(0,0);   
    lcd_puts(result);
}


Дерзайте!
Хотите подробнее – читайте даташит, ну или бегите на форум.


Теги: АЦП, аналого-цифровой преобразователь, avr, codevision, atmega8, adch, adcl, admux, adcsra

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
  • Группа: Посетители
  • ICQ:
  • Регистрация: 17.05.2013
  • Статус: Пользователь offline
  • Комментариев: 1
  • Публикаций: 0
^
ошибка : 2.56/255 = 0,01 то есть 10 мВ... ,
А если требуется получить точность до целых вольт ? нужно на 100 умножить ?
  • Группа: Посетители
  • ICQ:
  • Регистрация: 13.10.2013
  • Статус: Пользователь offline
  • Комментариев: 1
  • Публикаций: 0
^
Как просто все написано. И даже все понятно. Сегодня буду пробовать в живую.
  • Группа: Посетители
  • ICQ:
  • Регистрация: 9.02.2018
  • Статус: Пользователь offline
  • Комментариев: 1
  • Публикаций: 0
^
Как зто передать по USART?
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.