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:
