Challenge

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);

}

}

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.