Project 1 - Controlling a DC motor using PWM and monitoring its Running status
Aim
The aim of this project is to implement a system on the simulator to control a DC motor using PWM with the L293 motor driver. The project also involves monitoring the running status of the DC motor and displaying it on an LCD screen.
Components Required
- Atmega 32
- Motor Driver - L293
- DC Motor
- Pushbutton(2)
- Switch- ON & OFF
- LCD Display - 16x2
- Resistor - 2.2k ohm
- Resistor - 10kohm
- Fixed power supply - 5V
Code
#include
#define F_CPU 16000000L
#include "avr/interrupt.h"
#include
#define sw_dir (PIND & (1<<1>
#define pw (PINC & (1<<3>
//LCD connections & commands
#define lcd_port PORTB
#define RS_high PORTD |= (1<<5>
#define RS_low PORTD &= ~(1<<5>
#define EN_high PORTD |= (1<<6>
#define EN_low PORTD &= ~(1<<6>
//LCD specific commands
#define LCD_LINE_1 0x80
#define LCD_LINE_2 0xC0
unsigned char i; //Variable to store duty cycle
void lcd_cmd(char cmd) //function to send a command to the LCD
{
lcd_port=(cmd & 0xF0); //send higher 4 bits of the command
RS_low; //set RS pin as low(command mode)
EN_low; //set EN pin as low
_delay_ms(1); //delay to ensure command is processed
EN_high; //set EN pin as high to process command
lcd_port=((cmd<<4>
RS_low; //set RS pin as low(command mode)
EN_low; //set EN pin as low
_delay_ms(1); //delay to ensure command is processed
EN_high; //set EN pin as high to process command
}
void lcd_data(char data) //function to send data to the LCD
{
lcd_port=(data & 0xF0); //send higher 4 bits of the data
RS_high; //set RS pin as high(data mode)
EN_low; //set EN pin as low
_delay_ms(1); //delay to ensure data is processed
EN_high; //set EN pin as high to process data
lcd_port=((data <<4>
RS_high; //set RS pin as high(data mode)
EN_low; //set EN pin as low
_delay_ms(1); //delay to ensure data is processed
EN_high; //set EN pin as high to process data
}
void lcd_init() //function to initialize the LCD
{
lcd_cmd(0x28); //initialize LCD in 4 bit mode with 2lines and 5x8 font size
_delay_ms(5);
lcd_cmd(0x02); //return cursor to home position
_delay_ms(5);
lcd_cmd(0x01); //clear display
_delay_ms(5);
lcd_cmd(0x0C); //display ON,cursor OFF
_delay_ms(5);
}
void lcd_string(const char* str) //function to display a string on the LCD
{
while (*str)
{
lcd_data(*str++); //send each character of string to LCD
}
}
int adc_read(char channel) //function to configure the adc value
{
unsigned int a,result;
ADMUX=channel; //select ADC channel
ADCSRA=0x80; //enable ADC,start conversion,enable ADC interrupt
ADCH=0x00; //clear ADC high value
ADCL=0x00; //clear ADC low value
ADCSRA |=(1<<6>
while ((ADCSRA & 0x40) !=0) //wait for conversion to complete
a=ADCL; //read ADC low value
result=ADCH; //read ADC high value
result=result<<8>
result=result | a; //combine high and low values to get the result
return result;
}
int main(void) //main function
{
//set data direction for LCD and control pins
DDRB=0xFF; //all 8 pins of PORTB are set as output
DDRA |=((1<<0>
DDRD &= ~(1<<1>
DDRD &= ~(1<<2>
DDRD |= (1<<5>
DDRD |= (1<<6>
DDRC &= ~(1<<3>
PORTD |=(1<<2>
PORTC |=(1<<3>
i=64; //initialize i for 25% duty cycle
TCCR0 =0x61; //non inverting mode,PWM phase correct mode
GICR =(1<
MCUCR =0x02; //set interrupt INT0 to be triggered on falling edge
sei(); //enable global interrupt
lcd_init();
while (1)
{
while (pw == 0)
{
//continue till push button is released
if (sw_dir==0)
{
//set appropriate motor direction pins
PORTA=0b0000001;
lcd_cmd(LCD_LINE_1);
lcd_string("->Motor ON-CL "); //display on LCD
}
else
{
//set appropriate motor direction pins
PORTA=0b0000010;
lcd_cmd(LCD_LINE_1);
lcd_string("->Motor ON-ACL "); //display on LCD
}
OCR0=i;
}
PORTA=0x00; //turn off motor
lcd_cmd(LCD_LINE_1);
lcd_string("->Motor TURN OFF "); //display on LCD
}
}
ISR(INT0_vect)
{
i=i+22; //increase duty cycle when external interrupt occurs
}
Code Explanation
- The code starts by including necessary libraries and defining constants for the pins and commands used in the program.
- It then initializes the ADC and sets up the LCD display.
- The main function configures the ports and pins for motor control, external interrupt, and ADC.
- The main loop continuously monitors the push button state and the direction switch.
- When the push button is pressed, the motor starts running in the specified direction, and the duty cycle is adjusted based on the external interrupt.
- When the push button is released, the motor stops, and the LCD displays the status accordingly.
Explanation for Registers Used in Code
- DDRB, DDRA, DDRD, DDRC: Data Direction Registers for configuring the direction of PORTB, PORTA, PORTD, and PORTC pins.
- PORTD: Used for enabling internal pull-up resistors for D2 and D3 pins (push button and direction switch inputs).
- TCCR0: Timer/Counter Control Register for Timer0 configuration (PWM settings).
- GICR: General Interrupt Control Register for enabling external interrupts.
- MCUCR: MCU Control Register for configuring external interrupt behavior (trigger on falling edge).
- ADCSRA, ADMUX: ADC Control and Status Registers for configuring and starting ADC conversion.
OUTPUT
- When the push button is pressed and the direction switch is in one position, the motor starts running in the specified direction with a duty cycle proportional to the external interrupt count. The LCD displays the running status.
- CLOCKWISE:
- CLOCKWISE:
- When the push button is pressed and the direction switch is in the other position, the motor starts running in the opposite direction with a duty cycle proportional to the external interrupt count. The LCD displays the running status.
- ANTICLOCKWISE:
- ANTICLOCKWISE:
- When the push button is released, the motor stops, and the LCD displays the "Motor TURN OFF" message.
</> </> <><>></> <>>