Challenge

Project 1 - Controlling a DC motor using PWM and monitoring its Running status

QUESTION:

Project 1 - Controlling a DC motor using PWM and monitoring its Running status

SOLUTION:

---> CIRCUIT:

---> CODE:

/*
* Project1.c
*
* Created: 27-12-2022 16:52:25
* Author : ZEBA KHANUN
*/


#include <avr/io.h> //includes appropriate I/O definitions for the device
#define F_CPU 16000000L //tells compiler the CPU frequency to use for various delays
#include <util/delay.h> //Function where actual time values rather than a number of cycles to wait for
#include <avr/interrupt.h> //provides a set of default interrupt routines

#define LCD_PORT PORTB //defines which PORT of ATmega will be used to interface LCD

//RS bit tells whether we are going to send an Instruction or a piece of data
#define RS_HIGH() PORTD |= (1<<5) //for data
#define RS_LOW() PORTD &= ~(1<<5) //for instruction

//EN bit enables writing to the registers if HIGH
#define EN_HIGH() PORTD |= (1<<6)
#define EN_LOW() PORTD &= ~(1<<6)

//Switches to provide inputs to the operation of motor
#define SW_DIR (PIND & (1<<1)) //to control the direction of the motor
#define SW_SPEED (PIND & (1<<2)) //to control the speed of the motor
#define SW_POWER (PINC & (1<<3))  //to control the power of the motor

unsigned int i = 0; //global variable declaration

void LCD_COMMAND (unsigned char cmd) //commands to run when the LCD RS bit is LOW
{
	LCD_PORT = (cmd & (0xF0));
	RS_LOW();
	EN_LOW();
	_delay_ms(1);
	EN_HIGH();
	LCD_PORT = ((cmd<<4) & (0xF0));
	RS_LOW();
	EN_LOW();
	_delay_ms(1);
	EN_HIGH();
} 

void LCD_DATA (unsigned char data) //Commands to process the data of LCD RS bit is HIGH
{
	LCD_PORT = (data & (0xF0));
	RS_HIGH();
	EN_LOW();
	_delay_ms(1);
	EN_HIGH();
	LCD_PORT = ((data<<4) & (0xF0));
	RS_HIGH();
	EN_LOW();
	_delay_ms(1);
	EN_HIGH();
}

void LCD_INIT() //Commands to initialize the LCD display
{
	LCD_COMMAND(0x28);
	_delay_ms(5);
	LCD_COMMAND(0x02);
	_delay_ms(5);
	LCD_COMMAND(0x01);
	_delay_ms(5);
	LCD_COMMAND(0x0C);
	_delay_ms(5);
	LCD_COMMAND(0x06);
	_delay_ms(5);
	LCD_COMMAND(0x80);
	_delay_ms(5);
}

void CURSOR_POS(char x, char y) //function to set LCD Display cursor 
{
	if((x<1)|(x>2)||(y<1)|(y>16))
	{
		x = 1;
		y = 1;
	}
	
	if(x == 1)
	{
		LCD_COMMAND(0x7F+y); //to start from 1st line
	}
	else
	{
		LCD_COMMAND(0xBF+y); //to start from 2nd line
	}
}

void LCD_OUT(char x, char y, char* str) //to display the passed string on lcd
{
	CURSOR_POS(x, y);
	while(*str)
	{
		LCD_DATA(*str);
		str++;
	}
}

int ADC_READ (char channel) //ADC data processing we are configuring the ADC value
{
	unsigned int a, result;
	ADMUX = channel; //ADC Multiplexer selection bit helps to enable particular ADC channel
	ADCSRA = 0x80; //ADC Status and control register - ADEN is HIGH
	ADCH = 0x00; //clearing the ADCH register to store the higher byte of converted data 
	ADCL = 0x00; //clearing the ADCL register to store the lower byte of converted data 
	ADCSRA |= (1<<6); //ADSC bit is high to start conversion
	while((ADCSRA & (0x40)) != 0); //performing bitwise AND operation between ADCSRA and ADIF (INTERRUPT FLAG bit 4th bit in ADCSRA)
	a = ADCL; //storing lower byte of converted data in local variable a
	result = ADCH; //storing higher byte of converted data in local variable result
	result = result << 8; //as the ADLAR is 0 data is right justified so performing left shift
	result = result | a; //bitwise OR operation to store higher and lower byte of converted data in variable result
	return result;	//returning result value
}

int main(void)
{
	DDRB = 0xFF; //setting PORTB as output port
	DDRA |= ((1<<0)|(1<<1)); //Setting PORTA pin 0, 1 as output
	DDRD &= ~(1<<1); //setting PORTD pin1 as input
	DDRD &= ~(1<<2); //setting PORTD pin2 as input
	DDRB |= (1<<5);  //setting PORTB pin5 as output
	DDRB |= (1<<6);  //setting PORTB pin6 as output
	DDRC &= ~(1<<3); //setting PORTC pin3 as input
	PORTD |= (1<<2); //enabling internal pull-up resistor
	PORTC |= (1<<3); //enabling internal pull-up resistor
	i = 64; //storing value of OCR0 in global variable i
	TCCR0 = 0x61; //timer control register 0 configured for PWM phase correct mode, no prescaling
	GICR = (1<<INT0); //general interrupt control register 
	MCUCR = 0x02; //MCU control register - ISC01 is high(falling edge of INT0 generates interrupt request)
	sei(); //enabling interrupt
	LCD_INIT(); //initializing LCD
	while(1)
	{
		while(SW_POWER == 0) 
		{
			if(SW_DIR == 0)
			{
				PORTA = 0b00000001;
				LCD_OUT(1,1,"MOTOR ON-CLK");
			}
			else
			{
				PORTA =0b00000010;
				LCD_OUT(1,1,"MOTOR ON-ACL");
			}
			OCR0 = i;
		}
		PORTA = 0x00;
		LCD_OUT(1,1,"MOTOR IS OFF");
	} 
}

ISR (INT0_vect)
{
	i = i+20; //incrementing OCR0 value by a step size of 20 every time interrupt is called
}

---> EXPLANATION:

Above mentioned are special function registers used for timer0, ADC, and interrupts. We have configured the bits of these special function registers for the functionality.

GICR - INT0 bit (to enable INT0)

MCUCR - ISC01 (falling edge of INT0 will generate interrupt request)

ADCSRA - ADEN, ADIF (to enable ADC conversion, enable ADC interrupt flag)

TCCR0 - WGM00, COM01, CS00 (No prescaling, PWM phase correct mode)

---> SCREENSHOTS:

CLOCKWISE DIRECTION:

ANTICLOCKWISE DIRECTION:

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.