Challenge

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

Solution:

#include <avr/io.h> //Including AVR Input/Output header file

#define F_CPU 16000000ul //define the CPU frequency

#include "avr/interrupt.h" //Including AVR interrupt header file

#include <util/delay.h> //Including Delay header file

#define rs_high PORTD |= (1<<5) //Define a macro for setting the RS (Register Select) line high

#define rs_low PORTD &= ~(1<<5) //Define a macro for setting the RS (Register Select) line low

#define en_high PORTD |= (1<<6) //Define a macro for setting the EN (Enable) line high

#define en_low PORTD &= ~(1<<6) //Define a macro for setting the EN (Enable) line low

#define lcd_port PORTB //Define the port for the LCD

#define sw_dir (PIND & (1<<1)) //Read the state of a switch connected to Port D, Pin 1

#define sw_dspd (PIND & (1<<2)) //Read the state of a switch connected to Port D, Pin 2

#define pw (PINC & (1<<3)) //Read the state of a switch connected to Port C, Pin 3

void lcd_command(unsigned char cmd); //Declare a function for sending a command to the LCD

void lcd_data(unsigned char data); //Declare a function for sending data to the LCD

void lcd_init(); //Declare a function to initialize the LCD

void cursorpos(char x, char y); //Declare a function to set the cursor position on the LCD

int adc_read(char channel); //Declare a function to read an analog value from a specified channel

void lcd_out(char x, char y, char *str); //Declare a function to display a string on the LCD

unsigned char i; //Declare a variable 'i' of type unsigned char

//Function to send a command to the LCD

void lcd_command(unsigned char cmd)

{

//Send the upper 4 bits of the command to the LCD

lcd_port = (cmd & 0xf0); //Extract the upper 4 bits of the command and send them to the LCD data port

rs_low; // Set the RS pin low

en_low; // Set the EN (enable) pin low to prepare for data transfer

_delay_ms(1); // Wait for a short delay (1 millisecond)

en_high; // Set the EN (enable) pin high

//Send the lower 4 bits of the command to the LCD

lcd_port = ((cmd << 4) & (0xf0)); //Shift the lower 4 bits of the command and send them to the LCD data port

rs_low; //Set the RS pin low again

en_low; //Set the EN (enable) pin low for the second data transfer

_delay_ms(1); //Another short delay

en_high; //Set the EN (enable) pin high

}

// Function to send data to the LCD

void lcd_data(unsigned char data)

{

//Send the upper 4 bits of the data to the LCD

lcd_port = (data & 0xf0); //Mask and assign the upper 4 bits of 'data' to 'lcd_port'

rs_high; //Set the register select (RS) to high

en_low; //Set the enable (EN) signal to low to prepare for data transfer

_delay_ms(1); //Delay for 1 millisecond

en_high; //Set the enable (EN) signal to high to transfer the upper 4 bits of data to the LCD

// Send the lower 4 bits of the data to the LCD

lcd_port = ((data << 4) & (0xf0)); //Shift the lower 4 bits of 'data' to the upper 4 bits position, mask them, and assign to 'lcd_port'

rs_high; //Set the register select (RS) to high

en_low; //Set the enable (EN) signal to low to prepare for data transfer

_delay_ms(1); //Delay for 1 millisecond

en_high; //Set the enable (EN) signal to high to transfer the lower 4 bits of data to the LCD

}

//Function to initialize the LCD

void lcd_init()

{

lcd_command(0x38); //Initialize LCD in 2-line, 5x8 font mode

_delay_ms(5);

lcd_command(0x02); //Return home

_delay_ms(5);

lcd_command(0x01); //Clear display

_delay_ms(5);

lcd_command(0x0C); //Turn on display, cursor off, and cursor blink off

_delay_ms(5);

lcd_command(0x06); //Entry mode set: cursor moves to the right

_delay_ms(5);

lcd_command(0x80); //Set cursor to the beginning of the first line

_delay_ms(5);

}

//Function to set the cursor position on the LCD

void cursorpos(char x, char y)

{

//Check and adjust the input coordinates if out of bounds

if ((x < 1 || x > 2) || (y < 1) || (y > 16))

{

x = 1;

y = 1;

}

//Set the cursor position on the LCD based on the input coordinates

if (x == 1)

{

lcd_command(0x80 + y);

}

else

{

lcd_command(0xC0 + y);

}

}

//Function to read an analog value from a specified channel

int adc_read(char channel)

{

unsigned int a, result; //Declare variables to store intermediate values and the result

ADMUX = channel; //Set the ADMUX register to select the desired ADC channel.

ADCSRA = 0X80;//Set the ADC Control and Status Register A (ADCSRA) with the binary value 10000000

ADCH = 0x00; //Initialize the high ADC data registers to 0

ADCL = 0x00; //Initialize the low ADC data registers to 0

ADCSRA |= (1 << 6); //Set the 6th bit of ADCSRA to 1, which starts the ADC conversion

while ((ADCSRA & 0x40) != 0);

a = ADCL; //Store the low byte of the ADC result in 'a'.

result = ADCH; //Store the high byte of the ADC result in 'result'.

result = result << 8; //Shift the high byte left by 8 bits to prepare it for bitwise OR operation

result = result | a; //Combine the high and low bytes to form the 16-bit result

return result; //Return the 16-bit ADC result.

}

// Function to display a string on the LCD at the specified coordinates

void lcd_out(char x, char y, char *str)

{

cursorpos(x, y);

while (*str)

{

lcd_data(*str);

str++;

}

}

int main(void)

{

// Setting the data direction for various ports and initializing 'i' to 64

DDRB = 0xFF; //Set all pins of Port B as outputs (data direction register)

DDRA |= ((1 << 0) | (1 << 1)); //Set pins 0 and 1 of Port A as inputs

DDRD &= ~(1 << 1); //Set pin 1 of Port D as an input by clearing its bit in the data direction register

DDRD &= ~(1 << 2); //Set pin 2 of Port D as an input by clearing its bit in the data direction register

DDRD |= (1 << 5); //Set pin 5 of Port D as an output by setting its bit in the data direction register

DDRD |= (1 << 6); //Set pin 6 of Port D as an output by setting its bit in the data direction register

DDRC &= ~(1 << 3); //Set pin 3 of Port C as an input by clearing its bit in the data direction register

PORTD |= (1 << 2); //Set pin 2 of Port D as high (turn on) by setting its bit in the port register

PORTC |= (1 << 3); // Set pin 3 of Port C as high (turn on) by setting its bit in the port register

i = 64; //Assign the value 64 to the variable 'i'.

//Configuring Timer 0 and External Interrupt 0

TCCR0 = 0X61; //Configure Timer 0 with specific settings (hexadecimal value).

GICR = (1 << INT0); //Enable External Interrupt 0 by setting its bit in the GICR register.

MCUCR = 0X02; //Configure the mode of External Interrupt 0 (hexadecimal value).

sei(); //Enable global interrupts

lcd_init(); //Initialize the LCD.

while (1)

{

while (pw == 0)

{

if (sw_dir == 0)

{

PORTA = 0b00000001;

lcd_out(1, 1, "Motor ON-CLW");

}

else

{

PORTA = 0b00000010;

lcd_out(1, 1, "Motor ON-ACL");

}

OCR0 = i;

}

PORTA = 0X00;

lcd_out(1, 1, "Motor is_OFF");

}

}

// Interrupt Service Routine for External Interrupt 0

ISR(INT0_vect)

{

i = i + 20; // Increment 'i' by 20 when INT0 is triggered

}

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.