Опубликовано 2013-04-30 12:35:19 автором Electrod

Цифровой вольтметр на микроконтроллере


Сегодня мы будем делать цифровой вольтметр на микроконтроллере. Повторив и осознав материал в этой статье, вы узнаете, как с помощью микроконтроллера можно измерить напряжение и вывести его на lcd дисплей. Для повторения нам понадобится микроконтроллер atmega8, lcd 16x2 знакосинтезирующий, пару резисторов, линейный стабилизатор напряжения lm317, для запитки микроконтроллера, ну, вроде, все.

Принципиальная схема устройства представлена ниже схема вольтметра на микроконтроллере atmega8 Для измерения напряжения используется встроенный в микроконтроллер АЦП – аналого-цифровой преобразователь (ADC- Analog-to-Digital Converter).Он преобразует аналоговый сигнал в цифровой. Для работы АЦП нужен источник опорного напряжения и напряжения, которое мы хотим оцифровать(оно должно быть меньше опорного). В нашем случае мы опорное напряжение будем брать с вывода питания АЦП AVCC. Детальней про использование ацп в avr написано в статье "Использование АЦП AVR". Напряжение на вывод АЦП подается через резистивный делитель R1 R2, потому что вход у нас низковольтный, от 0 до 5 вольт, а измерять нам нужно напряжение от 0 до 20 вольт. Для этого нужно использовать делитель с коэффициентом деления 4, то есть когда на вход резистивного делителя будет подаваться 20 вольт, на входе АЦП будет 5 вольт

Приступаем к программной части проекта. В CodeVision AVR кликаем по вкладке Tools->CodeWizardAVR для запуска автогенератора кода. Далее во вкладке Chip выбираем микроконтроллер Atmega8 и устанавливаем частоту 1 Mhz. Переходим во вкладку ADC(АЦП) и здесь ставим галочку возле ADC Enable, выбираем источник опорного напряжения Volt. Ref: здесь три варианта

  • AREF pin - опорное напряжение будет браться с ножки aref
  • AVCC pin - опорное напряжение будет браться с ножки питания АЦП avcc
  • Int., cap on aref - подключить внутренние конденсаторы на ножку aref
Мы выбираем AVCC pin, после этого выбираем частоту работы АЦП 500 Khz схема настройки ацп Все настройки по АЦП выполнены. Теперь нам нужно подключить lcd. Переходим во вкладку LCD, и выбираем порт, к которому будет подключен lcd, у меня это PORTD. Теперь все настройки выполнены, нужно сгенерировать код. Для этого кликаем File->Generate, Save and exit и даем имена исходным файлам

Исходный код проекта

#include <mega8.h>
#include <stdio.h> //библиотека в которой лежит функция sprintf 
#include <delay.h> 
 
// Alphanumeric LCD Module functions 
#asm 
   .equ __lcd_port=0x12 ;PORTD 
#endasm 
#include <lcd.h> 
 
#define ADC_VREF_TYPE 0x40 
 
// Read the AD conversion result 
unsigned int read_adc(unsigned char adc_input) 
{ 
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); 
// Delay needed for the stabilization of the ADC input voltage 
delay_us(10); 
// Start the AD conversion 
ADCSRA|=0x40; 
// Wait for the AD conversion to complete 
while ((ADCSRA & 0x10)==0); 
ADCSRA|=0x10; 
return ADCW; 
} 
 
void main(void) 
{ 
// Declare your local variables here 
   char buffer[32]; //переменная, в которой будет формироваться строка для вывода на lcd 
   int adc; //переменная для записи значений АЦП  
   int v; //переменная для сохранения значения реального напряжения в миливольтах 
// Input/Output Ports initialization 
// Port B initialization 
PORTB=0x00; 
DDRB=0x00; 
 
// Port C initialization 
PORTC=0x00; 
DDRC=0x00; 
 
// Port D initialization 
PORTD=0x00; 
DDRD=0x00; 
 
// Timer/Counter 0 initialization 
// Clock source: System Clock 
// Clock value: Timer 0 Stopped 
TCCR0=0x00; 
TCNT0=0x00; 
 
// Timer/Counter 1 initialization 
// Clock source: System Clock 
// Clock value: Timer1 Stopped 
// Mode: Normal top=FFFFh 
// OC1A output: Discon. 
// OC1B output: Discon. 
// Noise Canceler: Off 
// Input Capture on Falling Edge 
// Timer1 Overflow Interrupt: Off 
// Input Capture Interrupt: Off 
// Compare A Match Interrupt: Off 
// Compare B Match Interrupt: Off 
TCCR1A=0x00; 
TCCR1B=0x00; 
TCNT1H=0x00; 
TCNT1L=0x00; 
ICR1H=0x00; 
ICR1L=0x00; 
OCR1AH=0x00; 
OCR1AL=0x00; 
OCR1BH=0x00; 
OCR1BL=0x00; 
 
// Timer/Counter 2 initialization 
// Clock source: System Clock 
// Clock value: Timer2 Stopped 
// Mode: Normal top=FFh 
// OC2 output: Disconnected 
ASSR=0x00; 
TCCR2=0x00; 
TCNT2=0x00; 
OCR2=0x00; 
 
// External Interrupt(s) initialization 
// INT0: Off 
// INT1: Off 
MCUCR=0x00; 
 
// Timer(s)/Counter(s) Interrupt(s) initialization 
TIMSK=0x00; 
 
// Analog Comparator initialization 
// Analog Comparator: Off 
// Analog Comparator Input Capture by Timer/Counter 1: Off 
ACSR=0x80; 
SFIOR=0x00; 
 
// ADC initialization 
// ADC Clock frequency: 500,000 kHz 
// ADC Voltage Reference: AVCC pin 
ADMUX=ADC_VREF_TYPE & 0xff; 
ADCSRA=0x81; 
 
// LCD module initialization 
lcd_init(16); 
 
while (1) 
      {   
                 
           adc=read_adc(0); // читаем ацп с порта 0    
           /*так как АЦП у нас 10-битный, то максимальное число, которое вернет  функция, read_adc() 
           будет равно 1024, это число будет еквивалентом напряжения на входе adc0. 
           Например, если  read_adc() вернул 512, то это значит, что на вход adc0 мы подали половину опорного напряжения          
           Чтобы вычислить реальное напряжение, нам нужно составить пропорцию 
            опорное напряжения - 1024 
            искомое напряжения - adc 
            У нас опорное напряжение=5.12 
            Искомое напряжение =  5.12*adc/1024, или Искомое напряжение = 0,005*adc  
            для простоты переведём вольты в миливольты,  домножив на 1000 
            Искомое напряжение = 0,005*adc*1000 
            Здесь всё хорошо, но мы не учли коефициент резисторного делителя напряжения 
            У нас он равен Кдел=(R1+R2)/R2.      Подставив, получим 
            Кдел=(15+5)/5=4 
            Реальное напряжение =  0,005*adc*1000*4 
            */ 
            v=20*adc; 
           sprintf(buffer,"V = %i mv",v); //формируем строку для вывода  
           lcd_clear(); //чистим дисплей перед выводом 
           lcd_puts(buffer);  //выводим сформированую строку на дисплей  
           delay_us(700);   //делаем задержку 
      }; 
}

Все необходимое для реализации вольтметра находится в архиве Voltmeter.rar

Комментарии - (1)

  • rvk говорит:
    Добрый день! С простым вольтметром все понятно. Спасибо большое! Есть двухканальный вольметр или больше, 3, 4 канала. Они все паралленые. Вход один резистивные делители разные. Как в таком случае работать програмно? например: 1 канал - 0.00 9.99 В, 2 - 10.0 - 99.9 В подаем напряжение больше 10 В и что? лапа микроконтроллера, корорая делителем расчитана до 10 В сгорает? А если подать 100 В? Поможет ли в этом случае стабилитрон? Вот таким вопросом я задаюсь! Поможете с этим разобраться? Я задаюсь вопросом:

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

Для отправки комментария вы должны авторизоваться.