Saturday, 20 March 2010

Temperature Controls DC Motor Speed


I have been experimenting with different features of Atmel microcontrollers for some time now. In this project I used the temperature value of an LM35 to control the speed of a DC motor. I also showed the value of the temperature in degree celcius and motor current and motor speed percentage. I worked on this project basically to improve my skills on control system design. I can easily convert this project to control a industrial scale Induction motor. Though the circuit would be a lot bigger as I have to use inverters to control the speed and the starting of the induction motor will need some careful designing which depends on the motor size.

I intend to add some buffer ICs between the ADC pins and the measurement point. However I did not use them in proteus simulation as those ICs take too much space.

I used fleury's LCD library for HDD44780.
#include
#include
#include
#include "lcd.h"
#include



#define F_CPU 8000000UL

//double ADC_value;
long temp[5];


ISR(INT0_vect)
{
PORTB ^= 0x01;

switch(PORTB & 0x01)
{
case 0x01:
{
lcd_gotoxy(0, 0);
lcd_puts("ON ");
break;
}
default:
{
lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts("OFF");
lcd_gotoxy(0, 1);
lcd_puts("Temperature:");
OCR0 = 0x00;
break;
}
}
}

long ReadADC()
{
while((ADCSRA & 0x40) != 0) {};
return ADC;
}

void TemperatureControl()
{
cli();
double avg;
unsigned char i;
char ch[4];
ADMUX = 0x40;
ADCSRA = 0xB0;
ADCSRA |= (1<
for(i=0; i<5;>
temp[i] = ReadADC();
avg = (temp[0] + temp[1] + temp[2] + temp[3] + temp[4]) * .09765625;
// avg = avg * 100;
lcd_gotoxy(12,1);
dtostrf(avg, 4, 1, ch);
lcd_puts(ch);
if((PORTB & 0x01) == 0x01)
{
avg = avg * 10.2;
dtostrf(avg, 4, 1, ch);
if(avg<255)
{
OCR0 = atoi(ch);
avg = avg * 100;
avg = avg / 255;
dtostrf(avg, 4, 1, ch);
lcd_gotoxy(6, 0);
lcd_puts(ch);
lcd_putc('%');
}
else
{
OCR0 = 254;
lcd_gotoxy(6, 0);
lcd_puts("100% ");
}
}
sei();
ADCSRA = 0x00;
}

void CurrentMeasure()
{
cli();
double avg;
unsigned char i;
char ch[4];
ADMUX = 0x40;
ADCSRA = 0xB7;
ADCSRA |= (1<
for(i=0; i<5;>
temp[i] = ReadADC();
avg = (temp[0] + temp[1] + temp[2] + temp[3] + temp[4]) * .48828125;
// avg = (temp[0] + temp[1] + temp[2] + temp[3] + temp[4]) * .019148284;
// avg (avg>>11);
// avg = avg * 1000;
dtostrf(avg, 4, 1, ch);
lcd_gotoxy(12,0);
lcd_puts(ch);
ADCSRA = 0x00;
sei();
}


void pwm_init()
{
TCNT0 = 0x00;
OCR0 = 0x00;
TCCR0 |= (1<<<<
}

int main()
{
DDRB = 0xF9;
PORTB = 0x00;
DDRD = 0x70;
PORTD = 0x00;
// DDRC = 0x00;
lcd_init(LCD_DISP_ON);
lcd_puts("OFF");
// ADC_init();
// lcd_puts_P("ADC Test: ");
lcd_gotoxy(0, 1);
lcd_puts("Temperature:");
pwm_init();
MCUCR |= (1<<
GICR |= (1<
sei();
while(1)
{
TemperatureControl();
if((PORTB & 0x01) == 0x01)
CurrentMeasure();
}
}

I used dtostrf() function to convert the double value to char. I searched a lot before finally I looked into the libc documentation. I didnt know about this function before. So anyone who wants to convert his double value to char value dtostrf() is the best solution. I think I should have used a 4line lcd display. Putting everything there in 2lines was quite difficult.

I plan to implement this by the end of this week.