Опубликовано 2013-05-03 15:02:21 автором Ruslan

Цифровий Ватметр


Купив я тут днями велосипедне мотор- колесо. Давно мріяв, і ось воно, у всій красі!

мотор колесо 500 w

Мотор постійного струму, вентильний, 48в, 500ват. Китайці обіцяють ККД близько 85%, що вже непогано для такої мощності. До нього в комплекті йшов контролер 800 ват, ручки газу і гальма. Блок акумуляторів - 4шт, 12в, 9а/часов і зарядний пристрій до них купував окремо.

Зібрав я все це добро на свій старий гірський велик

електріческій велосіпед

Перші враження від електротяги просто не передати словами! Крутний момент максимальний з самого старту ( розганяється швидше 50- кубового скутера), максималка 45 км/год.

Обкатавши все це добро, мені захотілося прикрутити до нього якусь фічу, що - небуть для індикації витрат енергії. Тут сам собою напросився цифровий ватметр.

У попередніх статях ми навчилися міряти напругу і струм . Для того, щоб виміряти споживану потужність, потрібно напругу помножити на струм: ВТ = В * А. По суті, ватметр - це амперметр і вольтметр в єдиному пристрої.

Давайте об'єднаємо схеми амперметра і вольтметра , описані в попередніх статтях, і отримаємо схему ваттметра:

схема ваттметра на мк

Ватметр побудований на мікроконтролері atmega8 , який заслужено займає статус народного. Струм, напруга і потужність виводяться на Lcd -дисплей 16x2. На резисторах R8, R9 побудований дільник напруги з коефіцієнтом ділення 11, джерело опорної напруги виконаний на регульованому стабілітроні TL431 і налаштований на напруги 5.12 вольт.Ток вимірюється шляхом вимірювання падіння напруги на шунті R2, далі це падіння напруги посилюється операційним підсилювачем Lm358 і надходить на вхід АЦП adc0.

Програма написана на CodeVisionAVR

# include <mega8.h>  
# include <delay.h>  
# include <stdio.h>  // бібліотека в якій лежить функція sprintf  
 
 // Alphanumeric LCD Module functions  
# asm  
   . equ __ lcd_port = 0x12 ; PORTD  
# endasm  
# include <lcd.h>  
    
# define ADC_VREF_TYPE 0x00  
 
 // 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 )  
{  
char buffer [ 32] ;  // змінна в якій буде формуватися рядок для виведення на lcd  
unsigned long int u ;  // змінна для зберігання напруги в мілівольтах  
unsigned long int a ;  // змінна для зберігання струму  
unsigned long int w ;  // змінна для зберігання значень споживаної потужності  
PORTB = 0x00;  
DDRB = 0x00;  
 
 // Port C initialization  
PORTC = 0x00;  
DDRC = 0x00;  
 
 // Port D initialization  
PORTD = 0x00;  
DDRD = 0x00;  
 
 // Timer / Counter 0 initialization  
TCCR0 = 0x00;  
TCNT0 = 0x00;  
 
 // Timer / Counter 1 initialization  
TCCR1A = 0x00;  
TCCR1B = 0x00;  
TCNT1H = 0x00;  
TCNT1L = 0x00;  
ICR1H = 0x00;  
ICR1L = 0x00;  
OCR1AH = 0x00;  
OCR1AL = 0x00;  
OCR1BH = 0x00;  
OCR1BL = 0x00;  
 
 // Timer / Counter 2 initialization  
ASSR = 0x00;  
TCCR2 = 0x00;  
TCNT2 = 0x00;  
OCR2 = 0x00;  
 
 // External Interrupt ( s ) initialization  
MCUCR = 0x00;  
 
 // Timer ( s ) / Counter ( s ) Interrupt ( s ) initialization  
TIMSK = 0x00;  
 
 // Analog Comparator initialization  
ACSR = 0x80 ;  
SFIOR = 0x00;  
 
 // ADC initialization  
 // ADC Clock frequency : 500,000 kHz  
 // ADC Voltage Reference : AREF pin  
ADMUX = ADC_VREF_TYPE & 0xff ;  
ADCSRA = 0x81 ;  
 
 // LCD module initialization  
lcd_init ( 16 ) ;  
 
while ( 1)  
      {  
       a = read_adc ( 0);  // читаємо значення АЦП з порту 0  
       u = read_adc ( 1);  // читаємо значення АЦП з порту 1  
           /*  
                   1.  Вимірюємо струм 
            Струм, що протікає через шунт , вічісляется за законом Ома : I = U / R  
            R = 0,1 ом , a U (падіння напруги на шунт ) ми будемо вимірювати .  
            Так як АЦП у нас 10 - бітний , то максимальне число , яке поверне функція read_adc , ()  
            дорівнюватиме 1024 , це число буде еквівалентом напруги на вході adc0 .  
            Наприклад , якщо read_adc ( ) повернув 512 то це означає , що на вхід adc0 ми подали половину опорного напруги  
            Щоб обчислити реальна напруга , нам потрібно скласти пропорцію:  
            опорна напруга - 1024  
            шукане напруга - a  
            У нас опорна напруга = 5.12  
            Шукане напруга = 5.12 * a/1024 , або Искомое напруга = 0,005 * a  
            для простоти переведемо вольти в мілівольтах , Домножимо на 1000  
            Шукане напруга = 0,005 * a * 1000  
            Тут все добре , але ми не врахували коеффициент посилення ЗУ  
            розраховується за формулою: Кус = 1 + R1/R2 . Підставивши , одержимо:  
            Кус = (1 +4) = 5  
            Реальне напруга = 0,005 * a * 1000 /5 , отримуємо просто a  
                  2.  Вимірюємо напругу   
            Далі вимірюємо напруга на резисторного дільнику  
            Складемо пропорцію , як описано вище , і отримаємо :  
            Шукане напруга = 0,005 * u * 1000  
            Треба ще врахувати коеффициент резисторного дільника напруги  
            у нас він дорівнює Кдел = (R1 + R2) / R2. Підставивши , одержимо:  
            Кдел = (10 +1 ) / 1 = 11  
            Реальне напруга = 0,005 * u * 1000 * 11  
            */  
               
            u = 55 * u ;  // обчислюємо значення напруги в мілівольтах  
            a = a * 10 ;  // обчислюємо значення струму за законом Ома : I = U / R = a/100 * 1000 = a * 10 в міліамперах  
            w = a * u ;  // обчислюємо споживану потужність  
           sprintf ( buffer , "I = % u , % u U = % u , % u W = % u , % lu " ,  
                     a/1000 ,  // Ціла честь струму  
                     ( a % 1000 ) / 10 ,  // Дрібна частина струму  
                     u/1000 ,  // Ціла частина напруги  
                     ( u % 1000 ) / 10 ,  // Дрібна частина напруги  
                     w/1000000 ,  // Ціла частина потужності  
                     ( w % 1000000) / 10000  
                    ) ;  // Формуємо рядок для виведення  
           lcd_clear ();  // чистимо дисплей перед виведенням  
           lcd_puts ( buffer ) ;  // виводимо сформованості рядок на дисплей  
           delay_ms (100);  // робимо затримку  
 
      } ;  
}

Для того , щоб функція sprintf могла працювати зі змінними типу long int , необхідно провести додаткові налаштування. Для CodeVision AVR : Project - > Configure -> C compiler -> ( S ) printf Features - > Вибрати пункт " long , width , precision " . Проект у Протеус і вихідний код програми в архіві Watmeter.rar

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

  • Виктор говорит:
    Скажите, а почему мигает индикатор? Я думал что мигает только в протеусе, собрал в железе, то же самое.. ((
  • AdminRu говорит:
    Здравствуйте. Мигает потому что частота обновления слишком маленькая, нужно увеличить частоту работы мк, до 4 мегагерц
    • Виктор говорит:
      А как сделать чтобы показания так не прыгали? Я пытаюсь измерять напругу от транса через диодный мост и кондеры. Но прыжки нереальные. Как устаканить контроллр?
      • AdminRu говорит:
        Добрий день. В каком диапазоне прыжки? попробуйте измерить напряжение какого нибудь постоянного источника например батарейки, сообщите результат.
  • nick говорит:
    если не секрет - а где купили моторколесо?
  • Максим говорит:
    Добрый день. Неплохо было бы добавить часы и считать емкость (ампер*час) чтобы видеть: во время зарядки(для этого надо мерять "отрицательный" ток) - насколько "живые" аккумуляторы; во время езды - видеть сколько еще заряда осталось... ну и по скорости вычислять на сколько метров(километров) еще хватит(но для этого надо приделать датчик холла или геркон на вилку и магнит на спицу)
    • AdminRu говорит:
      В мотор колесе уже есть аж три датчика хола, так что скорость и километраж вычислить не проблема

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

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