Challenge

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

Program:

#include <avr/io.h>
#define F_CPU 16000000
#include "avr/interrupt.h"
#include <util/delay.h>

#define lcdPort PORTB
#define rsHigh PORTC|=(1 << 0)
#define rsLow PORTC&=~(1 << 0)
#define enHigh PORTC|=(1 << 1)
#define enLow PORTC&=~(1 << 1)

enum STATUS {
	ON,
	OFF
};

uint8_t speedControl = 0;
uint8_t directionControl = 0;
uint8_t motorStatus = ON;


void lcdCmd(unsigned char cmd)
{
	rsLow;
	lcdPort = cmd;
	enHigh;
	_delay_ms(1);
	enLow;
	_delay_ms(5);
}
// method to send the ascii char data to lcd
void lcdData(unsigned char data)
{
	rsHigh;
	lcdPort = data;
	enHigh;
	_delay_ms(1);
	enLow;
	_delay_ms(1);
}

// method to setting the cursor position in lcd
void cursorPosition(uint8_t row, uint8_t column)
{
	if (column > 15) {
		column = 0;
	}
	
	switch (row) {
		case 0:
		lcdCmd(0x80 + column);
		break;
		case 1:
		lcdCmd(0xC0 + column);
		break;
		default:
		lcdCmd(0x80 + column);
		break;
		
	}
}
// method to send the string data to lcd
void printString(char *str)
{
	while (*str != '\0') {
		lcdData(*str++);
	}
}

void lcdInit()
{
	lcdCmd(0x38);
	lcdCmd(0x02);
	lcdCmd(0x01);
	lcdCmd(0x0C);
	lcdCmd(0x06);
	lcdCmd(0x80);
}

// method to control the dc motor based on the global variable which was controlled by interrupts
void controlMotor()
{
	// clear timer counter registers
	TCCR0A = 0x00;
	TCCR0B = 0x00;
	uint8_t OCRValue = 0x00;
	// clear LCD screen
	lcdCmd(0x01);
	
	_delay_ms(500);
	if (motorStatus == OFF) {
		cursorPosition(0, 0);
		printString("Motor: OFF");
		return ;
	}
	
	// set the OCR value based on speedControl value (0 - 3)
	switch (speedControl)
	{
		case 0:
			OCRValue = 0x3F;
			break;
		case 1:
			OCRValue = 0x7F;
			break;
		case 2:
			OCRValue = 0xBF;
			break;
		case 3:
			OCRValue = 0xFF;
			break;
		default:
			break;
	}
	char spStr[10];
	sprintf(spStr, "Speed: %u", speedControl);
	
	// control the direction by creating waveform in OC0A & OC0B pins
	switch (directionControl)
	{
		case 0: // rotate clockwise
			TCCR0A |= (1 << WGM00) | (1 << COM0A1);
			TCCR0B |= (1 << CS00);
			TCCR0B |= (1 << CS01);
			OCR0A = OCRValue;
			cursorPosition(0, 0);
			printString("Motor: Running");
			cursorPosition(1, 0);
			printString("Dir:CL ");
			printString(spStr);
			break;
		case 1: // rotate anti clockwise
			TCCR0A |= (1 << WGM00) | (1 << COM0B1) | (1 << COM0B0);
			TCCR0B |= (1 << CS00);
			TCCR0B |= (1 << CS01);
			OCR0B = ~OCRValue;
			cursorPosition(0, 0);
			printString("Motor: Running");
			cursorPosition(1, 0);
			printString("Dir:ACL ");
			printString(spStr);
			break;
		default: // switch off motor
			cursorPosition(0, 0);
			printString("Motor: OFF");
			break;
	}
}

int main(void)
{
	// enable hardware interrupt and enable both INT0 and INT1
	sei();
	EICRA = 0x0F;
	EIMSK = (1 << INT0) | (1 << INT1);
	
	// since we need additional interrupt i am using PCINT17
	// enable pin change interrupt 2
	PCICR |= (1 << PCIE2);
	// enabled pin change interrupt on PIND1
	PCMSK2 |= (1 << PCINT17);
	
	DDRD |= (1 << PIND5) | (1 << PIND6) | (1 << PIND7);
	PIND |= (1 << PIND7);
	
	// initializing lcd
	DDRB = 0xFF;
	DDRC |= (1 << PINC0) | (1 << PINC1);
	lcdInit();
	cursorPosition(0, 0);
	printString("DC Motor Control");
	_delay_ms(1000);
	
	controlMotor();
	
	while (1) {}
}

ISR(INT0_vect) {
	speedControl = ++speedControl % 4;
	controlMotor();
}


ISR(INT1_vect) {
	directionControl = ++directionControl % 2;
	controlMotor();
}

// PCINT on PORTD PIN D1
ISR(PCINT2_vect) {
	if (PIND & (1 << PIND1)) {
		if (motorStatus == ON) {
			motorStatus = OFF;
			} else {
			motorStatus = ON;
		}
		controlMotor();
	}	
}

Circuit:

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.