Микроконтроллеры

Вольтметр-Амперметр на микроконтроллере Atmega8

Простой вольтметр-амперметр можно собрать на микроконтроллере Atmega8. Вывод информации осуществляется на символьный LCD дисплей 16x2. 

  • диапазон измеряемого напряжения: 0 до 25 В;
  • диапазон тока: от 0 до 2.5 В;

Для работы нам понадобятся два канала АЦП, это каналы ADC0 и ADC1, при помощи одного мы мерием напяржение при помощи другого силу тока. В качестве источника внутренного напряжения используется внтуренней опорное напряжение в 2.56 В. АЦП работают с разрядность в 10 бит. Микроконтроллер Atmega8 затактирован от внутреннего RC генератора с частотой в 4 МГц. 

Схема Вольтметра-Амперметра на микроконтроллере Atmega8

Схема Вольтметра-Амперметра на микроконтроллере Atmega8

Вывод информации на дисплей осуществляется следующим образом:

volt-ampermetr1

Напряжение которое нам нужно померить сначала подается на делитель напряжения, и уже с него подается на вход АЦП ADC1. Делить собран на резисторах с номиналами в 100 кОм и 10 кОм, получается что отношение входного и выходного напряжения 10 к 1. Максимальное напряжение которое можно подать на вход делителя составляет 28.13 В.

Для того чтобы померить силу тока нам понадобится токовый шунт, его включаем в разры цепи ток в которой хотим померть. Падение напряжения на шутнте нетрудно определить по закону Ома, эта величина меряется други АЦП ADC0. Нужно стремится к уменьшению сопротивлению шунта, чем он меньше тем лучше. Если сопротивление равно 0,1 Ом то при силе тока в 1 Ампера получается падение напряжения в 0,1В.

Если у нас ток в 2 А то падение напряжения составит 0,2 В. Это значение очень мало для того чтобы его подать на вход АЦП микроконтроллера, поэтому его можно устелить при помощи ОУ (операционного усилителя). В нашем примере можно использовать схему неинвертирующего усилителя. Коэффициент усиления составит

Ku=1+(R2/R2)

Нудно чтобы это коэффициент был равен 10, для того чтобы измеряемы ток, к примеру 1 А соответствовал напряжение на выходе ОУ в 2В. В связи с тем что ИОП (источник опорного напряжения) 2.56 В. то мы не может подать больше этого значения. Шаг измерения тока состовит: 2.56А/2024=2.5 мА.

Таким образом для того чтобы получить значение тока, нам нужно напряжение измеренное АЦП умножить на 2.5 

Измерение происходит по прерыванию окончания преобразования АЦП. Сначала выбирается канал 1 и снимается напряжения, далее выбирается второй и также снимается напряжение. Измерения каналов происхоид 400 раз, далее вычисляется среднее значение и выводятся на символьный дисплей.

Схема установки Fuse битов

Схема установки Fuse битов

Код программы Амперметра-Вольтметра 

// Измерение постоянного тока с помощью AVR
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h> 
unsigned int voltage, current, adc_counter;
volatile unsigned long voltage_value, current_value;
// Функции работы с LCD 
#define RS PD0 
#define EN PD2
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')
{  
lcd_data(*string);
string++;
}
}
// Функция вывода переменной
void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
switch(nDigit)
{
case 4: lcd_data((value/1000)+'0');
case 3: lcd_data(((value/100)%10)+'0');
case 2: lcd_data(((value/10)%10)+'0');
case 1: lcd_data((value%10)+'0');
}
}
// Функция инициализации LCD
void lcd_init(void)
{
DDRD = 0xFF;
PORTD = 0x00;
_delay_ms(50); // Ожидание готовности ЖК-модуля
// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);
// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5); 
lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}
// Обработчик прерывания от АЦП
ISR(ADC_vect)
{
ADCSRA = 0; // Выключаем АЦП 
if((ADMUX & 0x0F)==1) // Если был выбран канал ADC1
{
voltage_value = voltage_value + ADC; // Суммируем измеренные значения напряжения и помещаем в буфер
ADMUX = (ADMUX & 0xF0) | 0; // Выбираем канал ADC0
}
else
{
current_value = current_value + ADC; // Суммируем измеренные значения тока и помещаем в буфер
ADMUX = (ADMUX & 0xF0) | 1; // Выбираем канал ADC1
adc_counter++; // Увеличиваем счетчик выборок АЦП на 1
}
// Включаем АЦП
ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE);
}
int main(void) 
{
ADMUX |= (1 << REFS1)|(1 << REFS0); // Внутренний ИОН 2,56V
ADMUX |= (1 << MUX0); // Подключаем канал ADC1
ADCSRA |= (1 << ADEN) // разрешение АЦП
	|(1 << ADSC) // запуск преобразования
                |(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0) // предделитель на 128
	|(1 << ADIE); // разрешение прерывания от АЦП
sei(); // Глобально разрешаем прерывания
lcd_init(); // Инициализация LCD
_delay_ms(25);
lcd_string(0x80	,"VOLTS  * AMPERES");
lcd_string(0xC0	,"  .    *  .     ");
while(1) 
{
// вычисляем среднее значение АЦП
if (adc_counter > 400)
{
ADCSRA = 0; // Выключаем АЦП 
// преабразуем данные в реальное значение напряжения
voltage = (voltage_value/adc_counter) * 11/4;
// преабразуем данные в реальное значение тока
current = (current_value/adc_counter) * 10/4;
adc_counter = 0; // Обнуляем счетчик выборок АЦП
voltage_value = 0; // Обнуляем буфер значений напряжения
current_value = 0; // Обнуляем буфер значений тока
// Выводим данные на LCD
lcd_com(0xC0);
lcd_num_to_str(voltage/100, 2);
lcd_com(0xC3);
lcd_num_to_str(voltage, 2);
lcd_com(0xC9);
lcd_num_to_str(current/1000, 1);
lcd_com(0xCB);
lcd_num_to_str(current, 3);
// Включаем АЦП
ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE);
}   
_delay_ms(1);
}
}

Исходники программы 

Комментарии  

 
#1 Pavel 04.03.2017 13:44
Здравствуйте. В каком компиляторе написан код? CVAVR выдает кучу ошибок
Цитировать
 
 
#2 Pavel 04.03.2017 14:31
Разобрался. Атмел студия проглотила код и выдала хекс
Цитировать
 
 
#3 Pavel 21.03.2017 15:26
Собрал данный вольт-амперметр . LCD 1602. Работает безупречно. Подскажите, как в индикации амперметра переместить запятую на один разряд правее. Спасибо
Цитировать
 
 
#4 Tol 06.04.2017 14:34
Вопрос. Откуда взялось 11/4 и как оно изменится, если я например буду использовать источник питания не на 2,56В, а к примеру на 1В?
Цитировать
 
 
#5 Дядя Вася 23.06.2017 05:06
диапазон тока: от 0 до 2.5 В - ток в вольтах? видать, рано тебе еще амперметрі делать, лучше фантики собирай
Цитировать
 
 
#6 Дядя Вася 24.06.2017 01:44
Цитата: "Микроконтролле р Atmega8 затактирован от внутреннего RC генератора с частотой в 4 МГц."
Судя по фюзам на картинке - CKSEL3 0 CKSEL2 0 CKSEL1 0 CKSEL0 1 (без инверсии) - это 1 МГц.
Цитировать
 
 
#7 Sergey 09.01.2018 21:01
Дядя Вася ток всегда меряется по падению напряжения на шунте.
Как мне кажется ток невозможно измерить на прямую,не случайно во всех измерительных приборах,которы е могут измерить ток,
присутствует шунт,поэтому измеряя ток прибором его подключают в разрыв цепи и по падению напряжения во внутреннем шунте
прибора измеряется ток.
Цитировать
 

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


Защитный код
Обновить

Последние комментарии

Последнии темы форума

  • Нет сообщений для показа