Speed Control of a DC Motor using Digital Control The scope of this project is threefold. The first part of the project is to control an LCD display and use it as part of a digital tachometer. Secondly, we need to develop a PI controller for controlling the speed of a DC motor. Thirdly, we need to deliver our control signal to an H-bridge to control speed and direction of the DC motor. LCD Display Driver LCD displays come in a variety of configurations, multiline, graphical, and color displays. A lot of these displays are controlled by the Hitachi HD44780 or compatible controller. For our purposes we selected the MDLS-81809 display which is a single line, eight character display. This was selected because we need to display 10000rpm and this would be adequate. Digital Tachometer with Voltage Output 0-73kHz approx. input
LCD display reads 0-10000 rpm approx. 8-bits out on PORTC to give D/A input this code is written with Hi-Tech C Lite for a 16f877 with 10MHz oscillator compile with config bits osc = xt, wdt & put & cp & bod & lvp & derp & fpw all off include standard pic header file #include <pic.h> define lcd signals to port bits #definelcd_rs #definelcd_rw #define lcd_en #define busy_bit #define direction RE2 RD7 RC0 RE1 RE0 #define lcd_data PORTD define global variables int count; int temp,temp1,temp2,temp3,temp4; int tempcount,advalue; initialization routine void init(void) TRISD = 0; TRISB = 0; TRISC = 0; port d is output port b is output port c is output
TRISA = 0xff; port a is input PORTD = 0; port d value = 0 PORTB = 0; port b value = 0 PORTC = 0; port c value = 0 INTCON = 0xc0; PIE1 = 0x01; ADCON1 = 0x04; ADCON0 = 0x89; T1CON = 0x31; global and peripheral interrupts enabled timer1 interrupt enabled port a and e are digital inputs prescale = 8, Fosc/4 input, timer on OPTION = 0x24; ra4 input to timer0 prescale = 32 TMR1H = 0x94; TMR1L = 0x58; timer interval to give full scale output Interrupt Service Routine static void interrupt isr(void) if (TMR1IF) T1CON &= 0xfe; count = TMR0; TMR0 = 0; test for timer1 interrupt timer1 off read timer0 value reset timer0 TMR1H = 0x94; TMR1L = 0x58; TMR1IF = 0; T1CON = 0x01; restore timer1 value clear interrupt flag timer1 on Routine that gives 1ms delay with 10MHz oscillator
void delayms(void) int i; for (i=1;i<180;i++); void initpwm(void) PR2 = 0x3f; CCPR1L = 0; period register CCP1X = 0; least sig. bits of duty cycle CCP1Y = 0; T2CKPS1 = 0; prescale timer 1 TMR2ON = 1; turn timer on CCP1M3 = 1; for PWM mode CCP1M2 = 1; for PWM mode void speedup(void) int i,j; tempcount = advalue; for (i=0;i<tempcount;i=i+10) CCPR1L = i; for (j=0;j<5;j++) 5ms delay void slowdown(void) int i,j; tempcount = advalue;
for (i=tempcount;i>0;i=i-10) CCPR1L = i; for (j=0;j<5;j++) 5ms delay void getad(void) GODONE = 1; while (GODONE) advalue = ADRESH; start A/D conversion wait for completion read upper 8 bits adn save in advalue test for lcd busy flag this routine is not used void lcdbusy(void) unsigned int busydata; TRISD = 0xff; lcd_rs = 1; lcd_rw = 1; lcd_en = 1; portd input data mode read operation enable lcd while (busy_bit!= 0); wait for busy bit to go low lcd_rs = 0; control lines back to 0 lcd_rw = 0; lcd_en = 0; TRISD = 0; portd output
sends a command to the lcd display void lcdputcmd(int cmd) int i; lcd_data = cmd; lcd_rw = 0; lcd_rs = 0; lcd_en = 1; lcd_en = 0; for (i=0;i<5;i++) put command on portd write operation command mode enable lcd 5ms delay void lcdclr(void) lcdputcmd(0x01); clear lcd display Sends data to be displayed on lcd void lcdputdata(int dat) lcd_data = dat; put data on portd lcd_rw = 0; write operation lcd_rs = 1; data mode lcd_en = 1; enable lcd lcd_en = 0; control lines back to 0 lcd_rs = 0; initialize lcd display
void lcdinit(void) lcdputcmd(0x30); lcdputcmd(0x0e); lcdputcmd(0x06); function set 8x1 display entry mode display mode main() int i,j; init(); initialize pic initpwm(); getad(); speedup(); for (j=0;j<4;j++) for(i=0;i<1900;i++); delay for lcd to power up lcdinit(); initialize lcd display while(1) getad(); tempcount = count + count + count + count; convert and display count if (count < advalue) direction = 0; CCPR1L = advalue + (advalue - count)/4; else direction = 0; CCPR1L = advalue - (count - advalue)/4; resolution of 40rpm temp = tempcount/1000; lcdputdata(0x30+temp);
temp1 = (tempcount - temp * 1000)/100; lcdputdata(0x30+temp1); temp2 = (tempcount - temp * 1000-temp1*100)/10; lcdputdata(0x30+temp2); temp3 = (tempcount - temp * 1000-temp1*100-temp2*10)/1; lcdputdata(0x30+temp3); lcdputdata('0'); lcdputdata('r'); lcdputdata('p'); lcdputdata('m'); for(j=0;j<100;j++) lcdclr();