Простой вольтметр-амперметр можно собрать на микроконтроллере Atmega8. Вывод информации осуществляется на символьный LCD дисплей 16x2.
Для работы нам понадобятся два канала АЦП, это каналы ADC0 и ADC1, при помощи одного мы мерием напяржение при помощи другого силу тока. В качестве источника внутренного напряжения используется внтуренней опорное напряжение в 2.56 В. АЦП работают с разрядность в 10 бит. Микроконтроллер Atmega8 затактирован от внутреннего RC генератора с частотой в 4 МГц.
Вывод информации на дисплей осуществляется следующим образом:
Напряжение которое нам нужно померить сначала подается на делитель напряжения, и уже с него подается на вход АЦП 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 раз, далее вычисляется среднее значение и выводятся на символьный дисплей.
// Измерение постоянного тока с помощью 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); } }
Комментарии
Судя по фюзам на картинке - CKSEL3 0 CKSEL2 0 CKSEL1 0 CKSEL0 1 (без инверсии) - это 1 МГц.
Как мне кажется ток невозможно измерить на прямую,не случайно во всех измерительных приборах,которы е могут измерить ток,
присутствует шунт,поэтому измеряя ток прибором его подключают в разрыв цепи и по падению напряжения во внутреннем шунте
прибора измеряется ток.