Uploaded by Haleema Arooj

FA18-BEE-161 Lab1-12

advertisement
MICROPROCESSOR SYSTEMS & INTERFACING
EEE-342
Lab Report No. 1
Name
Waqas Ahmed
Registration Number
FA18-BEE-161
Class
BEE (4C)
Instructor’s Name
Asma Ramay
Lab # 01 Introduction to Development Tools and Lab Software
OBJECTIVES
•
•
Learn to use software development tools such as Arduino, Integrated Development
Environment (IDE) (Atmel Studio, AVR Studio), Compiler (WinAVR), and Simulator
(Proteus) for the AVR ATmega 328P microcontroller.
Learn to program Arduino and ATmega328P.
SOFTWARES USED
• Arduino
• Atmel Studio (Version 7)
• AVR Studio (Version 4)
• Proteus ISIS
• WinAVR (Version 2010)
PRE-LAB
Get the following software installers from MP/VLSI lab and install them in your laptops. The
same software will be available in the Lab PCs.
Arduino:
Arduino is an open-source platform used for building electronics projects. It consists of both a
physical programmable circuit board and an IDE (Integrated Development Environment) that
runs on your computer. Most Arduino boards consist of an Atmel 8-bit AVR microcontroller
with varying amounts of flash memory, pins and features. Arduino is programmed using the
Arduino Software (IDE) which is a cross-platform application for windows, macOS and Linux. It
is connected to a PC via USB cable to upload computer code to the physical board. This also
provides power to the board, as indicated by a LED.
AVR Studio:
AVR Studio is an Integrated Development Environment (IDE) used to develop projects (software
part) for AVR microcontrollers. This IDE consists of a project management tool, source filer
editor, assembler and front-end for C/C++ programming, a debugger and a hardware (MCU
registers) Simulator. With AVR Studio, you can develop code in C as well as in Assembly
Language. Both approaches are different from each other. Each has its own merits as you will
learn during the coursework.
Atmel Studio:
Atmel Studio 7 is the integrated development platform (IDP) for developing and debugging
Atmel Atmel AVR microcontroller (MCU) applications. Atmel Studio 7 supports all AVR MCUs. It
gives you a seamless and easy-to-use environment to write, build and debug your applications
written in C/C++ or assembly code. It also connects seamlessly to Atmel debuggers and
development kits.
WinAVR
WinAVR is a suite of executable, open source software development tools for the Atmel AVR
series of microprocessors hosted on the Windows platform. It includes the GNU GCC compiler
for C and C++. You will install this software (release 2010) on your PC/Laptop and it will be used
to compile your C/C++ code for the AVR microcontroller. IDEs such as AVR Studio will
automatically detect and use WinAVR installation and you will not need to run this software
yourself.
Proteus
The Proteus Design Suite is a complete software solution for circuit simulation and PCB
design.Proteus can simulate electric/electronic and microcontroller based circuits. It supports
number of microcontrollers available in the market.
ATmega 328p
The Atmel AVR ATmega328P is a low-power 8-bit microcontroller architecture.It has 131
Powerful Instructions. Most of them require single clock cycle for execution. It has 32K bytes of
In-System Programmable Flash Program memory with Read-While-Write capabilities, 1K bytes
EEPROM, 2K bytes SRAM, 23 general purpose I/O pins and 32 general purpose working
registers.
ATmega 328P Peripheral Features
• 3 flexible Timer/Counters with compare modes
• Six PWM Channels
• Internal and External Interrupts
• A serial programmable USART
• Two Master/Slave SPI Serial Interface
• 8 channel 10-bit ADC.
ATmega328P Pin configuration
The 23 digital I/O pins are grouped into 3 ports named as Port B, C and D. Port B and D have 8
pins each whereas Port C has 7 pins. Pin 4 and 6 are required to connect with +ve (VCC) and pin
3, 5 and 21 need to connect with ground (GND). Pin 18 is the supply voltage pin for the A/D
Converter. Pin 20 is the analog reference pin for the A/D Converter.
Each of the AVR Digital I/O port i.e Port B, Port C and Port D are associated with three I/O
registers. These resigters are:
• DDRx (Data Direction Register) - Sets the direction of each pin as input or output.
• PORTx - Used to output/write values on a Port.
• PINx - Used to input/ read values from a Port.
Where x is the port B, C or D. All these registers are 8-bit registers. Figure 1.1 shows the three
registers associated with Port B.
Pin configuration of ATmega 328P can be seen in Figure 1.1.
IN LAB-TASKS:
Task 1: Arduino Learning Tutorial: Some built-in examples are included in Arduino
software. Click on the toolbar menu: File > Examples > Basics > Blink. This will turn an
LED on Arduino board on and off with some delay. Compile the sketch. After successful
compilation, the code can be uploaded to the Arduino board.
Task 2: AVR Studio Learning Tutorial: Launch AVR Studio and Select Project Wizard form menu
bar and Select New Project and follow the instructions given in lab manual. Then write down
the code below in source window.
In this we learned about AVR Studio step by step, steps given in Lab Manual. And we run a
given code in AVR studio. After running of code we tested the code in Protues by running the
Atmega328p.
a. The following code is written to generate fibonacci series output at PortB which is given as
(0, 1, 2, 3, 5, 8, 13, 21, 34, 55).
b. Build the following code in AVR Studio or Atmel Studio. Read the error messages, identify
and correct any syntax errors and rebuild the solution.
c. Use Debugging mode of AVR Studio or Atmel Studio to debug and correct the code to get
the desired output. In debug mode, open watch window to check the value of the variables.
Incorrect Code
//This code will generate Fibonacci series.
#include /*This header file includes the
appropriate I/O definitions for the device */
#define F_CPU 16000000UL //XTAL Frequency
=16MHz
#include /*This header file is required for
generating delays*/
int main(void)
{ DDRB = 0b11111111 //Configure Port B as
Output
int t1 = 1, t2 = 1, nextTerm = 0, i = 1;
while (i < 10)
{ PORTB = nextTerm; //Generate fibanocci
series
nextTerm = t1 - t2;
t1 = t2;
t2 = nextTerm;
i = i + 1; }
while (1)
{
}
return 0; }
Corrected Code
//This code will generate fibanocci series.
#include <avr\io.h> /*This header file includes
the apropriate
I/O definitions for the device */
#define F_CPU 16000000UL //XTAL Frequency
=16MHz
#include <util/delay.h> /*This header file is
required for
generating delays*/
int main(void)
{
DDRB = 0b11111111; //Configure Port B as
Output
int t1 = 0, t2 = 1, nextTerm = 0, i = 1;
while (i < 10)
{
PORTB = nextTerm;
//Generate fibanocci series
nextTerm = t1 + t2;
t1 = t2;
t2 = nextTerm;
i = i + 1;
}
while (1)
{
}
return 0;
}
CRITICAL ANALYSIS / CONCLUSION
In this lab we had to get a concise review about AVR studio and Proteus. It is plainly evidential
that AVR studio is one of those stages used to program microcontrollers. We examined about
the various kinds of Arduino and its working. Despite the fact that this was an overall outline
which disclosed how to make venture, running the program and to transfer it on proteus we
might have done a touch more in this lab, for example, helping us understanding the
restrictions of this product and to troubleshoot an issue when the product isn't working or
when the yield records are not being created.
EEE-342 MICROPROCESSOR SYSTEMS & INTERFACING
Lab Report # 02
Name
Registration Number
Instructor’s Name
Waqas Ahmed
FA18-BEE-161
Ma’am Asma Ramay
Lab # 02 Introduction to AVR Microcontroller Hardware Circuitry and
Digital I/O Ports
OBJECTIVES:
•
•
•
Understand the minimal circuit required to start using a microcontroller
Learn to program (download code to program memory of) a microcontroller using Arduino
board.
To understand and use digital I/O ports of AVR microcontroller
REQUIRED TOOLS:
SOFTWARE TOOLS:
• Atmel Studio (Version 7) or AVR Studio (Version 4)
• Proteus ISIS
• Arduino IDE
• AVRDUDESS
PRE-LAB
2.1 ARDUINO NANO
Arduino is open-source electronics prototyping platform based on flexible, easy-to-use
hardware and software. Arduino Nano is a surface mount breadboard embedded version with
integrated USB. It is a smallest, complete, and breadboard friendly Arduino Nano is
programmed using the Arduino Software (IDE).
ARDUINO NANO SPECIFICATIONS:
Microcontroller
Atmel ATmega328
Operating Voltage
Input Voltage
5V
7-12 V
Digital I/O Pins
14 (of which 6 provide PWM output)
Analog Input Pins 8 DC Current per I/O Pin 40 mA Flash Memory 32 KB (of which 2KB used by
bootloader) SRAM 2 KB EEPROM 1 KB Clock Speed 16 MHz
ARDUINO NANO FEATURES:
• Automatic reset during program download
• Power OK LED
• TX, RX, L LED
• Auto sensing/switching power input
• Small mini-B USB for programming and serial monitor
• ICSP header for direct program download
• Standard 0.1” spacing DIP (breadboard friendly)
• Manual reset switch
Figure 2.1 shows pinout of Arduino Nano and Figure 2.2 shows schematics of Arduino Nano.
FIGURE 2.1 PINOUT OF ARDUINO NANO
FIGURE 2.2 SCHEMATICS OF ARDUINO NANO
2.2 INTRODUCTION TO AVR DIGITAL INPUT/OUTPUT:
Digital I/O is the most fundamental mode of connecting a microcontroller to the outside world.
Atmel AVR ATMega 328P provides 23 I/O pins to interact with outside world in the form of logic
values. These pins are usually organised in groups and referred to as a port. Port B and Port D
have 8 pins each whereas Port C consists of 7 pins.
In Arduino nano, 20 pins are available for digital I/O. PC6 is connected with reset circuit and PB6
and PB7 are connected with crystal oscillator. So these 3 pins are not available for digital I/O in
Arduino nano.
Each of the AVR Digital I/O port is associated with three I/O registers.
• DDRx
• PORTx
• PINx
Where x is the port B, C or D.
2.2.1 DDRX - PORT X DATA DIRECTION REGISTER:
DDRx is an 8-bit register which stores configuration information for the pins of Portx. The bits in
this register set the data direction of the individual pins of a port. The direction of each pin can
be input or output. Writing a 1 in the pin location in the DDRx makes the physical pin of that
port an output pin and writing a 0 makes that pin an input pin.
DDRD= 0x00;
//Configures Port D as input
DDRB=0xFF;
//Configures Port B as output
The prefix 0x signifies hexadecimal number. 0xFF means decimal 255 or binary 11111111 which
means all the bits in register are at high logic level. 0x00 means all the bits in the register are at
low logic level. Each physical pin of a port is configured independently and thus a port can have
some of its pins configured as input and the others as output pins. For example:
DDRD = (1<<0)|(1<<4)|(1<<5)|(1<<7);
This is equivalent to
DDRD = 0b10110001; or
DDRD=0xB1;
In the above example, port D is initialized such that the pins PD0, PD4, PD5 and PD7 are output
pins whereas pins PD1, PD2, PD3 and PD6 are input pins.
We can change the value of a single bit without disturbing the previous value of all the other
bits of the register. For example:
DDRD |= (1<<5);
This will set bit 5 of DDRD while retaining the values of all other bits.
Similarly,
DDRD &= ~(1<<5);
This will clear bit 5 of DDRD while retaining the values of all other bits.
2.2.2 PORTX- PORT X DATA REGISTER:
PORTx is an 8-bit register which stores the logic values that are to be transferred on the physical
pins of Portx if the pins are configured as output pins. In short, once the direction of DDRx
register is defined as an output pins, we need to set them to give an output of HIGH logic or
LOW logic. So to write values to a port, you need to write the values to the “PORT” register of
that port.
PORTD = (1 << 0)|(1 << 3)|(1 << 6);
This is equivalent to
PORTD = 0b01001001;
Or
PORTD = 0x49;
2.2.3 PINX- PORTX INPUT PINS REGISTER:
PINx is an 8-bit register that stores the logic value, the current state, of the physical pins on
Portx. When you set any port as input you have to read its status using this register.
PINB = (1 << 0)|(1 << 3)|(1 << 6);
This is equivalent to
PINB = 0b01001001;
Or PINB =
0x49;
IN LAB-TASKS
Task-1: Write the given code in AVR studio and compile it. Use AVR dudes to upload the hex file
on the controller. Now see, the led will blink when connected to the controller.
Code:
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h> int
main()
{
DDRB = 0b11111111; while(1)
{
PORTB = 0b00001000;
_delay_ms(1000);
PORTB = 0b00000000;
_delay_ms(1000);
}}
Task 2: Switches are connected to one port of ATmega328p for input and LEDs are connected to
another port for output. Using these, perform a task assigned by your lab instructor. Students
should write the code for given task, simulate it on proteus and then implement it on hardware.
/*This code will configure Port B for output and then toggle Port B pin 3 with a delay of
1000ms*/
#include <avr/io.h>
*/
/*This header file includes the apropriate I/O definitions for the device
#define F_CPU 16000000UL //XTAL Frequency =16MHz
#include <util/delay.h> /*This header file is required for generating delays*/ int
main ()
{ // Write your code here
DDRB = 0b00000000; //Configure Port B as Output
= 0b11111111;
while (1)
//This loop will run forever
{unsigned char x; x=PINB;
if(x== 0b00000000)
PORTD =
0b00001000;
else if (x==0b0000001)
PORTD=0b00010000;
else if (x==0b00000010)
PORTD=0b10000000
;
else if (x==0b00000011)
PORTD=0b10001100 ;
else
DDRD
PORTD=0b00000000 ;
}}
CRITICAL ANALYSIS / CONCLUSION
In this lab we have learned the minimal circuit required to start using a microcontroller and how
to program (download code to program memory of) a microcontroller using Arduino board and
to understand and use digital I/O ports of AVR microcontroller.
AVR DIGITAL INPUT/OUTPUT: Atmel AVR ATMega 328P provides 23 I/O pins to interact with outside
world in the form of logic values. Port B and Port D have 8 pins each whereas Port C consists of 7 pins.
In Arduino nano, 20 pins are available for digital I/O.
Interfacing of devices was done with microcontroller and in turn program microcontroller in
order to perform specified tasks.
In first task given code was built on AVR studio and later simulated on proteus. Afterwards .Hex
file was burned to ATMega328P.In the second task given code was built on AVR studio and later
simulated on proteus. The code configured Port B for output and then toggle Port B pin 3 with a
delay of 1000ms. Both tasks were then simulated on proteus and verified
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 3
Name
Waqas Ahmed
Registration Number FA18-BEE-161
Class
5C
Instructor’s Name
Ma’am Asma Ramay
Lab # 03 Interfacing 7-Segment Display Using Digital
I/O Ports
Objectives:
•
Learn to interface components like seven-segment display using digital I/O ports.
Required Tools:
Software Tools:
•
•
•
AVR Studio/ Atmel Studio
Proteus ISIS
AVRDUDESS
Hardware Tools:
Name
Value
Quantity
Arduino Nano
7-Segment Display
Resistors
LED
Wires
470 Ω
Table 3.1 List of Components
1
1
8
1
-
Pre-Lab
Seven Segment Display:
A seven-segment display is a set of seven bar-shaped LEDs (light-emitting diodes) arranged to
form a squared-off figure 8. If all LEDs are activated, the display shows a numeral 8. When some
of the elements are activated but not others, any single-digit numeral from 0 to 9 is shown. Every
LED is assigned a name from 'a' to 'h' and is identified by its name. Seven LEDs 'a' to 'g' are used
to display the numerals while eighth LED 'h' is used to display the dot/decimal.
Seven-segment displays are commonly used in digital clocks, clock radios, timers, wristwatches,
and calculators. They can also be found in motor-vehicle odometers, speedometers, radio
frequency indicators, and practically any other display that
makes
use
of alphanumeric characters alone.
Figure 3.1 shows the arrangement of LEDs in a Seven Segment Display.
Figure 3.1: Seven Segment Display
Types of Seven segment display:
There are two types of LED 7-segment displays:
• Common Cathode
• Common Anode
Figure 3.2: Common Cathode and Common anode 7- Segment
In Common Cathode configuration, the negative terminals of all LEDs are connected to the
common pin. The common is connected to ground and a particular LED glows when its
corresponding pin is given high.
In Common anode arrangement, the positive terminals of all LEDs are connected to common
pin .The common pin is given a high logic and the LED pins are given low logic to display a
number.
Pin configuration of seven segment display:
The figure below shows Pin diagram of a 7- segment display. For common anode, COM pins
are given Vcc and for common cathode, COM pins are given ground.
Figure 3.3 Pin Configuration of different types of 7-Segment Display
Pre-Lab Task:
A seven segment display is connected with Port D. Write a code to toggle all the segments
simultaneously with some delay.
Disabling Tx and Rx on Port D:
The pins PD0 and PD1 are connected to the receiver and transmitter of of USART respectively.
To use these pins for digital I/O, we have to disable the transmitter and receiver. This can be
done by disabling TXEN0 and RXEN0 bits in UCSR0B register.
Disable Tx and Rx in your code as follows:
UCSR0B&=~(1<<TXEN0);
UCSR0B&=~(1<<RXEN0);
Simulate the code on Proteus (Proteus schematic is shown below).
Figure 3.4 Simulation for Pre-Lab Task
In Lab:
Task 1:
a. Implement Pre-lab task to test all segments of a 7-Segment display.
Task 2:
Interfacing of Seven Segment Display with AVR Microcontroller:
In this task a seven segment display is connected to Port D. On Port B a 4 inputs 7-segment
display is connected which takes BCD number and displays it on seven segment. An array is
created which is currently zero. This array will be filled with hexa-decimal numbers after
creating a Look-up table for 7-segment display.
Part a: Look-up Table:
Digit to
be
displayed
Hexadecimal
Value
H
g
F
0
1
0
0
0
0
1
0
1
0
1
0
1
1
1
1
1
0
0*3F
2
3
0
0
1
1
0
0
1
0
1
1
0
1
1
1
1
1
0*5B
4
5
6
7
8
9
0
0
0
0
1
0
1
1
1
0
1
1
1
1
1
0
1
1
0
0
1
0
1
0
0
1
1
0
1
1
1
1
1
1
1
1
1
0
0
1
1
1
0
1
1
1
1
1
0*66
Seven Segment Pin
e
d
c
ATmega 328P Pin
b
a
0*06
0*4F
0*6D
0*7D
0*07
0*7F
0*67
In Lab Task 2:
(To be specified by lab instructor)
Switches are connected to Port B for input and a seven segment display is
connected to PORT D of ATmega328p for output. Using these, perform a task
assigned by your lab instructor.
Task
Switches with PB. (4 switches
7 SEG with PD.
Display 0-9 on 7 segment using switches.
e.g when value of switches is 0001 -> display 1 on 7 seg
0000 -> display 0 on 7 seg
0010->2
0011->3
Ans:
Post lab task:
Connect 2 seven segments with Atmega 328P (As shown in schematic below).
Write a code to count from 0-99 on these 7- segments.
Figure 3.7: Simulation for Post Lab Task
Code:
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
int main(void)
{
DDRB = 0xff;
DDRD = 0xff;
UCSR0B&=~(1<<TXEN0);
UCSR0B&=~(1<<RXEN0);
unsigned char
seven_seg_array[10]={0x3F,0x06,0x5B,
0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char counterB = 0;
unsigned char counterD = 0;
while (1)
{
PORTD
=~seven_seg_array[counterD];
for (counterB=0 ;
counterB<10 ; counterB++)
{
PORTB=~seven_seg_array[counterB];
_delay_ms(200);
}
if (counterB == 10)
//when right display counts to 10 it gets
reset and left display in incremented
{
counterD++;
counterB = 0;
}
if (counterD==10)
{
counterD = 0;
//displays start counting from 0
}
}
return 0;
}
Critical Analysis / Conclusion
In this lab, I was able to program 7-segment display using AVR Studio. I was also familiarized
with the hexadecimal system of numbers which were required to operate the 7 LED’s of the
display in a various pattern which showed is numbers from 0 to 9. I was able to perform coding
for a single 7 segment display form range 0 to 9 and by using two 7 segments displays which
extended the counting range from 0 to 99. The important point was to disconnect Tx and Rx pins
implemented and then burn the code on hardware using AVRDUDESS. Seven Segment
Displays are mainly used to display numerical digits. A Seven Segment Display can also be used
to display certain letters of the alphabet.
MICROPROCESSOR SYSTEMS & INTERFACING
EEE-342
Lab Report # 04
Name
Waqas Ahmed
Registration Number
FA18-BEE -161
Instructor’s Name Asma Ramay
LCD Interfacing with AVR Microcontroller
OBJECTIVES:
•
•
Overview of controller to controller communication.
To understand LCD interfacing with AVR microcontroller.
TOOLS:
SOFTWARE TOOLS:
• Atmel Studio/ AVR Studio
• Proteus ISIS
• AVRDUDESS
HARDWARE TOOLS:
PRE-LAB
4.1 INTRODUCTION TO LCD
LCD provides an output interface to AVR microcontroller. It comes in various configurations
such as 20 x 2, 16 x 1, 40 x 1, 16 x 2 etc. with 5 x 8 or 5 x 11 dots resolution. Out of these, 16 x 2
is widely used.
LCD has a microcontroller in it which is already coded to display characters on the screen.
Therefor to use an LCD a controller to controller interface is required.
LCD controller is responsible for all the operations with in LCD such as movement of curser,
display clear, character printing and special character generation etc. HD44780U and S6A0069
are common examples of LCD control unit.
LCD controller’s internal memory comprises of Character Generator ROM (CGROM),
Character Generator RAM (CGRAM) and Display Data RAM (DDRAM).
• Character Generator ROM (CGROM) contain predefined character fonts table.
• Character Generator RAM (CGRAM) stores customized character table
• Display Data RAM (DDRAM) stores display data represented in 8-bit character codes.
4.1.1 LCD PIN CONFIGURATION
Figure 4.1 shows the pin configuration of LCD.
4.1.2 LCD COMMUNICATION MODES
The LCD can be used as 8-bit or 4-bit interface with microcontroller.
1. 8-bit communication.
2. 4-bit communication
In 8-bit communication 11 pins of MCU reserved as 8 pins for LCD data pins (D0-D7) and 3
pins for LCD Control Pins i.e. Enable (En is pin 6), Read/Write (RW is pin 5) and Register
Select (RS is pin 4). So each instruction executes in 1 cycle for 1byte instruction.
However, in 4-bit mode only 4 data pins (D0-D3) and 3 control pins are used so MCU reserves
7pins for LCD. Each instruction executes in normally 2 cycle for 1 byte instruction i.e. 1 nibble
per cycle
4.2 LCD INTERFACING
LCD controller has two 8-bit registers:
• Command Register allows the user to send commands such as clear display, cursor at
home etc.
• Data register allows the user to send the data to be displayed on LCD
Since same pins from D0 to D7 are used for both command and data, RS pin is used to identify
between the command and data.
Following steps are used to send command or data to LCD:
1. Initialize the LCD.
2. Send commands from Table 5.3 to LCD.
3. Send data to be displayed on LCD.
4.2.1 INITIALIZING THE LCD
To initialize the LCD for 5x7 matrix and 8-bit communication mode, following commands
should be send to LCD. See Table 5.3 for description of each command.
• Function Set: Select LCD mode to 8-bit interface, 2 line, and character size to 5x7.
• Display On/Off control: Display On, turn on the cursor, No blinking.
• Clear Display
• Entry mode set: Increment Cursor, No display shift
4.2.2 SENDING COMMANDS TO LCD:
To send any command from Table 5.3 to LCD, following steps should be followed.
• Set R/S and R/W pins to zero logic.
• Send the command code to pins D0-D07.
• Send a high to low pulse to Enable pin.
Enable pin is used to synchronize the whole operation of sending data or command to LCD. The
LCD will not read any pins for command or data until we give high to low transition level to
enable pin. After each command, add a delay of 100us to to wait for LCD controller to run the
command. After clear LCD and return home commands, wait for 2ms.
4.2.3 SENDING DATA TO LCD:
To send any data to be displayed LCD, following steps should be followed.
• Set R/S =1 and R/W = 0.
•
•
Send the data to pins D0-D07.
Send a high to low pulse to Enable pin.
PRE-LAB TASK
Find hexa-decimal codes for above mentioned commands using Table 4.3
CLEAR DISPLAY
RETURN HOME
ENTRY MODE
DISPLAY ON/ OFF CONTROL
FUNCTION SET
01
02
06
0E
38
IN-LAB TASK
Task-1: Complete the following code and simulate it on Proteus.
• Complete the LCD initialize function by using the command codes from Pre-Lab
task.
• Function to send commands to LCD is given, Write the function to send data on
LCD.
CODE TO BE IMPLEMENTED
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define RS PB0 //En pin is connected to PORTB Pin 0
#define RW PB1 //En pin is connected to PORTB Pin 1
#define EN PB2 //En pin is connected to PORTB Pin 2
int LCD_init(void);
void LCD_Send_Command(unsigned char);
void LCD_Send_Data(unsigned char);
int LCD_Send_Array(char * ptr);
int main(void)
{
LCD_init();
LCD_Send_Array("TRIOGENS"); /* Replace with your application code */
while (1) {
}
return(0);
}
int LCD_init() {
DDRD = 0b11111111;
DDRB = 0b00000111;
UCSR0B&=~(1<<TXEN0);
UCSR0B&=~(1<<RXEN0);
_delay_ms(100);
PORTB |= (1<<EN);
LCD_Send_Command(0x38);
_delay_ms(2);
LCD_Send_Command(0x0E);
_delay_ms(2);
LCD_Send_Command(0x01);
_delay_ms(2);
LCD_Send_Command(0x06);
return(0);
}
void LCD_Send_Command(unsigned char comm)
{
PORTB &= ~(1<<RS);
PORTB &= ~(1<<RW);
PORTD = comm;
PORTB &= ~(1<<EN);
_delay_ms(1);
PORTB |= (1<<EN);
}
void LCD_Send_Data(unsigned char data)
{
PORTB |= (1<<RS);
PORTB &= ~(1<<RW);
PORTD = data;
PORTB &= ~(1<<EN);
_delay_ms(1);
PORTB |= (1<<EN);
}
int LCD_Send_Array(char * ptr)
{
while(*ptr != '\0')
{
LCD_Send_Data(*ptr);
ptr++;
}
return(0);
}
PROTUES SIMULATION
CRITICAL ANALYSIS / CONCLUSION
The objective of this lab was to learn about the controller to controller communication and to
understand LCD interfacing with AVR microcontroller.
TASK 1 OUTCOMES: In this task a code was to given to display data on LCD using the
command LCD_Send_Array ( ). A delay was called between displaying the data continuously. The Tx
and Rx pins were disconnected while burning the code on microcontroller.
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 5
Name
Waqas Ahmed
Registration Number FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Lab # 05 Introduction to Assembly Language
Programming of AVR Microcontrollers
Objectives
•
•
To get started with assembly language programming for AVR microcontrollers.
Implementing loops and conditional execution instructions in Assembly language
Required Tools:
Software Tools:
•
•
•
AVR Studio/ Atmel Studio
Proteus ISIS
AVRDUDESS
Hardware Tools:
Name
Value
Quantity
Arduino Nano
Oscilloscope
Resistors
LED
Wires
470 Ω
Table 5.1 List of Components
1
1
1
1
-
Pre Lab
5.1 Introduction to Assembly Programming
Assembly language is a low-level programming language for a computer or other programmable
devices. It is an alphanumeric representation of machine code. The instructions used in writing
programs in assembly language are not general but specific to the microcontroller. AVR 8-bits
microcontrollers have a common instruction set.
5.1.1 Advantages of Assembly Language:
•
•
•
•
•
Assembly language is fast.
Program written in assembly take less execution time.
We know exact time for each instruction.
We are able to measure accurate execution time and hence able to generate specific delays.
It requires less memory.
•
The use of machine codes gives us precise control over microcontroller that we want to
program.
•
Assembly is also case insensitive hence commands written in upper or lower case don’t
make any difference.
5.1.2 Processor Registers:
There are 32 general-purpose 8-bit registers, R0–R31. All arithmetic and logic operations operate
on those registers; only load and store instructions access RAM. A limited number of instructions
operate on 16-bit register pairs.
The last three register pairs are used as pointer registers for memory addressing. They are known
as X (R27:R26), Y (R29:R28) and Z (R31:R30). Instructions which allow an immediate value are
limited to registers R16–R31 (8-bit operations) In addition to these 32 general-purpose registers,
the CPU has a few special-purpose registers:
•
•
•
PC: 16 bit program counter
SP: 16 bit stack pointer
SREG: 8 bit status register
5.2 Assembly Language Instructions:
Some common assembly language instructions used for AVR microcontroller programming are
given below:
Instruction Operands Description
Operation
IN
Rd , A
In from I/O location. Loads data from I/O space into Rd ← I/O(A)
destination register.
OUT
A, Rr
Out to I/O location. Stores data from register Rr in the I/O(A) ←Rr
Register File to I/O Space
NOP
This instruction performs a single cycle No Operation.
LDI
Rd, k
Load Immediate. Loads an 8 bit constant directly to Rd ← K
register 16 to 31.
BRNE
k
Branch if Not Equal. Conditional relative branch tests If (Z=0), then PC ←
the Zero Flag (Z) and branches relatively to PC if Z is PC+k+1
cleared.
BREQ
k
Branch if Equal. Conditional relative branch tests Z=1 If (Z=1), then PC ←
PC+k+1
CALL
k
RCALL
k
RET
RJMP
k
ADD
Rd, Rr
Dec
Rd
Long call to a subroutine. Calls to a subroutine within PC ← k
the entire program memory. The return address (to the
instruction after the CALL) will be stored onto the
stack.
Relative call to a subroutine. Relative call to an PC ← PC+k+1
address within PC - 2K + 1 and PC + 2K (words). The
return address (the instruction after the RCALL) is
stored onto the stack.
Return from a subroutine. The return address is loaded
from the Stack.
PC← Stack
Relative Jump
PC ← PC+k+1
Add without Carry
Rd ← Rd+Rr
Decrement
Table 5.2: Frequently used Assembly Language Instructions
Rd ← Rd-1
Pre-Lab Task:
Understand the operation of all instructions from Atmel AVR 8 bit instruction Set.
In-Lab
Task 1:
Generate a square wave signal of frequency 1 KHz and 40% duty cycle on a digital I/O pin of
ATmega328P.
Simulations:
Code:
.include "m328Pdef.inc"
;Initialize stack pointer.
ldi r16,HIGH(RAMEND)
out SPH, R16
ldi r16,LOW(RAMEND)
out SPL, R16
start:
ldi r16,0x01 ;load 0x01 into a register r16
out DDRB,r16 ;configure PB0 as output: DDRB=0x01
forever:
ldi r19,0x01 ;load 0x01 into a register
out PORTB,r19 ;PB0=1
rcall delay_400us
ldi r19,0x00
out PORTB,r19 ;PORTB=0x00
rcall delay_600us
rjmp forever ;keep doing this forever
delay_400us: ;This subroutine will call delay of 100us 4 times
;to generate a delay of 400us
ldi r20,4
loop1:
rcall delay_100us
dec r20
brne loop1
ret
delay_600us: ;This subroutine will call delay of 100us 6 times
;to generate a delay of 600us
ldi r20,6
loop2:
rcall delay_100us
dec r20
brne loop2
ret
delay_100us: ;This subroutine will generate a delay of 100us
; Inner loop count =4 (Ignoring overhead)
; Delay = (1/16M)*4*4*100
ldi r18, 4
l1: ldi r19,100
l2:
nop
dec r19
brne l2
dec r18
brne l1
ret
Output:
Hardware:
Done in the lab
In Lab Task 2:
Write a program to toggle all bits of PORT D with some delay (Specified by Lab Instructor).
Simulate it on Proteus and implement it on Hardware.
Simulations:
.include "m328Pdef.inc"
ldi r16,HIGH(RAMEND)
out SPH, R16
ldi r16,LOW(RAMEND)
out SPL, R16
start:
ldi r16,0xFF
out DDRD,r16
forever:
ldi r19,0x55
out PORTD,r19
rcall delay_400us
ldi r19,0xAA
out PORTD,r19
rcall delay_600us
rjmp forever
delay_400us: ;This subroutine will call delay of 100us 4 times
;to generate a delay of 400us
ldi r20,4
loop1:
rcall delay_100us
dec r20
brne loop1
ret
delay_600us: ;This subroutine will call delay of 100us 6 times
;to generate a delay of 600us
ldi r20,6
loop2:
rcall delay_100us
dec r20
brne loop2
ret
delay_100us: ;This subroutine will generate a delay of 100us
; Inner loop count =4 (Ignoring overhead)
; Delay = (1/16M)*4*4*100
ldi r18, 4
l1: ldi r19,100
l2:
nop
dec r19
brne l2
dec r18
brne l1
ret
Output:
Hardware:
Done in the lab
Post Lab Task:
Blinking LED’s with different frequencies.
Simulations:
.include "m328Pdef.inc"
ldi r16,HIGH(RAMEND)
out SPH, R16
ldi r16,LOW(RAMEND)
out SPL, R16
start:
ldi r16,0b00001111
out DDRB,r16
forever:
ldi r19,0b00001111
out PORTB,r19
rcall delay_200us;1
ldi r19,0b00001110
out PORTB,r19
rcall delay_200us;2
ldi r19,0b00001101
out PORTB,r19
rcall delay_200us;3
ldi r19,0b00001100
out PORTB,r19
rcall delay_200us;4
ldi r19,0b00001011
out PORTB,r19
rcall delay_200us;5
ldi r19,0b00001010
out PORTB,r19
rcall delay_200us;6
ldi r19,0b00001001
out PORTB,r19
rcall delay_200us;7
ldi r19,0b00000000
out PORTB,r19
rcall delay_200us;8
ldi r19,0b00000111
out PORTB,r19
rcall delay_200us;9
ldi r19,0b00000110
out PORTB,r19
rcall delay_200us;10
ldi r19,0b00000101
out PORTB,r19
rcall delay_200us;11
ldi r19,0b00000100
out PORTB,r19
rcall delay_200us;12
ldi r19,0b00000011
out PORTB,r19
rcall delay_200us;13
ldi r19,0b00000010
out PORTB,r19
rcall delay_200us;14
ldi r19,0b00000001
out PORTB,r19
rcall delay_200us;15
ldi r19,0b00000000
out PORTB,r19
rcall delay_200us;16
rjmp forever
delay_200us: ;This subroutine will call delay of 100us 4 times
;to generate a delay of 400us
ldi r20,2
loop1:
rcall delay_100us
dec r20
brne loop1
ret
delay_100us: ;This subroutine will generate a delay of 100us
; Inner loop count =4 (Ignoring overhead)
; Delay = (1/16M)*4*4*100
ldi r18, 4
l1: ldi r19,100
l2:
nop
dec r19
brne l2
dec r18
brne l1
ret
Output:
Digital Oscilloscope Diagram:
Critical Analysis / Conclusion
(By Student about Learning from the Lab)
In this lab we have learned how to do simulations while using assembly language instead of
C. It is analyzed that for assembly language we must use ATML instead of AVR studio for
simulations. It is analyzed that how to generate square wave with different duty cycles as well
as toggling of values in this lab.
Lab Assessment
Post Lab
Pre Lab
/1
In Lab
/5
Data Analysis
/4
Data
Presentation
/4
Writing Style
/4
/10
/4
Instructor Signature and Comments
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 6
Name
Waqas Ahmed
Registration Number FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Lab # 06 Keypad Interfacing Using Digital I/O Ports
Objectives:
•
•
Using digital I/O ports of AVR microcontroller for digital Inputs.
Use I/O ports To Interface matrix keypad with microcontroller.
Tools:
Software Tools:
•
•
•
AVR Studio/ Atmel Studio
Proteus ISIS
AVRDUDESS
Hardware Tools:
Name
Arduino Nano
4X4 Keypad
Resistors
Value
100Ω
Table 6.2: List of Components
Quantity
1
8
Pre Lab:
6.1 4x4 Membrane Keypad:
The Keypad 4x4 features 16 push buttons arranged in 4x4 matrix to form standard
alphanumeric keypad. It provides a useful human interface component for microcontroller
projects.Matrix keypads uses a combination of four rows and four columns to provide button
states to the microcontroller. Underneath each key is a pushbutton, with one end connected
to one row, and the other end connected to one column. These connections are shown in
figure 6.1.
Key Specifications
•
•
•
•
Maximum Rating: 24 VDC, 30 mA
Interface: 8-pin access to 4x4 matrix
Operating temperature: 32 to 122 °F (0 to 50°C)
Dimensions: Keypad, 2.7 x 3.0 in (6.9 x 7.6 cm) Cable: 0.78 x 3.5 in (2.0 x 8.8 cm)
This keypad can be used in Security systems, Menu selection, Data entry for embedded systems
and various other applications.
Figure 6.1: 4x4 Membrane Keypad
6.2 Working of keypad:
From Figure 6.11 it can be seen that if one of the 16 buttons are pressed, a pair of pins are
connected together. We will used this feature to detect with button was pressed. Under
normal conditions, the switch (key) is open. In order for the microcontroller to determine
which button is pressed, following steps are followed:
1) Create a look-up table filled with 16 entries for all keys of the keypad.
2) Four microcontroller pins should be defined as outputs, and other four pins should be defined
as inputs.
3) Connect columns of the keypad to input port and rows to the output port. Pull up the input
port and then read the value of columns.
4) Now connect rows of the keypad to input port and columns to the output port. Pull up the
input port and then read the value of rows.
5) If no key is pressed, the value of rows and columns will be 0000. If any key is pressed, the
value of rows and columns can be 0000,0001,0010,0100,1000 (1,2,4,8).
6) If no key is pressed, return 0. If a key is pressed, find its location in the keypad look-up table
and return the key pressed.
In-Lab:
Interfacing Atmega 328P with Keypad:
Simulations:
Code:
#include <inttypes.h> //Used for type casting
#include <avr/io.h> //Basic I/O definitions
#define F_CPU 16000000UL //XTAL Frequency
#include <util/delay.h> //to generate delays
///***************************
*******************************/
Definitions
for
UART
#include "debug_prints.c"
#define BAUD0 9600 // Baud Rate for UART
#define MYUBRR (F_CPU/8/BAUD0-1) // U2X = 1
//************* Definitions for Keypad Interfacing **********/
//Rows are connected to PORTB, Columns to PORTD
#define KEYPAD_DDR_ROWS DDRB
#define KEYPAD_PORT_ROWS PORTB
#define KEYPAD_PIN_ROWS PINB
#define KEYPAD_DDR_COLS DDRD
#define KEYPAD_PORT_COLS PORTD
#define KEYPAD_PIN_COLS PIND
/*Lookup table for Keypad*/
unsigned char keypad_tbl1[] = {255,0,1,255,2,255,255,255,3};
unsigned char keypad_tbl2[] = {'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D'}; // for Lab
Keypad
//unsigned char keypad_tbl2[] = {'7','8','9','/','4','5','6','X','1','2','3','-','C','0','=','+'}; // for proteus
model
unsigned char read_keypad(void);
int main()
{
unsigned char key_pressed = 0;
//Initalizting UART, Print UBRR value and F_CPU
UART0_init(MYUBRR);
printSerialStr("MYUBRR = ");
printSerialInt(MYUBRR);
printSerialStrln("");
printSerialStr("F_CPU = ");
printSerialInt((int)(F_CPU/1000000));
while (1) {
key_pressed = read_keypad();
if(key_pressed != 0) //wait for key to be pressed
{
UART0_send_char(key_pressed);//display pressed key on serial monitor
key_pressed = 0; } }
return 0; }
unsigned char read_keypad()
{ unsigned char columns;
unsigned char rows;
unsigned char key,temp;
//COMPLETE THIS SECTION OF CODE//
// Pull-up the columns
PORTD|=0xf0;
// Set columns to Input
DDRD&=0x0f;
//pull down the rows
PORTB&=0xf0;
// Set rows to Output
DDRB|=0x0f;
//give delay of 2ms
_delay_ms(2);
// read the value of columns
columns=0x0f&(~(PIND&0xf0)>>4);
_delay_us(100);
// Pull-up the rows
DDRB|=0x0f;
// Set rows to Input
DDRB&=0x00;
//pull down the columns
PORTD&=0x0f;
// Set columns to Output
DDRD|=0xf0;
//give delay of 2ms
_delay_ms(2);
// read the value of rows
rows=0x0f&(~(PINB&0x0f)); /* value of columns and rows will be 1,2,4,8
we will convert it to 0,1,2,3 using keypad_tbl1*/
temp = (keypad_tbl1[columns]) + (keypad_tbl1[rows]<<2); //multiply rows by 4
if(temp > 15) /*If value is greater than 15,return 0, otherwise return the key.*/
key = 0;
else
key = keypad_tbl2[temp];
_delay_ms(200);
return key;
}
Output:
Task 1- Hardware Implementation
Done in the lab.
Critical Analysis / Conclusion
(By Student about Learning from the Lab)
In this lab it is learned about the implementation of keypad on AURDINOIDE by uploading
the code in keypad. It is observed that after uploading the code in keypad and then by writing
the initial integer or an alphabet or arithmetic sign the same number is shown on the screen of
AURDINOIDE.
Lab Assessment
Post Lab
Pre Lab
/1
In Lab
/5
Data Analysis
/4
Data
Presentation
/4
Writing Style
/4
Instructor Signature and Comments
/10
/4
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 7
Name
Waqas Ahmed
Registration Number FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 1
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Lab # 07: Interfacing Analog Sensors using Analog to
Digital Converter
Objectives:
•
•
•
Understand the function of ADC in microcontroller.
Learn different mode of operation of ADC
Interfacing of LM35 temperature sensor with Atmega328p.
Software Tools:
•
•
•
•
Atmel Studio/AVR Studio
Arduino
Proteus ISIS
AVR DUDESS Hardware Tools:
Name
Value
Quantity
Arduino Nano
Breadboard
LM35
Table 7.3: List of Components
1
1
1
Pre-Lab
Analog to digital converters are the most widely used devices for data acquisition. Most of the
physical quantities are analog e.g. temperature, humidity, pressure, light, etc. Therefore, we need
an analog to digital converter to convert the data into digital data in order to communicate with
the digital processors like microcontrollers and microprocessors.
7.1 Internal ADC of ATmega328p microcontroller
The ADC in Atmega328p converts an analog input voltage to a 10-bit digital value through
successive approximation. The minimum value represents GND and the maximum value
represents the voltage on the AREF pin minus 1 LSB. Optionally, AVCC or an internal 1.1V
reference voltage may be connected to the AREF pin by writing to the REFSn bits in the
ADMUX Register.
The ADC system of Atmega328P has following features
•
10 bit ADC
•
±2 LSB absolute accuracy
•
13 ADC clock cycle conversion rate
•
8 multiplexed single-ended input channels
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 2
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
•
•
Selectable right or left result justification
0 to Vcc ADC input voltage range
7.2 ADC Register Description
1. ADC Multiplexer Selection Register – ADMUX
Bit 7:6 – REFS1:0: Reference Selection Bits
These bits select the voltage reference for the ADC, as shown in Table 8.2
Table 7.2: ADC Voltage reference selection
Bit 5 – ADLAR: ADC Left Adjust Result
The ADLAR bit affects the presentation of the ADC conversion result in the ADC Data Register.
Write one to ADLAR to left adjust the result. Otherwise, the result is right adjusted.
Bits 4:0 – MUX3:0: Analog Channel Selection Bits
The value of these bits selects which analog input is connected to the ADC. Table 8.3shows these
bit settings for selecting various single ended input channels:
Table 7.3: Mux ADC selection table
2. ADC Control and Status Register A – ADCSRA
Bit 7 – ADEN: ADC Enable
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 3
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off.
Bit 6 – ADSC: ADC Start Conversion
In Single Conversion mode, write this bit to one to start each conversion. ADSC will read as
one as long as a conversion is in progress. When the conversion is complete, it returns to zero.
Writing zero to this bit has no effect.
Bit 5 – ADATE: ADC Auto Trigger Enable
When this bit is written to one, Auto Triggering of the ADC is enabled (This mode is not covered
in this lab).
Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers are updated. The
ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set.
ADIF is cleared by hardware when executing the corresponding interrupt handling vector.
Alternatively, ADIF is cleared by writing a logical one to the flag.
Bit 3 – ADIE: ADC Interrupt Enable
When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Interrupt
is activated.
Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits
These bits determine the division factor between the XTAL frequency and the input clock to the
ADC.
Table 7.4: division factor calculation for frequency
3. The ADC Data Register –ADCL and ADCH
These two registers contain 10 bits of the conversion result. The result is stored in two different
ways depending on the setting of ADLAR bit as shown below:
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 4
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
ADLAR=0:
ADLAR=1
4. Digital Input Disable Register 0-DIDR0
When the respective bits are written to logic one, the digital input buffer on the corresponding
ADC pin is disabled. The corresponding PIN Register bit will always read as zero when this bit
is set. When an analog signal is applied to the ADC7...0 pin and the digital input from this pin is
not needed, this bit should be written logic one to reduce power consumption in the digital input
buffer.
7.3 Configuring the ADC
Following are the steps required to configure the ADC of AVR microcontrollers.
1. Disable digital I/O by writing ones in DIDR0.
2. Select a reference voltage and adjust your result to left/right using ADMUX register.
3. Select a pre-scalar for ADC clock on ADCSRA register. By default, the successive
approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz
to get maximum resolution
4. Enable the ADC by setting the ADC Enable bit, ADEN in ADCSRA. Voltage reference
and input channel selections will not go into effect until ADEN is set. The ADC does not
consume power when ADEN is cleared.
5. A '0' must be written to the Power Reduction ADC bit in the Power Reduction Register
(PRR.PRADC) before the ADC can be used.
6. ADC result is stored in ADCH and ADCL. By default, the result is presented right
adjusted. ADCL must be read first, then ADCH, to ensure that the content of the Data
Registers belongs to the same conversion. The ADC has its own interrupt which can be
triggered when a conversion completes.
7. A single conversion is started by writing a '1' to the ADC Start Conversion bit in the ADC
Control and Status Register A (ADCSRA.ADSC). ADCS will stay high as long as the
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 5
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
conversion is in progress, and will be cleared by hardware when the conversion is
completed. If a different data channel is selected while a conversion is in progress, the
ADC will finish the current conversion before performing the channel change.
8. Auto Triggering is enabled by setting the ADC Auto Trigger Enable bit
(ADCSRA.ADATE). The trigger source is selected by setting the ADC Trigger Select
bits in the ADC Control and Status Register B (ADCSRB.ADTS).
7.3.1 ADC Conversion Result
After the conversion is complete (ADCSRA.ADIF is set), the conversion result can be found in
the ADC Result Registers (ADCL, ADCH). For single ended conversion, the result is:
Where VIN is the voltage on the selected input pin, and VREF the selected voltage reference
7.4 Modes of operation:
The ADC has two fundamental operation modes:
1. Single conversion mode
2. Free running mode
7.4.1 Single Conversion Mode:
In Single Conversion mode, you have to initiate each conversion. When it is done, the result is
placed in the ADC Data register pair and no new conversion is started.
7.4.2 Free Running Mode:
It start the conversion only once, and then, the ADC automatically will start the following
conversion as soon as the previous one is finished. Its conversion is continuous. Once initialized
it takes 13 ADC cycles for single conversion. In this mode ADC data register has to be read
before new value is written.
7.5 LM35:
The LM35 is an integrated circuit sensor that can be used to measure temperature with an electrical
output proportional to the temperature (in oC).
PIN Configuration:
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 6
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Figure 7.1 LM35 Pinout
In Lab:
Task-1
Use LM35 to sense the room temperature. Convert this data into digital using atmega328P ADC and
display temperature value on virtual terminal. Complete the Code and simulate on Proteus.
Simulations:
Code:
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <string.h>
#include <math.h>
/****************** Definitions for UART *********************/
#include "debug_prints.c"
#define BAUD0 9600
// Baud Rate for UART
#define MYUBRR (F_CPU/8/BAUD0-1)
/*********************************************************************
************/
#define ADC_#include <inttypes.h>
#define ADC_CHANNEL0 0
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 7
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
#define ADC_CHANNEL1
#define ADC_CHANNEL2
1
2
#define ADC_VREF 5
// Ref voltage for ADC is 5 Volts
#define ADC_RES 10
// Resoulution of ADC in bits
#define ADC_QLEVELS 1024
// Quantization levels for the ADC
unsigned char ADC_Initialize();
unsigned int ADC_Read(unsigned char channel); // Reads the result of a single conversion
from the ADC
float ADC_Convert(unsigned int);
unsigned char VinToTemp(float Vin);
unsigned char read_temp_sensor(unsigned char ADC_channel);
#define TEMP_SENSOR_CHANNEL ADC_CHANNEL0
/*****************************************************************/
int main(void)
{
ADC_Initialize();
DIDR0=0xFF; //Disable digital I/O
DDRD = 0xFF;
UART0_init(MYUBRR);
printSerialStrln("Lab 8: ");
unsigned char temprature;
while(1)
{ printSerialStr("Temperature is ");
temprature = read_temp_sensor(TEMP_SENSOR_CHANNEL);
printSerialInt(temprature);
printSerialStr("\r \n");
PORTD = temprature;
_delay_us(1000000);
}
}
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 8
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
// Function Initializes the ADC for 10-Bit Single Conversion mode..
unsigned char ADC_Initialize()
{ //left adjust
ADMUX |=(1<<ADLAR);
// right adjust result. Vref = AVCC = 5V
/*** Write Code for this ***/
ADMUX|= (1<<REFS0); //Here select the prescaler for 16 MHz System Clock
ADCSRA |=(1<<ADPS1);
ADCSRA |=(1<<ADPS2); // Prescaler = 128
ADCSRA |=(1<<ADEN);// Clock for ADC = 125 KHz (should be between 50K to 200K)
return 0;
}
/* Function reads the result of a single conversion from the ADC
channel given as an argument*/
unsigned int ADC_Read(unsigned char channel)
{
unsigned char ADC_lo;
unsigned char ADC_hi;
unsigned int result;
ADMUX &= ~(0x07); // clear previous selction of channel
ADMUX |= channel; // Select the new channel
// Delay needed for the stabilization of the ADC input voltage
_delay_us(10);
//wait for ADC to finish any ongoing opeartion
while((ADCSRA & (1<<ADSC)) != 0);
ADCSRA |= (1 << ADSC); //start conversion
while((ADCSRA & (1<<ADIF)) == 0);
ADCSRA |= (1<<ADIF); // clear the flag by writing 1 to it
//result = (ADCH<<8)|(ADCL & 0xC0); // Left adjust result
ADC_lo = ADCL;
ADC_hi = ADCH;
result = (ADC_hi<<2)|(ADC_lo >> 6); // Right adjust result
return result;
}
/* This function takes an uint16 as input from the ADC.
This uint16 is an unsgined integer result of the ADC
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 9
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
encoded result. The function then converts this result
to floating point Voltage using the ADC_RES (resolution)
and ADC_REF (reference voltage) defined earlier*/
float ADC_Convert(unsigned int ADC_value)
{
float Vin;
Vin = ADC_VREF * ((float)ADC_value/ADC_QLEVELS);
return Vin;
}
/** This function takes the floating point Voltage value as input and
converts it to
corresponding Temprature in Celsius for an LM35 in Basic
Configuration.
The function returns an 8-Bit integer value of the Temprature */
unsigned char VinToTemp(float Vin)
{
unsigned char temprature=0;
float VoltsPerCentigrade = 0.01;
// 10 mv per centigrade
temprature = (unsigned char) floor(Vin/VoltsPerCentigrade);
return temprature; // Temprature value returned
}
/** This function reads the Value of Temprature Sensor (LM35) from
pre-defined ADC Channel and returns the result in Degree Celsius
as an 8-Bit unsigned int */
unsigned char read_temp_sensor(unsigned char ADC_channel)
{
unsigned int ADC_value = ADC_Read(ADC_channel); // Read the sensor Connected at
ADC_channel
float Vin = ADC_Convert(ADC_value);
// Get the value in floating point
unsigned char temp_celsius = VinToTemp (Vin); // Convert to temprature and return
return temp_celsius;
}
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 10
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Output:
Hardware:
Interface a temperature sensor with Arduino Nano and use serial monitor of Arduino IDE to
display temperature
…….
Done in lab
Critical Analysis / Conclusion
(By Student about Learning from the Lab)
In this lab it is analyzed about the construction of analog to digital converter while using
atmega328p.for the sake to check that if the converter works or not we used temperature sensor
in hardware as well as in software. It is observed that the temperature changed by placing the
finger on the sensor in hardware part while in software part it is done by clicking upon the
temperate sensor to stop or change the value.
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 11
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
Lab Assessment
Post Lab
Pre Lab
/1
In Lab
/5
Data Analysis
/4
Data
Presentation
/4
Writing Style
/4
/10
/4
Instructor Signature and Comments:
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 12
Lab # 07 Interfacing Analog Sensors using Analog to Digital Converter
COMSATS University Islamabad (CUI) , Islamabad Campus
Page 13
Microprocessor Systems & Interfacing
LAB Report # 08
Name
Registration Number
Submitted To
Waqas Ahmed
FA18-BEE-161
Ma’am Asma Ramay
Lab # 08 External and Internal Interrupts in
AVR Microcontrollers
OBJECTIVES
•
•
•
To learn the concepts related to interrupts in AVR microcontroller.
To configure and use the external interrupt or user input tasks
To configure and use the internal interrupts
SOFTWARE TOOLS
•
•
•
Atmel Studio or AVR Studio
Proteus
AVRDUDESS
HARDWARE TOOLS
PRE-LAB
What is Interrupt?
An interrupt refers to a notification, communicated to the controller, by a hardware device or
software, on receipt of which controller momentarily stops and responds to the interrupt.
Whenever an interrupt occurs the controller completes the execution of the current instruction
and starts the execution of an Interrupt Service Routine (ISR) or Interrupt Handler. ISR is a piece
of code that tells the processor or controller what to do when the interrupt occurs. After the
execution of ISR, controller returns to the instruction it has jumped from (before the interrupt
was received). The interrupts can be either internal interrupts or external interrupts.
Why needs interrupts?
An application built around microcontrollers generally has the following structure. It takes input
from devices like keypad, ADC etc., processes the input using certain algorithm and generates an
output which is either displayed using devices like seven segments, LCD or used further to
operate other devices like motors etc. In such designs, controllers interact with the inbuilt devices like
timers and other interfaced peripherals like sensors, serial port etc. The programmer needs to monitor
their status regularly like whether the sensor is giving output, whether a signal has been received or
transmitted, whether timer has finished counting, or if an interfaced device needs service from the
controller, and so on. This state of continuous monitoring is known as polling.
In polling, the microcontroller keeps checking the status of other devices and while doing so it does
no other operation and consumes all its processing time for monitoring. This problem can be
addressed by using interrupts. In interrupt method, the controller responds to only when an
interruption occurs. Thus, in interrupt method, controller is not required to regularly monitor the
status (flags, signals etc.) of interfaced and inbuilt devices.
To understand the difference better, consider the following. The polling method is very much like a
salesperson. The salesman goes door-to-door requesting to buy its product or service. Like controller
keeps monitoring the flags or signals one by one for all devices and caters to whichever needs its
service. Interrupt, on the other hand, is very similar to a shopkeeper. Whosoever needs a service or
product goes to him and apprises him of his/her needs. In our case, when the flags or signals are
received, they notify the controller that they need its service.
External Interrupts:
The External Interrupts are triggered by the INT pins or any of the PCINT pins. The Pin Change
Interrupt Request 2 (PCI2) will trigger if any enabled PCINT[23:16] pin toggles. The Pin Change
Interrupt Request 1 (PCI1) will trigger if any enabled PCINT[14:8] pin toggles. The Pin Change
Interrupt Request 0 (PCI0) will trigger if any enabled PCINT[7:0] pin toggles. The PCMSK2,
PCMSK1 and PCMSK0 Registers control which pins contribute to the pin change interrupts. Pin
change interrupts on PCINT are detected asynchronously.
The External Interrupts can be triggered by a falling or rising edge or a low level. This is set up as
indicated in the specification for the External Interrupt Control Register A (EICRA).
Internal Interrupts:
ATmega328p has 20 internal interrupts. These internal interrupts are generated by the internal
peripherals of Microcontroller like Timer, ADC etc. The internal interrupts are used for efficient
operation of the internal peripherals. They can be enabled through the registers of these peripherals.
In-Lab
How to use interrupts:
• First we have to configure and enable the global interrupts. The most significant bit of status
register called ‘I’ bit is used for this purpose. If ‘I’ is set 1 using register SREG this means
interrupt is enabled otherwise disabled.
• We write functions called Interrupt Service Routine (ISR) to handle interrupts. These
functions are defined outside the main function because the event that causes interrupt is not
known by the programmer; hence the function can’t be called inside the main function.
• Enable the external interrupts locally in External Interrupt Mask Register (EIMSK). Then
configure the interrupts for falling edge, rising edge, low level or any logical change by using
EICRA register.
• Enable the internal interrupts locally by writing 1 to interrupt enable bit in the registers of the
peripheral under use. For example, ADC system consists of ADIE bit in ADCSRA register.
ADIE bit is enabled to use ADC interrupts.
Advantages of Interrupt method:
• Priority can be assigned.
• Controller does not waste time checking if a device needs service or not.
Steps involved executing an interrupt:
Upon activation of an interrupt the microcontroller goes through the following steps as shown in
figure 7.1:
1. It finishes the instruction that it is executing and saves the address of next instruction on
the stack.
2. The program branches to the address of corresponding interrupt in the interrupt vector
table. The code starting here is called interrupt handler.
3. Check which source generated the interrupt using interrupt flags.
4. Executes the corresponding interrupt service subroutine.
5. Upon executing the last instruction in ISR the microcontroller returns to the place where
it was interrupted using reti instruction. First it gets the program counter address by
popping it from the stack. Then it starts to execute from that address.
Available interrupts in ATMEGA328P micro controller:
1. There are 26 interrupts in ATmega328P (Table 7.1) with 20 internal and 6 external
interrupts. The external interrupts are RESET, INT0 (pin16) and INT1 (pin17). All 21
interrupts are listed in table below in descending order of priority. In this lab we will
focus on external interrupts.
Register Description:
The registers involved in configuring the external interrupts are shown in below.
External Interrupt Control Register A(EICRA):
The External Interrupt Control Register A contains control bits for interrupt sense control
External Interrupt Mask Register (EIMSK):
In this register if INTn bit is set and the I-bit in the Status Register (SREG) is set, the external pin
interrupt is enabled.
External Interrupt Flag Register (EIFR):
When an edge or logic change on the INTn pin triggers an interrupt request, INTFn will be set. If the
I-bit in SREG and the INTn bit in EIMSK are set, the MCU will jump to the corresponding Interrupt
Vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be
cleared by writing '1' to it. This flag is always cleared when INTn is configured as a level interrupt.
In addition to above registers you will need to set Global Interrupt Enable (GIE) bit. GIE is bit7
of status register SREG.
For interrupt handling we need to include following header file into our project:
#include <avr/interrupt.h>
The following format is used to declare interrupt service routine:
ISR(ISR_Vect)
{
//Interrupt handling code goes here…..
}
IN-LAB TASK
TASK 1: GENERATE BINARY COUNTING WITH THE HELP OF LED’S
INTERFACED BY MCU AND CONTROLLED BY 2 SWITCHES. ONE FOR ENABLING
THE CIRCUIT AND THE OTHER IS TO RESET IT. SWITCH PRESSING IS AN
EXTERNAL EVENT, THAT’S WHY WE USE EXTERNAL INTERRUPTS. WRITE THE
C CODE FOR INTERRUPTS AND SIMULATE IN PROTEUS. REGISTERS USED IN
THIS TASK:
• EICRA
• EIMSK
• SREG (STATUS REGISTER)
CODE:
#include<avr/interrupt.h>
#include<avr/io.h>
#define F_CPU 16000000UL unsigned
char counter=0;
ISR(INT0_vect)
{
counter++; //Sw1 pressed LED on
PORTB = counter; //counter value displayed on portB
}
ISR(INT1_vect)
{
counter= 0x00; //reset counter
PORTB = counter; //counter value displayed on portB
}
int main()
{
DDRB= 0XFF;
counter=0;
SREG |=(1<<7) ;
//Enable interrupts globally
EIMSK|=(1<<INT0) ;
//Enable INT0 and INT1 interrupt locally
EIMSK|=(1<<INT1);
EICRA|= (1<<ISC01) ;
//configure EICRA for falling edge INT0 and INT1
EICRA|= (1<<ISC11);
while(1)
{
}
}
TASK 2: ASSUME THAT INT1 PIN IS CONNECTED TO A SWITCH THAT IS
NORMALLY LOW. WRITE A PROGRAM THAT TOGGLES PORTC 20 TIMES WITH
SOME DELAY WHENEVER INT1 PIN GOES HIGH.
CODE:
#include<avr/interrupt.h>
#include<avr/io.h>
#include<util/delay.h>
#define F_CPU 16000000UL unsigned
char counter=0;
ISR(INT1_vect)
{
for (int i=0;i<20;i++)
{
PORTC=0x00;
_delay_ms(500);
PORTC=0xFF;
_delay_ms(500);
} }
int main()
{
DDRC= 0XFF;
PORTC=0;
SREG |=(1<<7) ;
//Enable interrupts globally
EIMSK|=(1<<INT1);
//Enable INT1 interrupt locally
EICRA|= (1<<ISC10) ;
//configure EICRA for falling edge INT0 and INT1
EICRA|= (1<<ISC11);
while(1)
{
}
}
PROTUES SIMULATION
TASK 3: RECORD A SIGNAL USING ADC. USE ADC IN FREE RUNNING MODE.
ADD 8 BIT DAC AT PORT D AND CONVERT BACK THE SIGNAL IN ANALOG AND
DISPLAY RESULT ON OSCILLOSCOPE FOR COMPARISON.
TASK DESCRIPTION:
IMPLEMENTATION OF BUS IN PROTEUS.
• TO IMPLEMENT 8BIT DAC IN PROTEUS USE 10 DAC.
•
TAKE “BUS” (LABEL) FROM “TERMINALS MODE” AT SIDE BAR.
•
PLACED “BUS” AT ROOT SHEET. • CONNECT DAC BUS (BLUE LINE) TO
“BUS”. • DOUBLE CLICK AT “BUS” AND CHANGE ITS NAME TO
“DAC[0..9]”.
CONNECT PD0 TO DAC BUS. RIGHT CLICK ON WIRE AND SELECT
“PLACE WIRE LABEL”.
FROM DROP DOWN STRING MENU SELECT “DAC2”.
REPEAT LAST 2 STEPS WITH REST OF PD PINS.
CONNECT DAC0 AND DAC1 TO GROUND.
•
•
•
•
CODE:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define ADC_CHANNEL0 0
#define ADC_CHANNEL1 1
#define ADC_CHANNEL2 2
unsigned char ADC_Initialize(); // Initialize ADC
unsigned int ADC_Read(unsigned char channel); // Reads the result of a single conversion from
the ADC
#define DAC_DDR DDRD
#define DAC_PORT PORTD
ISR(ADC_vect)
{
DAC_PORT = ADCH; // ouput the digital value on DAC Port
}
int main(void)
{
ADC_Initialize();
DIDR0=0xFF;
DAC_DDR = 0xFF;
//Configure port for output
ADMUX &= ~(0x07);
// clear previous selction of channel
ADMUX |= ADC_CHANNEL1; // Select the new channel
SREG |=(1<<7);
//write command for this // Enable interrupts globally
ADCSRA |=(1<<ADSC) ;
// write command for this // Trigger the free running ADC
while(1)
{
}
}
unsigned char ADC_Initialize()
{
ADMUX |=((1<<ADLAR)|(1<<REFS0));
ADCSRA |=(1<<ADEN);
ADCSRA |=((1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2));
ADCSRA |=(1<<ADIE)|(1<<ADATE);
return 0; }
/* Function reads the result of a single conversion from the ADC channel
given as an argument*/
unsigned int ADC_Read(unsigned char channel)
{
unsigned char ADC_lo;
unsigned char ADC_hi; unsigned
int result;
ADMUX &= ~(0x07); // clear previous selction of channel
ADMUX |= channel; // Select the new channel
_delay_us(10); // Delay needed for the stabilization of the ADC input voltage
//wait for ADC to finish any ongoing operation while((ADCSRA &
(1<<ADSC)) != 0); ADCSRA |= (1 << ADSC); //start conversion
while((ADCSRA & (1<<ADIF)) == 0);
ADCSRA |= (1<<ADIF); // clear the flag by writing 1 to it
//result = (ADCH<<8)|(ADCL & 0xC0); // Left adjust result
ADC_lo = ADCL; ADC_hi = ADCH;
result = (ADC_hi<<2)|(ADC_lo >> 6); // Right adjust result return result;
}
PROTUES SIMULATION:
POST LAB TASK:
What is switch debouncing? Explain software and hardware methods for switch
debouncing.
A SWITCH DEBOUNCER CIRCUIT
There are many different approaches to cleaning up switch bounce. Below is a debouncing circuit.
The basic idea is to use a capacitor to filter out any quick changes in the switch signal.
A Switch debouncing circuit
The circuit's operation can be explained by looking at the equivalent circuits formed in the two
switch states, open and closed.
Debouncing circuit in switch open and closed states
Starting with the switch open.
•
•
•
The capacitor C1 will charge via R1 and D1.
In time, C1 will charge and Vb will reach within 0.7V of Vcc.
Therefore the output of the inverting Schmitt trigger will be a logic 0.
Now close the switch
•
•
The capacitor will discharge via R2.
In time, C1 will discharge and Vb will reach 0V.
ο‚’ SOFTWARE DEBOUNCE
Debouncing a switch in software is very simple. The basic idea is to sample the switch signal at a
regular interval and filter out any glitches. There are a couple of approaches to achieving this
listed below. Both approaches assume a switch circuit like that shown in the explanation of
switch bounce: a simple push switch with a pull-up resistor.
Approach 1
The first approach uses a counter to time how long the switch signal has been low. If the signal
has been low continuously for a set amount of time, then it is considered pressed and stable.
1
Setup a counter variable, initialize to zero.
2
Setup a regular sampling event, perhaps using a timer. Use a period of about 1ms.
3
4
5
6
7
8
10
11
On a sample event:
if switch signal is high then
Reset the counter variable to zero
Set internal switch state to released
else
Increment the counter variable to a maximum of 10 9 end if
if counter=10 then
Set internal switch state to pressed
12 end if
Approach 2
The second approach is similar to the first, but uses a shift register instead of a counter. The
algorithm assumes an unsigned 8bit register value, such as that found it 8-bit microcontrollers.
1
Setup a variable to act as a shift register, initialize it to xFF.
2
Setup a regular sampling event, perhaps using a timer. Use a period of about 1ms.
3
On a sample event:
4
Shift the variable towards the most significant bit
5
Set the least significant bit to the current switch value
6
if shift register val=0 then
7
Set internal switch state to pressed 8 else
9 Set internal switch state to released 10
end if
CRITICAL ANALYSIS AND CONCLUSION:
This lab is all about implementation of external as well as internal interrupts. It is observed that
interrupt directly effects the controller in a way that its appearance just stop the execution an give a
startup to interrupt service. It is found about how to enable that interrupt and observed to enable ikt
interrupt register must be cleared in case if any flag is high and to cleared it we must put 1 in bit.
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 9
Name
Waqas Ahmed
Registration
Number
FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Lab 09: Using Timer/Counter of AVR MCU for
Waveform Generation
In Lab Tasks:
Task 01:
A servomotor is connected to Timer OC0 pin and a potentiometer is connected to ADC
channel 0. Generate a PWM wave at Timer 0. The duty cycle of generated waveform should
vary according to the input voltage at channel 0 of the ADC (The duty cycle should vary as
you rotate the Potentiometer). By varying the On-Time of the signal the servo can be
rotated to different positions.
Code:
/*
* lab9task1.c
*
* Created: 04-Dec-2020, 3:44:10 pm
* Author : Lenovo
*/
#include <avr/io.h>
#include <inttypes.h>
#include <stdlib.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <string.h>
#include <math.h>
#define ADC_CHANNEL0
0
#define ADC_VREF
5
// Ref voltage for ADC is 5 Volts
#define ADC_RES
10
// Resoulution of ADC in bits
#define ADC_QLEVELS 1024
// Quantization levels for the ADC
unsigned char ADC_Initialize();
// Initialize ADC. Mode 1 = Single Conversion, Mode 2 = Free
Running
unsigned int ADC_Read(unsigned char channel);
// Reads the result of a single conversion from the
ADC
/******************* Function Prototypes *********************/
void init_timer0();
// Initialize Timer0 for Fast PWM mode
void move_motor(int adc_value); // vlaue = 0 to 1023 for -90 to 90 degrees angle
#define SERVO_OCR OCR0A
#define MIN_ANGLE_OCR 17.0
#define SERVO_OCR_OFFSET 14.0
// ***********************************************************
// Main program
int main(void)
{
init_timer0(); // timer0 configured for Fast PWM mode
ADC_Initialize();
int adc_value;
while(1)
{ // Infinite loop; define here the
adc_value = ADC_Read(0);
_delay_ms(20);
// Set motor Position
move_motor(adc_value); }}
void init_timer0()
{ OCR0A = (unsigned char) SERVO_OCR;
DDRD|=(1<<PD6);// Configure OC0A for output(PortD.6)
TCCR0A|=0x83;//Initialize timer0 for Fast PWM Mode, Non inverting,
TCCR0B|=0x05;// Set Pre scaler = 1024
}
/* Function Initializes the ADC for 10-Bit Single Conversion mode*/
unsigned char ADC_Initialize()
{
DIDR0=0x00;
ADMUX|=(1<<REFS0)|(1<<ADLAR);// Left adjust result. Vref = AVCC = 5V
ADCSRA|=(1<<ADEN); // Enable ADC
ADCSRA|=(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);//Select the pre scaler for 16 MHz System Clock
return(0); }
/* Function reads the result of a single conversion from the ADC
channel given as an argument*/
unsigned int ADC_Read(unsigned char channel)
{
unsigned char ADC_lo;
unsigned char ADC_hi;
unsigned int result;
ADMUX &= ~(0x07);
// clear previous selection of channel
ADMUX |= channel;
// Select the new channel
// Delay needed for the stabilization of the ADC input voltage
_delay_us(10);
//wait for ADC to finish any ongoing operation
while((ADCSRA & (1<<ADSC)) != 0);
ADCSRA |= (1 << ADSC); //start conversion
while((ADCSRA & (1<<ADIF)) == 0);
ADCSRA |= (1<<ADIF); // clear the flag by writing 1 to it
//result = (ADCH<<8)|(ADCL & 0xC0);
// Left adjust result
ADC_lo = ADCL;
ADC_hi = ADCH;
result = (ADC_hi<<2)|(ADC_lo >> 6); // Right adjust result
return result;
}
void move_motor(int adc_value) // value = 0 to 1023 for -90 to 90 degrees angle
{ SERVO_OCR=((float)adc_value/1023)*17+14; //if we use 8-bit timer then -90 degree (1 ms)
correspond to OCR
//value of approximately 14
}
Proteus:
Task 02:
Generate different waveforms using Timer0,1 and 2 as specified by your lab instructor.
View the generated waveforms on oscilloscope.
Code:
/*
* lab9task2.c
*
* Created: 04-Dec-2020, 7:44:03 pm
* Author : Lenovo
*
*/
#include <inttypes.h>
#include <stdlib.h>
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <string.h>
#include <math.h>
#define PH_CR_PWM_FREQ
20
#define PH_CR_PWM_TOP
255
#define PH_CR_PWM_DUTY_CYCLE
75.0
// A 20 KHz frequency
// TOP value for Timer0
// Duty Cycle for the PWM
#define FAST_PWM_DUTY_CYCLE_1 25.0
#define FAST_PWM_DUTY_CYCLE_0 10.0
#define CTC_OUTPUT_FREQ
void
void
void
void
2.0
// CTC mode output frequency in kHz
init_timer0();
// Initialize Timer0 for Phase Correct PWM mode(0), or Fast PWM mode(1)
init_timer1(void);
// Initialize Timer1 for Fast PWM on two channels
init_timer2(void);
// Initialize Timer2 for CTC mode
move_motor(int adc_value);
// value = 0 to 1023 for -90 to 90 degrees angle
int main(void)
{
init_timer0(); // timer0 configured for Fast PWM mode
init_timer2(); // Timer 2 configured for CTC mode
init_timer1(); // Timer 1 configured for FAST PWM mode (Channel A: Non-Inverting, Channel B:
Inverting)
while (1)
{
/*Initialize Timer0 for Fast PWM mode System Clock = 16 MHz Prescaler = 1024 PWM Freq = 16
Meg/1024*256 == 61 Hz FAST_PWM_DUTY_CYCLE defined at the top determines the duty cycle of the
generated signal */
void init_timer0()
{
float temp1 = FAST_PWM_DUTY_CYCLE_0/100;
long temp2;
DDRD |= (1<<PD6);
// Configure OC0A for output
temp1 *= 256;// set the OCR0A value according to the desired Duty Cycle
temp2 = (long) temp1;
OCR0A = (unsigned char) temp2;
TCCR0A|=(1<<COM0A1);
TCCR0A|=(1<<WGM01)|(1<<WGM00);
TCCR0B|=(1<<CS02)|(1<<CS00);
// Fast PWM Mode, Non inverting,
// Prescaler = 1024
}
/* Initialize Timer1 for Fast PWM mode. channel A with non-inverting PWM and channel B with
inverting PWM. The frequency of the PWM signal depends on the TOP value defined. For Top = 255, and
Fclk = 16 MHz, and Prescaler = 16 PWM freq == 4KHz (Approximately) Duty Cycle depends on the Values
of OCR1A and OCR1B.*/
void init_timer1(void)
{
float temp1 = FAST_PWM_DUTY_CYCLE_1/100;
temp1 *= 256;
// set the OCR1A/B values according to the desired Duty Cycle
long temp2;
temp2 = (long) temp1;
DDRB |= ((1<<PB1)|(1<<PB2));
// set OC1A and OC1B as outputs
OCR1AL = (unsigned char) temp2;// Assign the desired duty cycle values
OCR1AH = 0;
OCR1BL = (unsigned char) temp2;
OCR1BH = 0;
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);
TCCR1A|=(1<<WGM10);
TCCR1B|=(1<<WGM12)|(1<<CS10);
// Non-Inverting PWM on A, Inverting on B
// For 8-bit mode. TOP = 0xFF.
// Prescaler = 1}
/*Initialize Timer2 for CTC mode System Clock = 16 MHz Prescaler = 8Output Signal Freq
= 125 KHz/(2*OCR2)OCR2 value sets the output signal freq*/
void init_timer2(void)
{
float temp1 = (125/CTC_OUTPUT_FREQ)/2;
long temp2;
DDRB |= (1<<PB3);
// Configure OC2A for output
temp2 = (long) temp1;
OCR2A = (unsigned char) temp2;
// CTC Mode, Toggle OC2A on compare match
TCCR2A|=(1<<COM2A0);
TCCR2A|=(1<<COM2B0);
TCCR2A|=(1<<WGM21);
TCCR2B|=(1<<CS22)|(1<<CS20);
}
}
Proteus:
Conclusion:
In this lab we configure the timing sub-system of AtMega16 for different modes of wave-form
generation. Specifically, Timer0 (an 8-bit timer) is configured for Fast PWM mode. Timer1 is
configured so that the two channels provide Fast PWM outputs which are out of phase
with each other. Timer2 is used in the CTC mode
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 10
Name
Waqas Ahmed
Registration Number
FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Lab 10: Recording a Periodic Signal using Input
Capture Feature of Timers/Counters
Task 01:
Code:
*
* lab10task01.c
*
* Created: 13-Dec-2020 12:56:34 am
* Author : Lenovo
*/
#include <inttypes.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr\interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <string.h>
#include <math.h>
/****************** Definitions for UART *********************/
#include "debug_prints.c"
#define BAUD0 9600
// Baud Rate for UART
#define MYUBRR (F_CPU/8/BAUD0-1)
// U2X = 1
/****************** Global Variables ************************/
unsigned char icp_low = 0;
unsigned char icp_high = 0;
unsigned int input_capt_counter=0;
unsigned int rising1 = 0;
unsigned int rising2 = 0;
unsigned int falling1 = 0;
unsigned char capture_complete=0;
float sig_freq = 0;
float sig_dc = 0;
/************************************************************/
#define TRUE 1
#define FALSE 0
/*************** Function Prototypes here ********************/
void timer_init(void);
// Function to initialize Timer1 for Input Capture
void display_counter_values(void);
void display_signal_parameters(void);
void calculate_signal_param(void);
// ***********************************************************
// Main program //
int main(void)
{ DDRB &= (1<<PB0);
// Set PB0 (ICP1) for input
PORTB|= (1<<PB0);
// Activate internal pull-up
UART0_init(MYUBRR);
printSerialInt(MYUBRR);
printSerialStrln("");
printSerialStr("F_CPU = ");
printSerialInt((int)(F_CPU/1000000));
printSerialStrln("MHz");
printSerialStrln("Lab 10: Input Capture");
timer_init();
//******* Write Code For This ********//
EICRA|=(1<<ISC01); //Set interrupt sense control bits to falling edge for INT0
EIMSK|=(1<<INT0);//Enable INT0 locally
SREG=(1<<7);// Enable interrupts globally
int i=0;
while(1)
{ if(capture_complete == TRUE)
{ display_signal_parameters();
// display frequency and duty cycle
capture_complete = FALSE;
for(i=0; i<8; i++) // wait for 2 seconds
_delay_ms(250);
printSerialStrln("Press the button ..");
}}}
/* This function will setup Timer1 for Input Capture Mode. if Fclk = 16MHz, and
prescaler = 8, then 1 count = 0.5us. 2000 counts will fit a Time period of 1ms (f = 1 KHz). 500
Counts will fit a Time period of 0.25 ms (f = 4 KHz). */
void timer_init(void)
// Write code for this function
{ ACSR &= ~(1<<ACIC); // Disconnect the Analog Comparator output from the Input
Capture Unit
TCCR1A=0x00;// Normal Mode, OC1A and OC1B disconnected.
TCCR1B|=(1<<ICES1);
TCCR1B|=(1<<CS11);// Initially capture rising edge. Prescaler = 8
TCNT1L = 0;
TCNT1H = 0;
TIMSK1|=(1<<ICIE1);// Enable interrupt of Timer 1 input capture
}
/* Interrupt Service Routine for INT0. When the user presses the button, the ISR
clears TCNT1, capture_complete, rising1, rising2 and falling1 global variables. Then it turns on the
interrupts for Timer1 Input Capture. */
ISR(INT0_vect)
{
//printSerialStrln("Processing External Interrupt 0: ");
rising1 = 0; rising2 = 0; falling1 = 0;
capture_complete = FALSE;
input_capt_counter = 0;
sig_freq = 0;
sig_dc = 0;
TCCR1B |= (1<<ICES1);
// for rising edge on ICP1
TCNT1 = 0;
// clear the free running counter of Timer 1
TIMSK1 |= (1<<ICIE1); // Enable interrupt of Timer 1 input
capture
}
/* ISR for Input Capture of Timer1. You need to write code and complete this
function*/
ISR(TIMER1_CAPT_vect)
{
//printSerialStrln("Processing Timer Interrupt: ");
icp_low = ICR1L;
icp_high = ICR1H;
input_capt_counter ++;
//printSerialInt((int)input_capt_counter);
//printSerialStrln("");
if(input_capt_counter == 2)
{ rising2=(ICR1H<<8)|(ICR1L);// Record the counter value on first Rising Edge
} if(input_capt_counter == 3)
{ rising2=(ICR1H<<8)|(ICR1L); // Record the counter value on second Rising Edge
TCCR1B&=~(1<<ICES1); // Change the polarity of sensing
TIFR1=(1<<ICF1);// Clear ICF flag as prescribed in the Datasheet Page
157 Section 20.9.3
}
if(input_capt_counter == 4)
{
falling1=(ICR1H<<8)|(ICR1L);// Record the counter value on first Falling
Edge
TIMSK1&=~(1<<ICIE1);// disable further interrupts of Timer 1 input
capture
capture_complete = TRUE; // capture is complete at this point
calculate_signal_param(); // calculate the Frequency and Duty Cycle of
the Input Signal
} }
/** This function displays the values of the captured edges 'rising1',
'rising2', and 'falling1'. */
void display_counter_values()
{ printSerialStr("Rising 1: ");
printSerialLong((long int) rising1);
printSerialStrln("");
printSerialStr("Rising 2: ");
printSerialLong((long int) rising2);
printSerialStrln("");
printSerialStr("Falling 1: ");
printSerialLong((long int) falling1);
printSerialStrln(""); }
/** Function to display the Frequency and Duty Cycle of the Captured signal.*/
void display_signal_parameters(void)
{
printSerialStr("Frequency = ");
printSerialFloat(sig_freq);
printSerialStrln(" Hz");
printSerialStr("Duty Cycle = ");
printSerialFloat(sig_dc);
printSerialStrln(" %"); }
/** This function is called after all the required edges are captured and saved
in global variables 'rising1', 'rising2', and 'falling1'. It calculates the input signal frequency
and its duty cycle and saves them in corresponding variables.*/
void calculate_signal_param(void)
{ printSerialStrln("Calculating Signal Parameters ... ");
if((rising2-rising1) != 0) // if denominator is non-zero
{
sig_freq = F_CPU/(8*(float)(rising2-rising1));
//Here Prescalar =
8 so Ftimer == F_CPU/8
sig_dc = 100.0 * ((float)(falling1 - rising2))/((float)(rising2rising1)); // ON-Time/ Total Time * 100 %
}
else
{ sig_freq = 0;
sig_dc = 0;
}
display_counter_values();
display_signal_parameters();
}
Proteus:
Post lab task:
Input capture is a method of dealing with input signals in an embedded system. Embedded systems using
input capture will record a timestamp in memory when an input signal is received. It will also set a flag
indicating that an input has been captured. This allows the system to continue executing without interruption
while an input is being received while still having the capability to trigger events based on the exact time
when the input was received.
The Compare Mode operates identical for both CCPx and ECCPx peripherals. When a match occurs, one of
the events can occur for example Toggle the CCPx output pin, set the CCPx output pin, clear the CCPx
output pin, generate a Special Event Trigger or generate a Software Interrupt.
Conclusion:
In this lab, we learnt about the input capture feature of the Timers/Counters in microcontrollers and also
emphasize on the preference of interrupt-based designs over polling mechanisms. We gave and input signal
of periodic pulse train. Then we calculated the frequency and duty cycle of this signal. A code was given to
us to configure interrupts to work with external interrupts and input capture of Timer1. Adding the missing
parts in the code we run the code on atmel and making the circuit on proteus we upload the hex file of the
code to the microcontroller.
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 11
Name
Waqas Ahmed
Registration Number
FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Lab 11: Serial Communication with UART and
Interfacing Bluetooth HC-05
In lab tasks:
Task 01:
Code:
#include <avr\io.h> // Most basic include files
#include <avr\interrupt.h> // Add the necessary ones
#define F_CPU 16000000UL
#include <util\delay.h>
#include <string.h>
// a System clock of 16 MHz
// ************** Definistion for USART **********************
#define BAUD 9600.00 // Baud Rate Declared as a float
#define UBRR_VAL (F_CPU/(16*BAUD))-1 // Corresponding UBRR Value
// ***********************************************************
void USART_Init(unsigned int ubrr); // function to Initialize the USART
void USART_Transmit(unsigned char data); // Transmit Data via USART
unsigned char USART_Receive(void); // Receive Data via USART
void USART_send_str(char * string1); // Transmit a string
void USART_read_str(char * ); // Read the USART buffer
// ***********************************************************
unsigned int data_available = 0; // A flag to indicate that data is available in the receive buffer
// Main program
int main(void)
{
USART_Init((unsigned int)UBRR_VAL);
unsigned char data;
while(1)
{ // Infinite loop; define here the
data = USART_Receive();
_delay_ms(20); // a 20 ms Delay between receiving and sending data
USART_Transmit(data);
}
}
void USART_Init(unsigned int ubrr)
{
/* Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Complete this code*/
UCSR0B|=(1<<TXEN0)|(1<<RXEN0);/* Enable receiver and transmitter */
UCSR0C|=(1<<UPM01)|(1<<UPM00)|(1<<UCSZ01)|(1<<UCSZ00);/* Set frame format: 8data, 1stop bit, odd parity */
}
void USART_Transmit(unsigned char data)
{ while (!(UCSR0A & (1<<UDRE0)));
UDR0=data; /* Wait for empty transmit buffer */
/* Put data into buffer, sends the data */
}
unsigned char USART_Receive(void)
{
while (!(UCSR0A & (1<<RXC0)));
return UDR0;
/* Wait for data to be received */
/* Get and return received data from buffer */
}
void USART_send_str(char * str) // Transmit a string
{
char i=0;
for(i=0; i<strlen(str); i++)
{
USART_Transmit(str[i]);
}
}
void USART_read_str(char * str) // Read a string from UART
{
char ch;
char i;
do
{
ch = USART_Receive();
str[i] = ch;
}
while(ch != '\0');
}
Proteus:
Task 02:
Code:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // (Rx,TX)
void setup()
{ Serial.begin(9600); // the Arduino Baud rate
delay(1000);
mySerial.begin(9600);
delay(1000);
Serial.println("System Initialized");
}
void loop()
{
if(Serial.available())
mySerial.print ((char) Serial.read());
if(mySerial.available())
Serial.print((char) mySerial.read()) ;
}
Conclusion/ critical Analysis:
In this lab, we learnt about how to implement serial communication using UART of Atmega328p and how
to establish Bluetooth connectivity between Atmega328p and an Android mobile device. We configured
UART of Atmega328P for Asynchronous Serial communication also the data was transmitted and received
in an echo back mechanism that is the UART received data and transmitted it back. The received can be
seen on visual terminal of proteus simulation. For the second task The code was implemented on Arduino
nano and Bluetooth module HC-05 was connected to the mobile phone and using the app “Serial Bluetooth
Terminal”.
Microprocessor Systems & Interfacing
EEE-342
Lab Report # 12
Name
Waqas Ahmed
Registration Number
FA18-BEE-161
Class
BEE-5C
Instructor’s Name
Ma’am Asma Ramay
Objectives:
• To learn about Serial Peripheral Interfacing (SPI) and SPI programming
• Implementation of SPI using microcontroller (ATmega328P) in proteus.
Tools:
Software Tools:
• Atmel Studio/ AVR Studio
• Proteus ISIS
• AVR DUDESS
Hardware Tools:
Name
Value
Quantity
Arduino Nano
-
1
Breadboard
-
1
MCP4821
-
1
Table 12.1: List of Components
Pre-LB:
Introduction to Serial Peripheral Interfacing (SPI)
Serial Peripheral Interface (SPI) is an interface bus commonly used to send data between microcontrollers
and small peripherals such as shift registers, sensors, and SD cards. It uses separate clock and data lines,
along with a select line to choose the device you wish to talk to.
A common serial port, the kind with TX and RX lines, is called “asynchronous” because there is no control
over when data is sent or any guarantee that both sides are running at precisely the same rate. To work
around this problem, asynchronous serial connections add extra start and stop bits to each byte help the
receiver sync up to data as it arrives. Both sides must also agree on the transmission speed (such as 9600
bits per second) in advance
SPI works in a slightly different manner. It’s a “synchronous” data bus, which means that it uses separate
lines for data and a “clock” that keeps both sides in perfect sync. The clock is an oscillating signal that
tells the receiver exactly when to sample the bits on the data line. This could be the rising (low to high)
or falling (high to low) edge of the clock signal; the datasheet will specify which one to use. When the
receiver detects that edge, it will immediately look at the data line to read the next bit.
HOW SPI WORKS:
SPI consists of two shift or more registers. One at master side, others at slave side.In SPI, only one side
generates the clock signal .The side that generates the clock is called the “master”, and the other side is
called the “slave”. There is always only one master (which is almost always your microcontroller), but
there can be multiple slaves.When data is sent from the master to a slave, it’s sent on a data line called
MOSI, for “Master Out / Slave In”. If the slave needs to send a response back to the master, the master
will continue to generate a prearranged number of clock cycles, and the slave will put the data onto a
third data line called MISO, for “Master In / Slave Out”.
Slave Select (SS)
Slave select line tells the slave that it should wake up and receive / send data and is also used when
multiple slaves are present to select the one you’d like to talk to.
The SS line is normally held high, which disconnects the slave from the SPI bus just before data is sent to
the slave, the line is brought low, which activates the slave. When you’re done using the slave, the line is
made high again.
SPI Read and Write:
In connecting a device with SPI bus to a microcontroller, we use microcontroller as master and SPI device
as slave. Microcontroller generates SCLK which is SCLK pin of SPI. The information address and data) is
transferred between microcontroller and SPI device in group of 8 bits, where address byte is followed
immediately by data byte. To distinguish between the read and write operations, the D7 bit of address
byte is always 1 for write, while for read, D7 bit is low.
Figure 12.1 SPI Pins
In Lab:
SPI Programming in AVR:
In AVR, three Registers are associated with SPI. They are SPSR (SPI Status Register), SPCR (SPI Control
Register) and SPDR (SPI Data Register).
Figure 12.2: Working of SPI
SPI Control Register 0:
SPI Control Register 0 is shown below.
SPI Status Register 0:
SPI Status Register 0 is shown below:
SPI Data Register 0:
The SPI Data register is a Read/write register. It contains data to be transmitted or received data.
Writing to SPDR register initiates data transmission.
Clock Polarity and phase in SPI:
In SPI communication, the master and slaves must agree on clock polarity and phase. Table 12.3 shows
options of clock polarity and phase.
MCP4821 DAC:
MCP4821 is a single channel 12-bit Digital-to-Analog converter (DAC) with internal voltage reference. This
device offers high accuracy and low power consumption, and is available in various packages.
Communication with the device is accomplished via a simple serial interface using SPI protocols.
Some of its features are:
•
•
•
•
•
•
•
12-bit Resolution
Single Channel Voltage Output
2.7V to 5.5V Operation
Operating Current 330 µA (typ)
Internal Voltage Reference 2.048V
Selectable Unity or 2x Gain Output
works with SPI mode 0
Figure12.6: Pin diagram of MCP4821
(where 𝐺 is gain)
MCP4821 DAC SPI Register
Some features of MCP4821 DAC SPI Register are:
Only one 16-bit data register
a)
b)
c)
Bit 15 should always be written with zero
Gain 𝐺 = 2 if 𝐺𝐴 = and Gain 𝐺 = 1 if 𝐺𝐴 = 1
𝑆
𝐻𝐷𝑁 = 1 to activate device, otherwise shutdown
d)
D11 down to D0 the digital input
Fig 12.7 16-bit data register
➒
➒
MSB is shifted in first then LSB is shifted
AVR has SPI module with 8-bit shift register
a) So AVR need to send 16-bit data in two portions
b) First send upper byte, then lower byte
Fig 12.8: Sending data from AVR to MCP 4821 Data register
In Lab Task:
Task 1:
The given code contains functions to write bytes to SPI and writing to DAC. Your task is to
write code to send a sequence of numbers to the DAC to generate a saw-tooth wave. Use gain =2x
Code:
Triangular Wave:
/*
* AVRGCC2.c
*
* Created: 12/24/2018 12:17:05 PM
*
Author: Maham Nadeem
*/
#include <avr\io.h> // Most basic include files
#include <avr\interrupt.h> // Add the necessary ones
#include <avr\signal.h> // here
#define F_CPU 16000000
#define MOSI 3
#define SCK 5
#define SS 2
void SPI_byte_send(char ebyte);
void write_SPI_DAC(unsigned int val);
void SPI_Init(void);
int main(void)
{
unsigned int val = 0;
DDRC=0xFF;
SPI_Init();
while (1)
{
for (int i=0;i<4095;i++)
{
write_SPI_DAC(i);
}
for (int i=4095;i>=1;i--)
{
write_SPI_DAC(i);
}
}
}
void SPI_byte_send(char ebyte)
{
//This function send one byte through AVR SPI module
//This function should ensure that existing communication is complete
//PORTC = SPSR;
SPDR = ebyte;
while(!(SPSR & (1<<SPIF)));
}
void write_SPI_DAC(unsigned int val)
{
//clear SS
PORTB &= ~(1<<SS);
//Send upper byte (0b0000xxxx) where xxxx is upper four bits of Digital data
//Upper nible zero suggest GA'=0 SHDN'=0
SPI_byte_send(0b00110000 | ( (val>>8) & 0x0F )); //send upper byte
//Send lower 8 bits of digital data
SPI_byte_send( val & 0xFF ); //send lower byte
//Set SS
PORTB |= (1<<SS);
//_delay_us(50);
}
void SPI_Init()
{
DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
SPSR|=(1<<SPI2X);
SPCR|=(1<<MSTR)|(1<<SPE);
}
Simulation:
Figure 1
Critical Analysis:
In this lab I learnt about the features and characteristics of SPI (serial peripheral interfacing)
which is used to communicate the microcontroller with registers and SD cards. It has 4 lines or
more which work synchronously. SPI consists of two shift or more registers. One at master side,
others at slave side. In SPI, only one side generates the clock signal. The side that generates the
clock is called the “master”, and the other side is called the “slave”. There is always only one master
(which is almost always your microcontroller), but there can be multiple slaves. When data is sent
from the master to a slave, it’s sent on a data line called MOSI, for “Master Out / Slave In”.
moreover, I got to know that it works in slave or master mode and in order to select these modes
first we put the values in CPOL and CPHA which are actually bits of SPCR representing polarity and
phase, also Digital to Analog converter MCP4821 was used and it was communicated through SPI
protocol which produced a sawtooth waves as observed in lab task.
Download