Highly recommended reading/reference:
MPASM Assembler Help, found at
Unlike a Windows C/C++ Hello World tutorial, we will not be printing output to the console. Instead we will connect an LED to an input/output pin on the microcontroller and create a simple assembly program to turn the LED on.I will try to avoid making real schematics until it becomes really necessary, so here is a picture of the setup:
GND — 1KOhm — LED — (20)
With the hardware done, it’s time to move on to the software.
- Open MPLAB
- Select Project/Project Wizard… Click Next
- Select your microcontroller (PIC18F4550). Click Next
- Choose Microchip MPASM Toolsuite. The locations should already be set up, but in case they aren’t, you can find the files in
:\Program Files\Microchip\MPASM Suite\. Click Next
- Click Browse… and select a directory and name for your project Tutorial2. For some reason, Microchip tools have some problem with long file paths, so you are limited to a maximum 62 character project path. A good directory might be
- Don’t add any files. Keep clicking Next, then click FinishYou should now see the project window titled Tutorial2.mcw. If you don’t, click View/Project. Similarly, click View/Output if you do not see the output window. Windows inside the IDE can be docked by right clicking the blue title bar, selecting Dockable and dragging the window to an edge of the IDE. Click File/New to open a new editor window. Rearrage your windows to your liking.
Mine looks like this:
at the top of the text file. Wow! Your first line of code. Better save! Click File/Save As…, find the project directory and save file as tutorial2.asm. Note: You need to make sure that the file saves with the .asm extension by typing it yourself.
To add the file into your project, right click Source Files and click Add Files…. Select tutorial2.asm and click Open.
It may also be helpful to add the include file into the project for reference. Right click Header Files and click Add Files…. Cruise to
Open the include file by double clicking on it. Note the comment (comments are marked by semicolons) toward the top:
; This header file defines configurations, registers, and other useful; bits of information for the PIC18F4550 microcontroller. These names ; are taken to match the data sheets as closely as possible.
Unfortunately, this means that you will have to become friends with the datasheet. Anytime you wish to use a peripheral, you need to consult the datasheet to find out which file registers perform the task you need. Then, confirm in the include file that the register names are consistent by searching for them.
Back to the tutorial2.asm..
Before any real coding gets done, the configuration bits (described in the datasheet – Section 25.1) must be set. These bits configure various aspects of the microcontroller’s operation that must be set before any code actually runs. Some recommend setting all of the configuration bits to make sure that everything is correct, but we will not be doing that at this point. Instead, we will set a few important bits that will allow our program to run:
CONFIG WDT=OFF; disable watchdog timer CONFIG MCLRE = ON; MCLEAR Pin on CONFIG DEBUG = ON; Enable Debug Mode CONFIG LVP = OFF; Low-Voltage programming disabled (necessary for debugging) CONFIG FOSC = INTOSCIO_EC;Internal oscillator, port function on RA6
The watchdog timer is a failsafe mechanism that resets the microcontroller in case there is a problem in the code. This may receive a tutorial later on. It’s mainly useful for commercial applications and will only be a hindrance in this tutorial. Therefore it will be turned off.
The MCLEAR pin (1) needs to be enabled to be able to use the debugging features (which we will be using shortly).
The DEBUG bit dedicates RB6 (39) and RB7 (40) to the debugger, instead of leaving them as I/O pins.
LVP will be disabled if you are programming with the PicKit 2 since it uses high voltage programming.
Last, but not least (the least least, actually) is the oscillator setup. We will use the internal oscillator. This means that the clock signal for the microcontroller will be generated inside the PIC. However, the default setting is an external oscillator (meaning that it will expect a clock signal on one of the pins), meaning that this must be set, or this tutorial will not work.
org 0; start code at 0
According to the MPASM Help (referenced above), the org directive allows the user to :
Set the program origin for subsequent code at the address defined in expr (0 in this case). If no org is specified, code generation will begin at address zero.For PIC18 devices, only even-numbered expr values are allowed.
This means that org dictates where in the microcontroller’s memory to place the data following it. Even though the default behavior is to start the code at memory location 0, it is a good idea to have this directive to mark the start of the code.
Now, the real code begins. A brief explanation of what this program does might help make the code easier to understand. First, the variables are declared and set to 0. Then, a pin is set up to output a value to turn the LED on and off. We will be using PORT D, PIN 1 (20). Note that this is the second pin on PORT D (after pin 0). I chose this port/pin for two reasons. First, it is at the end of the chip, making it easy to access. Second, PORT D is the only port that does not have some non-digital-I/O action using some of its pins by default, making it easiest to set up. Once the port is set up correctly, PIN 1 (20) is toggled. Then, a delay is necessary as the PIC runs at a default speed of 1Mhz (blinking far too fast to see). After the delay loop, the code goes back and toggles the pin. This cycle continues indefinitely.
Delay1 res 1 ;reserve 1 byte for the variable Delay1 Delay2 res 1 ;reserve 1 byte for the variable Delay2
The res directive reserves memory for variables.
This is a good time to mention that there are 3 types of “words” that you can use in assembler:
Directives/Instructions (blue): Must be preceeded with a tab or space
Labels (purple): Variable names are considered labels. Should start at the beginning of a line
Literals (black): Numbers and strings are literals, meaning that they do not have symbolic meaning other than the number/letter sequence they represent. These usually follow some instruction
Start: CLRF PORTD CLRF TRISD CLRF Delay1 CLRF Delay2
The label Start, followed by a colon represents a point in the code that can be returned to using the goto/call instructions. A goto instruction simply moves program flow to a specified address or label. The call instruction will be covered later, but it performs a similar action to calling a C function (which returns to the same point once it is finished).
PORT D can be accessed in two different ways. The PORTD register allows the port values to be written. However, it may be useful to read back an output value set on a certain pin. A latch attached to each PORT D pin allows this value to be stored. LATD is the register that allows access to the pin latches. A write to PORTD and LATD has the same result. Only a LATD read, however, will provide the correct output value of a pin. CLRF is an instruction that clears the file register (F) supplied. In this case, the PORTD register is cleared. According to the datasheet, this initializes PORTD by clearing the data latches. Next, the data direction must be set. PORTD pins can function either as digital inputs or digital outputs. In this case we want outputs, to control the LED. The register TRISD controls the direction of the port. A good way to remember how to set the direction is that in TRISD 0s are Outputs and 1s are Inputs. Therefore, we clear TRISD to set the whole port to output. Note: TRISD bits control the same pins as the PORTD bits. For example, PORT D PIN 1 is set to input or output by the second bit in TRISD and written to by the second bit in PORTD.
The Delay variables are also set to 0.
MainLoop: BTG PORTD,RD1 ;Toggle PORT D PIN 1 (20) Delay: DECFSZ Delay1,1 ;Decrement Delay1 by 1, skip next instruction if Delay1 is 0 GOTO Delay DECFSZ Delay2,1 GOTO Delay GOTO MainLoop end
In the main loop, PORT D PIN 1 is toggled, followed by a delay loop.
(The delay algorithm has been taken from the example code in the MicroChip 16F 44-Pin Demo Board User Guide). The decfsz instruction subtracts the requested amount (second argument) from the file register (F) provided (first argument) and then checks the value of that register. If it is 0, the following instruction is ignored. This delay loop is actually a nested loop. Since Delay1 was 0 at the start, decrementing 1 from this 8 bit register turns it into 255. The goto instruction then moves the program flow back to the decfsz instruction. This continues until Delay1 reaches 1. When decfsz runs again, Delay1 becomes 0. As promised, the following goto instruction is skipped so the second decfsz instruction is run, subtracting 1 from Delay 2. Delay 2 was also 0 and becomes 255. The following goto instruction brings it back to the FIRST decfsz instruction, causing Delay1 to be decremented another 255 times before decrementing another 1 from Delay2. To quantify the delay, a reference from the MicroChip 16F 44-Pin Demo Board User Guide: Each loop takes 3 instruction times; one for the decrement and two for the GOTO and the counter will force it to go around 256 times, which takes it a total of 768 instruction times (768 µs) to execute. The inner loop (Delay1) takes 768 µs plus 3 for the outer loop(Delay2), but now it’s executed another 256 times, (768 + 3) * 256 = 197376 µs = 0.197s.
Once the delay code is finished (the second goto is skipped because Delay2 turns to 0), the goto MainLoop instruction is executed and the cycle begins again. The end directive is also present, as it must be in every assembly program. However, it should never be reached.
The program is now complete. Click Project/Build All to build it. You should see BUILD SUCCEEDED in the build tab in the output window. Then, click Programmer/Select Programmer and choose PicKit2. You should see
Found PICkit 2 - Operating System Version 2.20.0 Target power detected ( 5.00V) PIC18F4550 found (a3) PICkit 2 Ready
in the PicKit2 tab in the output window.
Click Programmer/Program to program your PIC.
Click Programmer/Release from Reset to run your program.