This is a continuation of the following tutorials:
ATmega328P and its Architecture
The Pinout (with ports):Zoom-In to see the Ports and the bit numbers.
Note: This project is a continuation of this content. Please take a look at it before starting this project.
Three ports, Port B, Port C, and Port D can be used as general I/O pins. Port B and Port D are used as Digital I/O while Port C is used for Analog I/O. However, Port C can also be used as Digital I/O in case you need more I/O,
Now the digital I/O can be made high or low by writing the respective bits into the port registers.
There are 3 states of an I/O pin, HIGH, LOW, and HIGH IMPEDANCE.
HIGH refers to logic 1 and LOW refers to logic 0. While HIGH IMPEDANCE refers to the "NC (No Connection)" state. It's always recommended not to leave any pins to be in a floating / high impedance state as it may sometimes lead to failure of design.
Thus the other pins can be pulled down.
Wait, what's pull-down?
The ATmega328P is equipped with pull-up and pull-down resistors. This means that, if they are not in use or if they're connected to a switch they can be tied to VCC or Ground to avoid the floating state.
The diagram below depicts the arrangement of how the pull-up or pull-down resistor can be used while connecting a switch.
In the assembly language, certain keywords or mnemonics are used to specify the instructions that the processor needs to execute.
Few Basic Instructions of the Assembly language are listed below with the Syntax for a better understanding of the usage.
LDI – Load ImmediateLoads an 8 bit constant directly to register 16 to 31.
Loads one byte from the data space to a register. For parts with SRAM, the data space consists of the Register File, I/O memory, and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space consists of the register file only. The EEPROM has a separate address space.
Stores one byte from a Register to the data space. For parts with SRAM, the data space consists of the Register File, I/O memory, and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space consists of the Register File only. The EEPROM has a separate address space.
Loads data from the I/O Space (Ports, Timers, Configuration Registers, etc.) into
register Rd in the Register File.
Stores data from register Rr in the Register File to I/O Space
(Ports, Timers, Configuration Registers, etc.).
Clears a specified bit in an I/O Register. This instruction operates on the lower 32
I/O Registers – addresses 0-31.
Clears the specified bits in register Rd. Performs the logical AND between the
contents of register Rd and the complement of the constant mask K.The result will be placed in register Rd.
Sets a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31.
Sets specified bits in register Rd. Performs the logical ORI between the contents of register Rd and a constant mask K and places the result in the destination register Rd.
This instruction tests a single bit in an I/O Register and skips the next instruction
if the bit is cleared. This instruction operates on the lower 32
I/O Registers – addresses 0-31.
This instruction tests a single bit in a register and skips the next instruction if
the bit is cleared.
This instruction tests a single bit in an I/O Register and skips the next instruction
if the bit is set. This instruction operates on the lower 32
I/O Registers – addresses 0-31.
This instruction tests a single bit in a register and skips the next instruction if the bit is set.
Relative jump to an address within PC - 2K +1 and PC + 2K (words). For AVR microcontrollers with Program memory not exceeding 4K words (8K bytes), this instruction can address the entire memory from every address location.
Returns from the subroutine. The return address is loaded from the STACK. The Stack Pointer uses a pre-increment scheme during RET.
; - A semicolon is used to comment in the assembly language however Arduino IDE supports "//" too.
So that's sufficient for now, we will explore more in the upcoming projects.
So let's get started.
Assembly Programming:Problem statement: "There are two LEDs, one connected to PB2 and the other to PB3. A push-button is connected to PB4. The task is to write an assembly code such that when the push button is not pressed, the LED connected to PB2 glows and the LED connected to PB3 does not glow. When the push button is pressed, the LED connected to PB3 glows and the LED connected to PB2 does not glow."
I used a common cathode RGB LED for ease. The pinout is as follows:
First of all, we need to assign the direction of the ports, i.e, whether they are going to be used as INPUT or OUTPUT. So, PB2 and PB3 have to be configured as O/P and PB4 has to be configured as I/P.
The Data Direction Register (DDRx) is used to specify whether that pin is going to be an I/P or an O/P.
This can be done in two ways.
Method 1:
LDI R16, 0xEF ; 0x is to indicate that the following number is in Hexa
OUT DDRB, R16 ; Set the DDR Register
In AVR Assembly, 0 in a data direction register specifies that it's an I/P and 1 specifies that it's an O/P.
EF in hexadecimal is 1110 1111 in binary. Which corresponds to assigning
So now PB4 is assigned as I/P and all other pins as O/P
The statement LDI R16, $EF -> means to load the value EF into the register R16 and the statement OUT DDRB, R16 -> means to assign the respective direction bits that specify the I/P and O/P.
Method 2:
SBI DDRB, 2 ; Set PB2 as Output
SBI DDRB, 3 ; Set PB3 as Output
CBI DDRB, 4 ; Set PB4 as Input
The above code does the following changes in the Data Direction Register:
The only change is that the bits other than 2, 3, and 4 are not defined
Enable Pull-Up Resistor:
SBI PORTB, 4 ; Enable pull-up resistor
It's important to do so because when the push-button is not pressed, the input pin of the MCU will be left hanging which means it's in the high-impedance state.
Now, let's check the state of the button and determine the state of the LEDs. Since we have pulled-up the input, we need to connect the other end of the switch to a logic HIGH (VCC)
L2: SBIS PINB, 4 ; Skips below statement if Push-button is not pressed
RJMP L1
SBI PORTB, 2 ; Turn ON LED -> PB2 if not pressed
CBI PORTB, 3 ; Turn OFF LED -> PB3 if not pressed
SBIC PINB, 4 ; Skips below statement if Push-button is pressed
RJMP L2
L1: SBI PORTB, 3 ; Turn ON LED -> PB3 if pressed
CBI PORTB, 2 ; Turn OFF LED -> PB2 if pressed
RET
Working:
After jumping to SBI PORTB, 2 the consecutive statements are executed until the next jump at RJMP L2.
RET returns to the void loop ( ) of the main program and hence this code will start from the beginning.
The e-C way: (C code)void setup()
{
// put your setup code here, to run once:
pinMode (10, OUTPUT); // GPIO 10 as Output
pinMode (11, OUTPUT); // GPIO 11 as Output
pinMode (12, INPUT); // GPIO 12 as Input
pinMode (12, INPUT_PULLUP); // Enable pull-up
}
void loop()
{
// put your main code here, to run repeatedly:
if ( digitalRead(12) == LOW ) // Read the state of button
{ // Execute this if button-pressed
digitalWrite (10, LOW); // LED -> PB2 OFF
digitalWrite (11, HIGH); // LED -> PB3 ON
}
else
{ // Execute this if button not pressed
digitalWrite (10, HIGH); // LED -> PB2 ON
digitalWrite (11, LOW); // LED -> PB3 OFF
}
}
Upload your code:There have to be two files to code in assembly language in the Arduino IDE. One.ino file to provide the basic info to the IDE to use the assembler and one.s file which contains the assembly code.
Please note that the .ino file and the .s file have to be inside the same folder with the same name.
Hit compile and then hit upload.
Congratulations! 🎉
You have successfully uploaded the assembly code into your Arduino Uno!
Final Result:
Comments