Купил я тут на днях велосипедное мотор-колесо. Давно мечтал, и вот оно, во всей красе!Мотор постоянного тока, вентильный, 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
/*
- Измеряем ток Ток, протекающий через шунт, вичисляется по закону Ома: 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
- Измеряем напряжение
Дальше измеряем напряжение на резисторном делителе
Составим пропорцию, как описано выше, и получим:
Искомое напряжение = 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". Проект в протеусе и исходний код программы в архиве.
АРХИВ:Скачать