Project 1 - Controlling a DC motor using PWM and monitoring its Running status
Controlling a DC motor using PWM and monitoring its Running status
PWM Mode:
For PWM mode sellected PWM correct mode of Operation of Atnega 32 of timer0.
that is TCCR0=01100001;
From the last three bits we are sellected the no-pre scaling mode of operation.
In the PWM correct mode we have sellected Clear OC0 on compare match when up-counting. Set OC0 on compare
match when downcounting mode of operation.
Speed Control Operation:
For controling the speed of the motar we are enabled the INT0 function. In this controller we have total of three intrupt ports in it. In intrupt port we are increasing the cycle of the PWM wave.
initialy we have taken 25% of duty cycles so thats why we are giving the value of OCR0=i
that is i=64
CODE:
#include <avr/io.h> //we are using I/O registers of AVR
#define F_CPU 16000000L // define the crystal frequency
#include "avr/interrupt.h" // we are using external interrupt pin
#include <util/delay.h> // delay function purpose
#define sw_dir (PIND & (1<<1)) // d1 pin is declared as push button for direction control.
#define pw (PINC & (1<<3)) // c3 is declared as push button for power ON/OFF
#define lcd_port PORTA //PORTB pins are for LCD data
#define RS_high PORTD |= (1<<5) // d5 pin is used for Register Select(RS)
#define RS_low PORTD &=~ (1<<5) // d5 pin is used for RS
#define EN_high PORTD |= (1<<6) // d6 pin is used for Enable
#define EN_low PORTD &=~ (1<<6) // d6 pin is used for En.
unsigned char i;
void lcd_cmd(char cmd) //command for lcd display
{
lcd_port = (cmd & 0xff); //4 bits for 4 bit lcd mode
RS_low;
EN_low;
_delay_ms(1); //after 1ms disable lcd
EN_high; //enable the lcd
lcd_port = ((cmd<<4) & (0xff)); //lcd port
RS_low;
EN_low;
_delay_ms(1); //after 1ms disable lcd
EN_high; //enable the lcd
}
void lcd_data (char data) //send the data to lcd
{
lcd_port = (data & 0xff); //4 bits for 4 bit lcd mode
RS_high; //access data register
EN_low;
_delay_ms(1);
EN_high;
lcd_port = ((data<<4) & (0xff)); //4 bits for 4 bit lcd mode
RS_high; //access data register
EN_low;
_delay_ms(1);
EN_high;
}
void lcd_init()
{
lcd_cmd(0x28);// used for 4 bit lcd mode
_delay_ms(5);
lcd_cmd(0x02); // return home
_delay_ms(5);
lcd_cmd(0x01); // clear screen
_delay_ms(5);
lcd_cmd(0x0C); // display on cursor off
_delay_ms(5);
lcd_cmd(0x06); // increment the display cursor
_delay_ms(5);
lcd_cmd(0x80); // force cursor to begin from 1st line
_delay_ms(5);
}
void cursorpos(char x,char y)
{
if((x<1 || x>2) || (y>16 || y<1 )) //condition will checks the 2 rows and 16 columns
{
x=1; //x= row
y=1; //y= column
}
if(x==1)
{
lcd_cmd(0x7F + y); //{ 80-1 = 7F} for starting the 1st line hex decimal value (80) {y we r using the 7F+y means we need to dtart from that column}
}
else //(x==2)
{
lcd_cmd(0xBF + y); //{0C-1 = 0B} for starting the 2nd line, 2nd row.
}
}
void lcd_out(char x, char y, char *str) //here we are checking which position we want to print
{
cursorpos(x,y);
while(*str)
{
lcd_data(*str);
str++;
}
}
//If we configure A port for display function then no need to execute the bellow function//
/*int adc_read(char channel) // we r configuring the adc value
{
unsigned int a, result;
ADMUX = channel; // here we r going to use which channel we need to select in mux here using 2 bit
ADCSRA = 0X80; //control & status register to enable the adc conversion ,enable the interrupt flag, adc interrupt. ADEN=1
ADCH = 0X00; // showing the value 0 or clearing the adc register
ADCL = 0x00; // showing the value 0
ADCSRA |= (1<<6); // to start the conversion 6 bit ADSC high
while((ADCSRA & 0x40) != 0); // when the conversion become zero means conversion of adc (0x40 means interrupted pin )
a= ADCL; //dummy data type a and ais stored the ADCL register (ADC0-ADC7)
result = ADCH; // Store the high value (ADC8-ADC9)
result = result<<8; //to get proper result or alined value we need to do left shift
result = result | a ; // we r adding the ADCL + ADCH to get the 16 bits
return result;
}*/
int main(void)
{
DDRA = 0XFF; //Declaring all 8-pins as output.
DDRB |= ((1<<0)| (1<<1)|(1<<3)); //Declaring A0 & A1 pins as output.
DDRD &=~ (1<<1); //Declaring D1 pin as input.
DDRD &=~ (1<<2); //Declaring D2 pin as input.
DDRD |= (1<<5); //Declaring D5 pin as output.
DDRD |= (1<<6); //Declaring D6 pin as output.
DDRC &=~ (0<<3); //Declaring C3 pin as input.
PORTD |= (1<<2); //enabling internal pull up resistor for D2.
PORTC |= (1<<3); //enabling internal pull up resistor for D3.
TCNT0=0X08;
i=64; //initializing i=64 because we are running the motor with 25% duty cycle.
TCCR0=0X61; //Non-Inverting mode, PWM phase correct mode,NO pre-scalar.
GICR=(1<<6); //using INT0 for interrupt
MCUCR=0X02; //make interrupt negative edge triggered
sei(); //Enable global interrupt
lcd_init(); //Initialize lcd
/* Replace with your application code */
while (1)
{
while(pw) //continue till the push button is released.
{
if(sw_dir == 0) //if the direction control push button is released.
{
PORTB = 0b00000010; // 1 0 to respective 0B 1B pins to rotate in clockwise direction.
lcd_out(1,1,"Motor ON-CLOCK W"); //Running clock wise direction
}
else
{
PORTB = 0b00000001; // 0 1 to respective 0B 1B pins to rotate in Anti-Clockwise direction.
lcd_out(1,1,"Motor ON-ANTI-CL");//Displaying the direction of the motar.
}
OCR0 = i; //i increases in ISR, the corresponding value is to be loaded into OCR0.
}
PORTB = 0x00; // 0 0 to respective 1A 2A pins to Stop rotation.
lcd_out(1,1,"Motor in OFF-pos");
}
}
ISR(INT0_vect) //interrupt service routine
{
i=i+10; // as i increases the duty cycle also increases. i increases by 20 in each push//
// and the corresponding value is to be loaded into OCR0 in while loop//
}
Program out put:
SimulIDE out put:
MOTAR In Power OFF MODE:
MOTOR ON RUNNING IN CLOCK WISE DIRECTION 25% OFF SPEED:
IN CLOCK WISE DIRECTION:
MOTOTR ON RUNNING IN ANTI COCK WISE DIRECTION WITH 25% OF SPEED:
INCREASING THE SPEED OF THE MOTOR BY PRESSING THE INTRUPT SWITCH:
IN ANTI CLOCK WISE DIRECTION: