Project 1 - Controlling a DC motor using PWM and monitoring its Running status
#ifndef F_CPU
#define F_CPU 8000000UL // 8MHz clock speed
#endif
#include <avr/io.h>
#include <util/delay.h>
// Define motor control pins
#define MOTOR_EN PB3 // Enable pin for PWM (OC0)
#define MOTOR_IN1 PD2 // Control pin 1
#define MOTOR_IN2 PD3 // Control pin 2
// Define LCD control pins
#define RS PC0
#define RW PC1
#define E PC2
// Define LCD data pins
#define D4 PC4
#define D5 PC5
#define D6 PC6
#define D7 PC7
void LCD_Command(unsigned char cmnd) {
PORTC = (PORTC & 0x0F) | (cmnd & 0xF0); // Sending upper nibble
PORTC &= ~(1 << RS); // RS = 0 for command
PORTC &= ~(1 << RW); // RW = 0 for write
PORTC |= (1 << E); // Enable pulse
_delay_us(1);
PORTC &= ~(1 << E);
_delay_us(200);
PORTC = (PORTC & 0x0F) | (cmnd << 4); // Sending lower nibble
PORTC |= (1 << E); // Enable pulse
_delay_us(1);
PORTC &= ~(1 << E);
_delay_ms(2);
}
void LCD_Char(unsigned char data) {
PORTC = (PORTC & 0x0F) | (data & 0xF0); // Sending upper nibble
PORTC |= (1 << RS); // RS = 1 for data
PORTC &= ~(1 << RW); // RW = 0 for write
PORTC |= (1 << E); // Enable pulse
_delay_us(1);
PORTC &= ~(1 << E);
_delay_us(200);
PORTC = (PORTC & 0x0F) | (data << 4); // Sending lower nibble
PORTC |= (1 << E); // Enable pulse
_delay_us(1);
PORTC &= ~(1 << E);
_delay_ms(2);
}
void LCD_Init(void) {
DDRC = 0xFF; // Make all pins of PORTC output
_delay_ms(20); // LCD power on delay
// Initialization sequence
LCD_Command(0x02); // 4-bit mode
LCD_Command(0x28); // 2 lines, 5x7 matrix
LCD_Command(0x0C); // Display on, cursor off
LCD_Command(0x06); // Increment cursor
LCD_Command(0x01); // Clear display
_delay_ms(2);
}
void LCD_String(const char *str) {
while (*str) {
LCD_Char(*str++);
}
}
void LCD_Clear(void) {
LCD_Command(0x01); // Clear display
_delay_ms(2);
LCD_Command(0x80); // Cursor to home position
}
void PWM_init()
{
/* Set fast PWM mode with non-inverted output */
TCCR0 = (1<<WGM00) | (1<<WGM01) | (1<<COM01) | (1<<CS00);
DDRB |= (1<<MOTOR_EN); /* Set OC0 pin as output */
}
void motor_init()
{
/* Set MOTOR_IN1 and MOTOR_IN2 as outputs */
DDRD |= (1<<MOTOR_IN1) | (1<<MOTOR_IN2);
/* Initialize motor to stop state */
PORTD &= ~((1<<MOTOR_IN1) | (1<<MOTOR_IN2));
}
void motor_control(uint8_t duty_cycle, uint8_t direction)
{
/* Set motor direction */
if (direction == 1) {
PORTD |= (1<<MOTOR_IN1);
PORTD &= ~(1<<MOTOR_IN2);
} else if (direction == 0) {
PORTD &= ~(1<<MOTOR_IN1);
PORTD |= (1<<MOTOR_IN2);
} else {
PORTD &= ~((1<<MOTOR_IN1) | (1<<MOTOR_IN2)); /* Stop */
}
/* Set motor speed (duty cycle) */
OCR0 = duty_cycle;
}
int main ()
{
unsigned char duty;
PWM_init();
motor_init();
LCD_Init();
while (1)
{
/* Increase speed from 0% to 100% */
LCD_String("Forward direction");
for (duty = 0; duty < 255; duty++)
{
motor_control(duty, 1); /* Forward direction */
_delay_ms(8); /* Adjust for smoother transition */
}
/* Run at full speed for a while */
_delay_ms(2000);
LCD_Clear();
/* Decrease speed from 100% to 0% */
LCD_String("Forward direction");
for (duty = 255; duty > 0; duty--)
{
motor_control(duty, 1); /* Forward direction */
_delay_ms(8); /* Adjust for smoother transition */
}
/* Pause for a while before reversing */
_delay_ms(2000);
LCD_Clear();
/* Increase speed from 0% to 100% in reverse */
LCD_String("Reverse direction");
for (duty = 0; duty < 255; duty++)
{
motor_control(duty, 0); /* Reverse direction */
_delay_ms(8); /* Adjust for smoother transition */
}
/* Run at full speed in reverse for a while */
_delay_ms(2000);
LCD_Clear();
/* Decrease speed from 100% to 0% in reverse */
LCD_String("Reverse direction");
for (duty = 255; duty > 0; duty--)
{
motor_control(duty, 0); /* Reverse direction */
_delay_ms(8); /* Adjust for smoother transition */
}
/* Pause before repeating the cycle */
_delay_ms(2000);
LCD_Clear();
}
return 0;
}