Опубликовано 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  
                Шуканa напруга = 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 В? Поможет ли в этом случае стабилитрон? Вот таким вопросом я задаюсь! Поможете с этим разобраться? Я задаюсь вопросом:

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

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