Цифровой вольтметр 0-25В на микроконтроллере AVR ATmega32

В этой статье мы рассмотрим схему на микроконтроллере ATmega32A (семейство AVR), реализующую цифровой вольтметр с пределами измерений от 0 до 25В. Для этого мы задействуем 10-битный аналого-цифровой преобразователь (АЦП), имеющийся в данном микроконтроллере. Поскольку АЦП микроконтроллера ATmega32A не может на своем входе обрабатывать напряжение больше 5В, для увеличения диапазона рассматриваемого нами цифрового вольтметра мы применим делитель напряжения.

Цифровой вольтметр 0-25В на микроконтроллере AVR ATmega32: внешний вид

При проектировании схем с делителем напряжения следует принимать во внимание то, что входной ток на АЦП микроконтроллера AVR должен быть не менее 50 мкА. Поэтому следует правильно выбирать резисторы делителя напряжения чтобы минимизировать влияние нагрузки (loading effect) резистора на проходящий через делитель ток.

Схема делителя напряжения

Как показано на представленной схеме, мы будем использовать делитель напряжения на двух резисторах, поэтому при входном напряжении 25В мы на выходе этого делителя будем иметь 5В (при соответствующем подборе номиналов резисторов). Таким образом, для получения истинного значения измеряемого напряжения мы должны будем умножить измеренное (с выхода делителя) напряжение на 5.

Необходимые компоненты

Аппаратное обеспечение

Микроконтроллер ATmega32
Источник питания с напряжением 5 Вольт
Программатор AVR-ISP, USBASP или другой подобный
JHD_162ALCD (ЖК дисплей 16×2)
Конденсатор 100 мкФ
Конденсатор 100 нФ (5 шт.)
Резистор 10 кОм
Резистор 2,2 кОм
Переменный резистор 1 кОм

Программное обеспечение

Atmel Studio версии 6.1 (или выше)
Progisp или flash magic (необязательно)

Работа схемы

Схема устройства приведена на следующем рисунке.

Схема цифрового вольтметра на микроконтроллере AVR ATmega32

В представленной схеме PORTB микроконтроллера ATmega32 соединен с портом данным жидкокристаллического (ЖК) дисплея. При этом следует помнить о том, что необходимо деактивировать JTAG интерфейс микроконтроллера на порту PORTC при помощи изменения фьюзов (fuse bytes) если мы хотим использовать PORTC как обычный порт ввода/вывода. В ЖК дисплее (если мы не хотим использовать черный цвет) можно задействовать только 14 его контактов: 8 контактов для передачи данных (7-14 или D0-D7), 2 контакта для подачи питания (1&2 или VSS&VDD или gnd&+5v), 3-й контакт для управления контарстностью, 3 контакта для управления (RS&RW&E).

В представленной схеме мы использовали только 2 контакта управления ЖК дисплея для лучшего понимания работы схемы. Бит контраста и READ/WRITE используются нечасто, поэтому они могут быть замкнуты на землю. Это обеспечивает ЖК дисплею максимальную контрастность и переводит его в режим чтения. Теперь нам всего лишь нужно контролировать контакты ENABLE и RS чтобы передавать на ЖК дисплей символы и данные. Также на нашем сайте вы можете прочитать более подробную статью о подключении ЖК дисплея к микроконтроллеру AVR ATmega32.

В схеме необходимо сделать следующие соединения с ЖК дисплеем:
PIN1 или VSS — земля
PIN2 или VDD или VCC — +5v питание
PIN3 или VEE — земля (обеспечивает максимальный контраст ЖК дисплею)
PIN4 или RS (Register Selection) – контакт PD6 микроконтроллера
PIN5 или RW (Read/Write) — земля (переводит ЖК дисплей в режим чтения что упрощает взаимодействие с ним для начинающих)
PIN6 или E (Enable) — контакт PD5 микроконтроллера
PIN7 или D0 — контакт PB0 микроконтроллера
PIN8 или D1 — контакт PB1 микроконтроллера
PIN9 или D2 — контакт PB2 микроконтроллера
PIN10 или D3 — контакт PB3 микроконтроллера
PIN11 или D4 — контакт PB4 микроконтроллера
PIN12 или D5 — контакт PB5 микроконтроллера
PIN13 или D6 — контакт PB6 микроконтроллера
PIN14 или D7 — контакт PB7 микроконтроллера

В схеме мы использовали 8-битную связь (D0-D7) ЖК дисплея с микроконтроллером, хотя можно было ограничиться и 4-битной – но в этом случае код программы стал бы немного сложнее. Таким образом, мы использовали 10 контактов ЖК дисплея, 8 из которых будут использоваться для передачи данных и 2 для управления.

Напряжение на резисторе R2 (2,2 кОм) не будет полностью линейным – оно будет подвержено влиянию шума. Для борьбы с этим явлением в схеме параллельно резисторам делителя включены два конденсатора.

Переменный резистор 1 кОм служит для задания точности АЦП. В микроконтроллере ATMEGA32A мы можем подключить аналоговый выход к любому из восьми каналов PORTA – не важно к какому. В данной схеме мы использовали канал 0 (контакт 0) PORTA.

В микроконтроллере ATmega32A АЦП имеет разрешение (разрешающую способность) 10 бит, таким образом микроконтроллер способен реализовать чувствительность равную Vref/2^10, то есть если опорное напряжение (Vref) равно 5В мы получим цифровой инкремент на выходе 5/2^10 = 5мВ. Таким образом, на каждое приращение напряжения на 5 мВ мы будем получать один дополнительный инкремент цифрового выхода АЦП.

Для обеспечения работы схемы мы должны установить значения регистров АЦП следующим образом:

  1. Сначала мы должны активировать АЦП микроконтроллера.
  2. Максимальное входное напряжение для АЦП микроконтроллера составляет +5В (5*(12.2/2.2) =27.7В; поскольку R1 = 10 кОм and R2 = 2.2 кОм). Поэтому мы можем установить максимальное значение опорного напряжения АЦП равное 5В.
  3. АЦП микроконтроллера в нашей схеме будет начинать действовать при внешнем воздействии (не от действий пользователя), поэтому нам следует установить его в режим непрерывного преобразования (free running mode): в этом режиме запуск преобразований выполняется непрерывно через определенные интервалы времени.
  4. В любом АЦП частота преобразования аналогового значения в цифровое и точность цифрового выхода обратно пропорциональны. То есть для лучшей точности цифрового выхода мы должны выбрать меньшую частоту. Для этого мы должны установить коэффициент деления предделителя АЦП в максимальное значение (128). Поскольку мы используем внутреннюю частоту микроконтроллера 1 МГц, то значение частоты преобразования АЦП будет равно 1000000/128.

Четыре основных принципа работы с АЦП микроконтроллера мы рассмотрели, теперь нам нужно установить правильные значения в регистрах АЦП.

Регистр ADMUX АЦП микроконтроллера AVR ATmega32

Регистр ADCSRA АЦП микроконтроллера AVR ATmega32

RED (красный, ADEN): этот бит устанавливается чтобы задействовать функции АЦП в ATmega32A.

BLUE (синий, REFS1, REFS0): эти два бита используются для установки опорного напряжения (максимального входного напряжения, которое мы собираемся обрабатывать). Поскольку мы будем использовать опорное напряжение равное 5В, бит REFS0  необходимо выставить в соответствии с приведенной таблицей.

Установка битов REFS1, REFS0 в регистре ADMUX АЦП

LIGHT GREEN (светло зеленый, ADATE): этот бит должен быть установлен чтобы АЦП работал непрерывно (в режиме непрерывного преобразования).

PINK (розовый, MUX0-MUX4): эти 5 бит используются чтобы задать входной канал. Поскольку мы будем использовать ADC0 (PIN0) то, как следует из ниже приведенной таблицы, нам нет необходимости устанавливать все эти биты.

Установка битов MUX0-MUX4 в регистре ADMUX АЦП

BROWN (коричневый, ADPS0-ADPS2): эти три бита используются для установки коэффициент деления предделителя АЦП. Поскольку мы используем коэффициент деления предделителя 128, мы должны установить все эти три бита.

Биты для установки коэффициента деления предделителя АЦП

DARK GREEN (темно-зеленый, ADSC): этот бит необходимо установить для того чтобы АЦП начал осуществлять преобразование. Далее в программе мы можем его сбросить (в 0) если нам нужно будет остановить процесс аналого-цифрового преобразования.

Объяснение работы программы

Программа для рассматриваемой схемы представлена следующим фрагментом кода на языке С (Си). Комментарии к коду программы поясняют принцип работы отдельных команд.

/*
* C code for Digital Voltmeter using ATmega32 Microcontroller
*/
#include <avr/io.h> // заголовок чтобы разрешить контроль данных на контактах
#define F_CPU 1000000 // задание тактовой частоты микроконтроллера
#include <util/delay.h> // заголовок чтобы задействовать функции задержки в программе
#include <stdlib.h>
#define enable 5 // задействуем 5-й контакт PORTD (“enable”), поскольку он соединен с контактом “enable” ЖК дисплея
#define registerselection 6 // задействуем выбор регистра (“registerselection”) на 6-м контакте PORTD, поскольку он соединен с контактом RS ЖК дисплея
void send_a_command(unsigned char command);
void send_a_character(unsigned char character);
void send_a_string(char *string_of_characters);
int main(void)
{
DDRB = 0xFF; // установка portB на вывод данных
DDRA = 0; // установка portA на ввод данных
DDRD = 0xFF; // установка portD на вывод данных
_delay_ms(50);

ADMUX |=(1<<REFS0); // установка опорного напряжения для АЦП
ADCSRA |=(1<<ADEN)|(1<<ADATE)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
// активация АЦП, установка режима непрерывного преобразования, установка коэффициента деления предделителя АЦП 128

float voltage = 0;
char voltageshow [7];

send_a_command(0x01); // очистить экран 0x01 = 00000001
_delay_ms(50);
send_a_command(0x38); // сообщаем ЖК дисплею что мы будем использовать 8 битный режим
_delay_ms(50);
send_a_command(0b00001111); // включаем экран и мигание курсора на ЖК дисплее
_delay_ms(50);

ADCSRA |=(1<<ADSC);
while(1)
{
voltage = ADC/204.8*18;  // ADC/18.618;
send_a_string («CIRCUIT DIGEST «); // отображение строки
send_a_command(0x80 + 0x40 + 0); // установка курсора на 1 позицию 2 строки
send_a_string («VOLTAGE=»); // отображение строки
send_a_command(0x80 + 0x40 + 8); // установка курсора на 9-ю позицию 2 строки
dtostrf(voltage, 5, 2, voltageshow); //преобразование значения напряжения в строку
send_a_string(voltageshow);
send_a_string(«V «);
//dtostr(double precision value, width, precision, string that will store the numbers);
// Value – число, или переменная , содержащая число
//Width – общая длина числа, которое функция dtostrf должна преобразовать в строку, включающая точку и отрицательный знак числа(-). Например, если рассматриваем число -532.87, то его длина будет равна 7 (5 цифр + знак (-) + точка (.))
//Precision – задает точность преобразования, то есть сколько знаков после запятой учитывать
//Base – максимальное число значений для одной цифры. К примеру, 2 для двоичного представления числа (2 возможных значения для каждой цифры – 0 или 1). 10 – для привычной человеку десятичной системы счисления (10 возможных значений для каждой цифры — 0, 1, 2, 3, 4, 5, 6, 7, 8, or 9); 16 – для шестнадцатеричной системы счисления, в которой возможно 16 значений для каждой цифры — 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, или F. Следует понимать, что чем больше base (база), тем и требуемый алфавит будет больше.
//String – строковая переменная, которая будет хранить преобразованное число в виде последовательности символов.

send_a_command(0x80 + 0); // возвращаемся на 1 позицию
}
}
void send_a_command(unsigned char command)
{
PORTB = command;
PORTD &= ~ (1<<registerselection);
PORTD |= 1<<enable;
_delay_ms(2);
PORTD &= ~1<<enable;
PORTB = 0;
}
void send_a_character(unsigned char character)
{
PORTB = character;
PORTD |= 1<<registerselection;
PORTD |= 1<<enable;
_delay_ms(2);
PORTD &= ~1<<enable;
PORTB = 0;
}
void send_a_string(char *string_of_characters)
{
while(*string_of_characters > 0)
{
send_a_character(*string_of_characters++);
}
}

Видео, демонстрирующее работу схемы

(1 голосов, оценка: 5,00 из 5)
Загрузка...
154 просмотров


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *