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_port PORTB
#define lcd_ctrl_port PORTD
#define rs_high PORTD |= (1<<5)
#define rs_low PORTD &= ~(1<<5)
#define en_high PORTD |= (1<<6)
#define en_low PORTD &= ~(1<<6)
double dutyCycle = 0;
void lcd_cmd(unsigned char cmd)
{
lcd_data_port = (lcd_data_port & 0x0F) | (cmd & 0xF0); // Send high nibble
rs_low;
en_high;
_delay_ms(1);
en_low;
_delay_ms(2);
lcd_data_port = (lcd_data_port & 0x0F) | ((cmd << 4) & 0xF0); // Send low nibble
en_high;
_delay_ms(1);
en_low;
_delay_ms(1);
}
void lcd_data(unsigned char data)
{
lcd_data_port = (lcd_data_port & 0x0F) | (data & 0xF0); // Send high nibble
rs_high;
en_high;
_delay_ms(1);
en_low;
_delay_ms(1);
lcd_data_port = (lcd_data_port & 0x0F) | ((data << 4) & 0xF0); // Send low nibble
en_high;
_delay_ms(1);
en_low;
_delay_ms(1);
}
void lcd_init()
{
lcd_data_port &= 0x0F; // Set lower 4 bits of data port as output
lcd_ctrl_port |= (1 << PD5) | (1 << PD6); // Set RS and EN pins as output
_delay_ms(20); // Wait for LCD to power up
// Initialization sequence
lcd_cmd(0x32); // Initialize 4-bit mode
lcd_cmd(0x28); // 4-bit mode, 2 lines, 5x7 font
lcd_cmd(0x0E); // Display on, cursor off, blink off
lcd_cmd(0x06); // Increment cursor
lcd_cmd(0x01); // Clear display
_delay_ms(2); // Wait for command to complete
}
void cursorpos(char row, char col)
{
unsigned char position;
if (row == 1)
{
position = 0x80 + col - 1;
}
else if (row == 2)
{
position = 0xC0 + col - 1;
}
lcd_cmd(position);
}
void lcd_print(char row, char coloumn, unsigned int value, int digits)
{
unsigned int temp;
unsigned int unit;
unsigned int tens;
unsigned int hundred;
unsigned int thousand;
unsigned int million;
unsigned char flag = 0;
if (row == 0 || coloumn == 0)
cursorpos(1, 1);
else
cursorpos(row, coloumn);
if (digits == 5 || flag == 1)
{
million = value / 10000 + 48;
lcd_data(million);
flag = 1;
}
if (digits == 4 || flag == 1)
{
temp = value / 1000;
thousand = temp % 10 + 48;
lcd_data(thousand);
flag = 1;
}
if (digits == 3 || flag == 1)
{
temp = value / 100;
hundred = temp % 10 + 48;
lcd_data(hundred);
flag = 1;
}
if (digits == 2 || flag == 1)
{
temp = value / 10;
tens = temp % 10 + 48;
lcd_data(tens);
flag = 1;
}
if (digits == 1 || flag == 1)
{
unit = value % 10 + 48;
lcd_data(unit);
}
if (digits > 5)
lcd_data('e');
}
void lcd_out(char x, char y, char *str)
{
cursorpos(x, y);
while (*str)
{
lcd_data(*str);
str++;
}
}
int main(void)
{
lcd_init(); // Initialize LCD
DDRD &= ~(1 << PD2); // Set PD2 as input (External Interrupt INT0)
PORTD |= (1 << PD2); // Enable internal pull-up resistor for PD2
PORTC = (1 << PC3); // Set PC3 as input (Motor Enable Switch)
DDRB = (1 << PB3); // Set PB3 as output (PWM Output for Motor)
DDRA = (1 << PA1) | (1 << PA2); // Set PA1 and PA2 as output (Motor Direction Control)
TCCR0 = (1 << WGM00) | (1 << COM01) | (1 << CS00); // Fast PWM, Non-inverted mode, No prescaler
OCR0 = dutyCycle; // Initialize PWM duty cycle
GICR = (1 << INT0); // Enable external interrupt INT0
MCUCR = 0x02; // Falling edge detection for INT0
sei(); // Enable global interrupts
while (1)
{
if ((PINC & (1 << PC3)) == (0 << PC3))
{
lcd_out(1, 1, "Motor is : ON");
if ((PIND & (1 << PD1)) == (1 << PD1))
{
PORTA |= (1 << PA1); // Rotate motor clockwise
PORTA &= ~(1 << PA2);
lcd_out(2, 1, "Dir:CW Speed:");
lcd_print(2, 14, dutyCycle, 3); // Print duty cycle on LCD
}
if ((PIND & (1 << PD1)) == (0 << PD1))
{
PORTA &= ~(1 << PA1); // Rotate motor counter-clockwise
PORTA |= (1 << PA2);
lcd_out(2, 1, "Dir:CCW Speed:");
lcd_print(2, 14, dutyCycle, 3); // Print duty cycle on LCD
}
OCR0 = dutyCycle; // Update PWM duty cycle
}
if ((PINC & (1 << PC3)) == (1 << PC3))
{
lcd_out(1, 1, "Motor is :OFF");
PORTA &= ~(0x06); // Turn off motor
}
}
return 0;
}
ISR(INT0_vect)
{
_delay_ms(100); // Debounce delay
dutyCycle += 10; // Increase duty cycle by 10%
if (dutyCycle > 256)
{
dutyCycle = 0; // Reset duty cycle if it exceeds maximum value
}
}