Опубликовано 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

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

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

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

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