Амперметр на 100 мА на микроконтроллере AVR ATmega8

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

Амперметр на 100 мА на микроконтроллере AVR ATmega8: внешний вид

В этом методе мы будем пропускать ток, силу которого необходимо измерить, через резистор с маленьким сопротивлением. Измеряя напряжение на этом резисторе с помощью АЦП микроконтроллера мы сможем определить и интересующую нас силу тока. Измеренное значение тока мы будем показывать на жидкокристаллическом (ЖК) дисплее 16х2.

В схеме мы будем использовать делитель напряжения на резисторах. Измеряемый ток будем пропускать через всю цепочку резисторов, а измерять напряжение будем в средней точке делителя. Напряжение в этой точке будет изменяться по линейному закону в зависимости от величины тока, протекающего через делитель напряжения.

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

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

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

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

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

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

Работа схемы

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

Схема амперметра на 100 мА на микроконтроллере AVR ATmega8

Принципы взаимодействия микроконтроллера AVR с ЖК дисплеем можно изучить в этой статье (или, если в сокращенной форме, то в этой).

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

Аналого-цифровой преобразователь (АЦП) микроконтроллера ATmega8 может быть использован на любом из четырех каналов PORTC – мы выберем канал 0 (PIN0) PORTC.

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

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

  1. Сначала мы должны активировать АЦП микроконтроллера.
  2. Затем необходимо установить максимальное входное напряжение для АЦП равное 5В. Это можно сделать путем установки значения опорного напряжения АЦП равного 5В.
  3. АЦП микроконтроллера в нашей схеме будет начинать действовать при внешнем воздействии (не от действий пользователя), поэтому нам следует установить его в режим непрерывного преобразования (free running mode): в этом режиме запуск преобразований выполняется непрерывно через определенные интервалы времени.
  4. В любом АЦП частота преобразования аналогового значения в цифровое и точность цифрового выхода обратно пропорциональны. То есть для лучшей точности цифрового выхода мы должны выбрать меньшую частоту. Для этого мы должны установить коэффициент деления предделителя АЦП в максимальное значение (2). Поскольку мы используем внутреннюю частоту микроконтроллера 1 МГц, то значение частоты преобразования АЦП будет равно 1000000/2.

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

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

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

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

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

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

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

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

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

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

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

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

Для лучшего понимания этой статьи можно также прочитать статью о цифровом вольтметре на микроконтроллере AVR.

Исходный код программы на языке С (Си) с пояснениями

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

#include <avr/io.h> // заголовок чтобы разрешить контроль данных на контактах
#define F_CPU 1000000 // задание тактовой частоты микроконтроллера
#include <util/delay.h> // заголовок чтобы задействовать функции задержки в программе
#include <stdlib.h>
#define enable 1 // задействуем контакт PB1 PORTB (“enable”), поскольку он соединен с контактом “enable” ЖК дисплея
#define registerselection 0 // задействуем PB0 PORTB (“enable”), поскольку он соединен с контактом 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)
{
DDRD = 0xFF; // установка portD на вывод данных
DDRC = 0; // установка PC0/ADC0 (вход АЦП) на ввод данных
DDRB= 0xFF; // установка portB на вывод данных

ADMUX |=(1<<REFS0); // установка опорного напряжения для АЦП
ADCSRA |=(1<<ADEN)|(1<<ADPS0)|(1<<ADFR);
// активация АЦП, установка режима непрерывного преобразования, установка коэффициента деления предделителя АЦП 2
float i =0;
float CURRENT = 0;
char CURRENTSHOW [7];

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

ADCSRA |=(1<<ADSC); //старт АЦП
send_a_string ("CIRCUIT DIGEST "); // отображение строки "CIRCUIT DIGEST "
send_a_command(0x80 + 0x40 + 0); // переводим курсор на 1 позицию второй строки
send_a_string ("CURRENT="); // отображение строки "CURRENT="
send_a_command(0x80 + 0x40 + 8); // переводим курсор на 10 позицию второй строки

while(1)
{
i=ADC/204.8;
CURRENT = (2*i*1000)/2.7; // ADC/18.618; - вычисление значения тока
dtostrf(CURRENT, 4, 1, CURRENTSHOW); //преобразуем число в строку
send_a_string(CURRENTSHOW);
send_a_string("mAmp");
//ADCSRA &=~(1<<ADSC);
//ADCSRA |=(1<<ADSC);
_delay_ms(50);
send_a_command(0x80 + 0x40 + 8);

//dtostr(double precision value, width, precision, string that will store the numbers);
// Value – число, или переменная , содержащая число
//Width – общая длина числа, которое функция dtostrf должна преобразовать в строку, включающая точку и отрицательный знак числа(-). Например, если рассматриваем число -532.87, то его длина будет равна 7 (5 цифр + знак (-) + точка (.))
//Precision – задает точность преобразования, то есть сколько знаков после запятой учитывать

}
}
void send_a_command(unsigned char command)
{
PORTD = command;
PORTB &= ~ (1<<registerselection); // устанавливаем RS в 0 чтобы сообщить ЖК дисплею что мы будем передавать команду
PORTB |= 1<<enable; // сообщаем ЖК дисплею чтобы он принял команду/данные
_delay_ms(2);
PORTB &= ~1<<enable; // сообщаем ЖК дисплею что мы закончили передачу данных
PORTD = 0;
}
void send_a_character(unsigned char character)
{
PORTD = character;
PORTB |= 1<<registerselection; // сообщаем ЖК дисплею что мы будем передавать данные (не команду)
PORTB |= 1<<enable; // сообщаем ЖК дисплею чтобы он начал прием данных
_delay_ms(2);
PORTB &= ~1<<enable; // сообщаем ЖК дисплею что мы закончили передачу данных
PORTD = 0;
}
void send_a_string(char *string_of_characters)
{
while(*string_of_characters > 0)
{
send_a_character(*string_of_characters++);
}
}

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

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


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

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