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.