Project 1 - Controlling a DC motor using PWM and monitoring its Running status
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#define LCD_DATA_DIR DDRC
#define LCD_DATA_PORT PORTC
#define LCD_CTRL_DIR DDRD
#define LCD_CTRL_PORT PORTD
#define RS PD0
#define RW PD1
#define EN PD2
#define MOTOR_PORT PORTB
#define MOTOR_DIR DDRB
#define MOTOR_PIN1 PB0
#define MOTOR_PIN2 PB1
#define PWM_PIN PB3
void lcd_command(unsigned char cmnd);
void lcd_data(unsigned char data);
void lcd_init(void);
void lcd_clear(void);
void lcd_print(char *str);
void lcd_print_xy(char row, char pos, char *str);
void pwm_init(void);
volatile int direction = 1;
void lcd_command(unsigned char cmnd) {
LCD_DATA_PORT = cmnd;
LCD_CTRL_PORT &= ~(1 << RS);
LCD_CTRL_PORT &= ~(1 << RW);
LCD_CTRL_PORT |= (1 << EN);
_delay_us(1);
LCD_CTRL_PORT &= ~(1 << EN);
_delay_ms(2);
}
void lcd_data(unsigned char data) {
LCD_DATA_PORT = data;
LCD_CTRL_PORT |= (1 << RS);
LCD_CTRL_PORT &= ~(1 << RW);
LCD_CTRL_PORT |= (1 << EN);
_delay_us(1);
LCD_CTRL_PORT &= ~(1 << EN);
_delay_ms(2);
}
void lcd_init(void) {
LCD_CTRL_DIR |= (1 << RS) | (1 << RW) | (1 << EN);
LCD_DATA_DIR = 0xFF;
_delay_ms(20);
lcd_command(0x38); // 8-bit mode, 2 lines, 5x7 font
lcd_command(0x0C); // Display on, cursor off
lcd_command(0x06); // Auto increment cursor
lcd_command(0x01); // Clear display
_delay_ms(2);
}
void lcd_clear(void) {
lcd_command(0x01);
_delay_ms(2);
}
void lcd_print(char *str) {
int i = 0;
while (str[i] != 0) {
lcd_data(str[i]);
i++;
}
}
void lcd_print_xy(char row, char pos, char *str) {
if (row == 1) {
lcd_command((pos & 0x0F) | 0x80);
} else if (row == 2) {
lcd_command((pos & 0x0F) | 0xC0);
}
lcd_print(str);
}
void pwm_init(void) {
// Set PWM pin as output
DDRB |= (1 << PWM_PIN);
// Set non-inverting mode and fast PWM mode with TOP at ICR1
TCCR1A |= (1 << WGM11) | (1 << COM1A1);
TCCR1B |= (1 << WGM13) | (1 << WGM12) | (1 << CS11); // Prescaler = 8
ICR1 = 39999; // Frequency = 50Hz (Period = 20ms)
}
void motor_forward(void) {
MOTOR_PORT |= (1 << MOTOR_PIN1);
MOTOR_PORT &= ~(1 << MOTOR_PIN2);
}
void motor_backward(void) {
MOTOR_PORT &= ~(1 << MOTOR_PIN1);
MOTOR_PORT |= (1 << MOTOR_PIN2);
}
void motor_stop(void) {
MOTOR_PORT &= ~(1 << MOTOR_PIN1);
MOTOR_PORT &= ~(1 << MOTOR_PIN2);
}
void set_motor_speed(uint8_t speed) {
OCR1A = (speed * 39999) / 255; // Scale speed to 8-bit value
}
ISR(INT0_vect) {
if (direction == 1) {
motor_forward();
lcd_clear();
lcd_print_xy(1, 0, "Motor ON-FWD");
} else {
motor_backward();
lcd_clear();
lcd_print_xy(1, 0, "Motor ON-BWD");
}
_delay_ms(2000);
motor_stop();
lcd_clear();
lcd_print_xy(1, 0, "Motor OFF");
}
ISR(INT1_vect) {
direction = !direction;
if (direction == 1) {
lcd_clear();
lcd_print_xy(1, 0, "Dir: Forward");
} else {
lcd_clear();
lcd_print_xy(1, 0, "Dir: Backward");
}
}
int main(void) {
MOTOR_DIR |= (1 << MOTOR_PIN1) | (1 << MOTOR_PIN2);
pwm_init();
lcd_init();
lcd_print_xy(1, 0, "Motor OFF");
// Enable internal pull-up resistors
PORTD |= (1 << PD2) | (1 << PD3);
// Enable external interrupts
GICR |= (1 << INT0) | (1 << INT1);
MCUCR |= (1 << ISC01) | (1 << ISC11); // Falling edge triggers INT0 and INT1
sei(); // Enable global interrupts
while (1) {
set_motor_speed(128); // Set motor speed to 50%
_delay_ms(100);
}
}