You are on page 1of 10

1 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

Command Line Assembly Language


Programming for Arduino Tutorial 2
by 1o_o7[1]

[2]

This tutorial is a continuation of "Command Line Assembly Language Programming for


Arduino Tutorial 1"

6/27/2015 11:33 PM

2 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

If you haven't gone through Tutorial 1 you should stop now and do that one rst.
In this tutorial we will continue our study of assembly language programming of the
atmega328p used in Arduino's.
You will need:
1. a breadboard Arduino or just a normal Arduino as in Tutorial 1
2. an LED
3. a 220 ohm resistor
4. a push button
5. connecting wires for making the circuit on your breadboard
6. Instuction Set Manual: www.atmel.com/images/atmel-0856-avr-instruction-s...[3]
7. Datasheet: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco...[4]

Step 1: Building the circuit

6/27/2015 11:33 PM

3 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

[5]

First you need to construct the circuit that we will be studying in this tutorial.
Here is the way it is connected:
PB0 (digital pin 8) ---> LED ---> R (220 ohm) ---> 5V
PD0 (digital pin 0) ---> pushbutton ---> GND
You can check that your LED is oriented properly by connecting it to GND instead of PB0. If
nothing happens then reverse the orientation and the light should come on. Then reconnect
it to PB0 and continue. The picture shows how my breadboard arduino is connected.

Step 2: Writing the assembly code

6/27/2015 11:33 PM

4 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

[6]

Write the following code in a text le called pushbutton.asm and compile it with avra as you
did in Tutorial 1.
Notice that in this code we have plenty of comments. Every time the assembler sees a
semicolon it will skip the rest of the line and go on to the next line. It is good programming
practice (especially in assembly language!) to heavily comment your code so that when you
return to it in the future you will know what you were doing. I am going to comment things
quite a lot in the rst few tutorials so that we know exactly what is going on and why. Later
on, once we become a bit better at assembly coding I will comment things in a bit less detail.
;************************************
; written by: 1o_o7
; date: <2014|10|23>
; version: 1.0
; file saved as: pushbutton.asm
; for AVR: atmega328p
; clock frequency: 16MHz
;************************************
; Program function:-----------------------------; Turns on an led connected to PB0 (digital 0)
; when you push a button connected to PD0
;----------------------------------------------;
;

PB0 (normally 0V) -----> LED --> 220 Ohm ---> 5V

;
;

PD0 (normally 5V) -----> Button ---> GND

;
.nolist
.include "./m328Pdef.inc"

6/27/2015 11:33 PM

5 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

.list
;==============
; Declarations
.def

temp

=r16

; designate working register r16 as temp

;=================
; Start of Program
rjmp

Init

; first line executed

;============
Init:
ser

temp

; set all bits in temp to 1's.

out

DDRB,temp

; setting a bit as 1 on the Data Direction I/O


;

register for PortB, which is DDRB, sets that

pin as output, a 0 would set that pin as input

so here, all PortB pins are outputs (set to 1)

ldi temp,0b11111110 ; load the `immediate' number to the temp register

out

DDRD,temp

if it were just ld then the second argument

would have to be a memory location instead

; mv temp to DDRD, result is that PD0 is input


;

and the rest are outputs

clr

temp

; all bits in temp are set to 0's

out

PortB,temp

; set all the bits (i.e. pins) in PortB to 0V

ldi temp,0b00000001 ; load immediate number to temp


out

PortD,temp

; move temp to PortD. PD0 has a pull up resistor


;

(i.e. set to 5V) since it has a 1 in that bit

the rest are 0V since 0's.

;======================
; Main body of program:
Main:
in

out

temp,PinD

PortB,temp

; PinD holds the state of PortD, copy this to temp


;

if the button is connected to PD0 this will be

0 when the button is pushed, 1 otherwise since

PD0 has a pull up resistor it's normally at 5V

; sends the 0's and 1's read above to PortB


;

this means we want the LED connected to PB0,

when PD0 is LOW, it sets PB0 to LOW and turn

on the LED (since the other side of the LED is

connected to 5V and this will set PB0 to 0V so

6/27/2015 11:33 PM

6 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

;
rjmp

Main

current will flow)

; loops back to the start of Main

Notice that this time we not only have many more comments in our code, but we also have a
header section which gives some information about who wrote it, when it was written, what
type of controller it was written for, and I have even included a simple circuit diagram to
show how you construct the circuit. The rest of the code is also separated into sections.
After you have compiled the above code you should load it onto the microcontroller and see
that it works. The LED should turn on while you are pushing the button and then turn off
again when you let go. I have shown what it looks like in the picture.

Step 3: Line-by-line analysis of the code


I will skip the lines that are merely comments as their purpose is self-evident.
.nolist
.include "./m328Pdef.inc"
.list

These three lines include the le containing the Register and Bit de nitions for the
ATmega328P that we are programming. The .nolist command tells the assembler not to
include this le in the pushbutton.lst le that it produces when you assemble it. It turns off
the listing option. After including the le we turn the listing option back on with the .list
command. The reason we do this is because the m328Pdef.inc le is quite long and we don't
really need to see it in the list le. Our assembler, avra, doesn't automatically generate a list
le and if we would like one we would assemble using the following command:
avra -l pushbutton.lst pushbutton.asm

If you do this it will generate a le called pushbutton.lst and if you examine this le you will
nd that it shows your program code along with extra information. If you look at the extra
information you will see that the lines begin with a C: followed by the relative address in hex
of where the code is placed in memory. Essentially it begins at 000000 with the rst
command and increases from there with each subsequent command. The second column
after the relative place in memory is the hex code for the command followed by the hex code
for the argument of the command. We will discuss list les further in future tutorials.
.def

temp

= r16 ; designate working register r16 as temp

In this line we use the assembler directive ".def" to de ne the variable "temp" as equal to the
r16 "working register." We will use register r16 as the one which stores the numbers that we
want to copy to various ports and registers (which can't be written to directly).

6/27/2015 11:33 PM

7 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

Exercise 1: Try to copy a binary number directly into a port or special register
like DDRB and see what happens when you try to assemble the code.
A register contains a byte (8 bits) of information. Essentially it is usually a collection of
SR-Latches each one is a "bit" and contains a 1 or a 0. We may discuss this (and even build
one!) later on in this series. You may be wondering what is a "working register" and why we
chose r16. We will discuss that in a future tutorial when we dive down into the quagmire of
the internals of the chip. For now I want you to understand how to do things like write code
and program physical hardware. Then you will have a frame of reference from that
experience which will make the memory and register properties of the microcontroller easier
to understand. I realize that most introductory textbooks and discussions do this the other
way around but I have found that playing a video game for a while rst and dicking around to
get a global perspective and then reading the instruction manual to get better at it is much
easier than reading the manual rst.
rjmp

Init

; first line executed

This line is a "relative jump" to the label "Init" and is not really necessary here since the next
command is already in Init but we include it for future use.
Init:
ser

temp

; set all bits in temp to 1's.

After the Init label we execute a "set register" command. This sets all of the 8 bits in the
register "temp" (which you recall is r16) to 1's. So temp now contains 0b11111111.
out

DDRB,temp ; setting a bit as 1 on the Data Direction I/O register


;

for PortB, which is DDRB, sets that pin as output

a 0 would set that pin as input

so here, all PortB pins are outputs (set to 1)

The register DDRB (Data Direction Register for PortB) tells which pins on PortB (i.e. PB0
through PB7) are designated as input and which are designated as output. Since we have the
pin PB0 connected to our LED and the rest not connected to anything we will set all the bits
to 1 meaning they are all outputs.
ldi temp,0b11111110

; load the `immediate' number to the temp register


;

if it were just ld then the second argument would

have to be a memory location

This line loads the binary number 0b11111110 into the temp register.
out

DDRD,temp

; mv temp to DDRD, result is that PD0 is input and


;

the rest are outputs

6/27/2015 11:33 PM

8 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

Now we set the Data Direction Register for PortD from temp, since temp still contains
0b11111110 we see that PD0 will be designated as an input pin (since there is a 0 in the far
right spot) and the rest are designated as outputs since there are 1's in those spots.
clr

temp

; all bits in temp are set to 0's

out

PortB,temp

; set all the bits (i.e. pins) in PortB to 0V

First we "clear" the register temp which means setting all of the bits to zero. Then we copy
that to the PortB register which sets 0V on all of those pins. A zero on a PortB bit means that
the processor will keep that pin at 0V, a one on a bit will cause that pin to be set to 5V.
Exercise 2: Use a multimeter to check if all of the pins on PortB are actually zero.
Is something weird going on with PB1? Any idea why that might be? (similar to
Exercise 4 below then follow the code...)
Exercise 3: Remove the above two lines from your code. Does the program still run
correctly? Why?
ldi temp,0b00000001

; load immediate number to temp

out

; move temp to PortD. PD0 is at 5V (has a pullup resistor)

PortD,temp

since it has a 1 in that bit the rest are 0V.

Exercise 4: Remove the above two lines from your code. Does the program still run
correctly? Why? (This is different from Exercise 3 above. See the pin out diagram.
What is the default DDRD setting for PD0? (See page 90 of the data sheet)
First we "load immediate" the number 0b00000001 to temp. The "immediate" part is there
since we are loading a straight up number to temp rather than a pointer to a memory
location containing the number to load. In that case we would simply use "ld" rather than
"ldi". Then we send this number to PortD which sets PD0 to 5V and the rest to 0V.
Now we have set the pins as input or output and we have set up their initial states as either
0V or 5V (LOW or HIGH) and so we now enter our program "loop".
Main:

in

temp,PinD

; PinD holds the state of PortD, copy this to temp


;

if the button is connected to PD0 then this will be

a 0 when the button is pushed, 1 otherwise since

PD0 has a pull up resistor it is normally at 5V

The register PinD contains the current state of the PortD pins. For example, if you attached a
5V wire to PD3, then at the next clock cycle (which happens 16 million times per second
since we have the microcontroller hooked up to a 16MHz clock signal) the PinD3 bit (from
the current state of PD3) would become a 1 instead of a 0. So in this line we copy the current
state of the pins to temp.

6/27/2015 11:33 PM

9 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

out PortB,temp

; sends the 0's and 1's read above to PortB


;

this means we want the LED connected to PB0, so

when PD0 is LOW, it will set PB0 to LOW and turn

on the LED (the other side of the LED is connected

to 5V and this will set PB0 to 0V so current flows)

Now we send the state of the pins in PinD to the PortB output. Effectively, this means that
PD0 will send a 1 to PortD0 unless the button is pressed. In that case since the button is
connected to ground that pin will be at 0V and it will send a 0 to PortB0. Now, if you look at
the circuit diagram, 0V on PB0 means the LED will glow since the other side of it is at 5V. If
we are not pressing the button, so that a 1 is sent to PB0, that would mean we have 5V on
PB0 and also 5V on the other side of the LED and so there is no potential difference and no
current will ow and so the LED will not glow (in this case it is an LED which is a diode and
so current only ows one direction regardless but whatever).
rjmp

Main

; loops back to Start

This relative jump loops us back to our Main: label and we check PinD again and so on.
Checking every 16 millionth's of a second whether the button is being pushed and setting
PB0 accordingly.
Exercise 5: Modify your code so that your LED is connected to PB3 instead of PB0
and see that it works.
Exercise 6: Plug your LED into GND instead of 5V and modify your code
accordingly.

Step 4: Conclusion
In this tutorial we have further investigated the assembly language for the ATmega328p and
learned how to control an LED with a pushbutton. In particular we learned the following
commands:
ser register sets all of the bits of a register to 1's
clr register sets all of the bits of a register to 0's
in register, i/o register copies the number from an i/o register to a working register
In the next tutorial we will examine the structure of the ATmega328p and the various
registers, operations, and resources contained therein.

6/27/2015 11:33 PM

10 of 10

http://www.instructables.com/id/Command-Line-Assembly-Language-Pro...

Before I continue with these tutorials I am going to wait and see the level of interest. If there
are a number of people that are actually enjoying learning how to code programs for this
microprocessor in assembly language then I will continue and construct more complicated
circuits and use more robust code.
1. http://www.instructables.com/member/1o_o7/
2. http://cdn.instructables.com/F4I/UT4Q/I1P33YSI/F4IUT4QI1P33YSI.LARGE.jpg
3. http://www.atmel.com/images/atmel-0856-avr-instruction-se...
4. http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A88PA-168A-168PA-328-328P_datasheet_Complete.pdf
5. http://cdn.instructables.com/FM0/0MXY/I1P33YQ7/FM00MXYI1P33YQ7.LARGE.jpg
6. http://cdn.instructables.com/F5T/QZGJ/I1P33YPQ/F5TQZGJI1P33YPQ.LARGE.jpg

6/27/2015 11:33 PM

You might also like