When an 8051 is first initialized, it resets the PC to 0000h. The 8051 then begins to
execute instructions sequentially in memory unless a program instruction causes the PC
to be otherwise altered. There are various instructions that can modify the value of
the PC; specifically, conditional branching instructions, direct jumps and calls, and
"returns" from subroutines. Additionally, interrupts, when enabled, can cause the
program flow to deviate from its otherwise sequential scheme.
The 8051 contains a suite of instructions which, as a group, are referred to as
"conditional branching" instructions. These instructions cause program execution to
follow a non-sequential path if a certain condition is true.
Take, for example, the JB instruction. This instruction means "Jump if Bit Set." An
example of the JB instruction might be:
In this case, the 8051 will analyze the contents of bit 45h. If the bit is set program
execution will jump immediately to the label HELLO, skipping the NOP instruction. If
the bit is not set the conditional branch fails and program execution continues, as
usual, with the NOP instruction which follows.
Conditional branching is really the fundamental building block of program logic since
all "decisions" are accomplished by using conditional branching. Conditional branching
can be thought of as the "IF...THEN" structure in 8051 assembly language.
An important note worth mentioning about conditional branching is that the program may
only branch to instructions located withim 128 bytes prior to or 127 bytes following
the address which follows the conditional branch instruction. This means that in the
above example the label HELLO must be within +/- 128 bytes of the memory address which
contains the conditional branching instruction.
While conditional branching is extremely important, it is often necessary to make a
direct branch to a given memory location without basing it on a given logical decision.
This is equivalent to saying "Goto" in BASIC. In this case you want the program flow
to continue at a given memory address without considering any conditions.
This is accomplished in the 8051 using "Direct Jump and Call" instructions. As
illustrated in the last paragraph, this suite of instructions causes program flow to
Consider the example:
The LJMP instruction in this example means "Long Jump." When the 8051 executes this
instruction the PC is loaded with the address of NEW_ADDRESS and program execution
continues sequentially from there.
The obvious difference between the Direct Jump and Call instructions and the conditional
branching is that with Direct Jumps and Calls program flow always changes. With
conditional branching program flow only changes if a certain condition is true.
It is worth mentioning that, aside from LJMP, there are two other instructions which
cause a direct jump to occur: the SJMP and AJMP commands. Functionally, these two
commands perform the exact same function as the LJMP command--that is to say, they always
cause program flow to continue at the address indicated by the command. However, SJMP
and AJMP differ in the following ways:
- The SJMP command, like the conditional branching instructions, can only jump to an
address within +/- 128 bytes of the SJMP command.
- The AJMP command can only jump to an address that is in the same 2k block of memory
as the AJMP command. That is to say, if the AJMP command is at code memory location
650h, it can only do a jump to addresses 0000h through 07FFh (0 through 2047, decimal).
You may be asking yourself, "Why would I want to use the SJMP or AJMP command which
have restrictions as to how far they can jump if they do the same thing as the LJMP
command which can jump anywhere in memory?" The answer is simple: The LJMP command
requires three bytes of code memory whereas both the SJMP and AJMP commands require
only two. Thus, if you are developing an application that has memory restrictions
you can often save quite a bit of memory using the 2-byte AJMP/SJMP instructions
instead of the 3-byte instruction.
Recently, I wrote a program that required 2100 bytes of memory but I had a memory
restriction of 2k (2048 bytes). I did a search/replace changing all LJMPs to AJMPs
and the program shrunk downto 1950 bytes. Thus, without changing any logic whatsoever
in my program I saved 150 bytes and was able to meet my 2048 byte memory restriction.
NOTE: Some quality assemblers will actually do the above conversion for you
automatically. That is, they'll automatically change your LJMPs to SJMPs whenever
possible. This is a nifty and very powerful capability that you may want to look
for in an assembler if you plan to develop many projects that have relatively tight
Another operation that will be familiar to seasoned programmers is the LCALL instruction.
This is similar to a "Gosub" command in Basic.
When the 8051 executes an LCALL instruction it immediately pushes the current Program
Counter onto the stack and then continues executing code at the address indicated by
the LCALL instruction.
Returns from Routines
Another structure that can cause program flow to change is the "Return from Subroutine"
instruction, known as RET in 8051 Assembly Language.
The RET instruction, when executed, returns to the address following the instruction that
called the given subroutine. More accurately, it returns to the address that is stored
on the stack.
The RET command is direct in the sense that it always changes program flow without basing
it on a condition, but is variable in the sense that where program flow continues can
be different each time the RET instruction is executed depending on from where the
subroutine was called originally.
An interrupt is a special feature which allows the 8051 to provide the illusion of
"multi-tasking," although in reality the 8051 is only doing one thing at a time. The
word "interrupt" can often be subsituted with the word "event."
An interrupt is triggered whenever a corresponding event occurs. When the event occurs,
the 8051 temporarily puts "on hold" the normal execution of the program and executes a
special section of code referred to as an interrupt handler. The interrupt handler
performs whatever special functions are required to handle the event and then returns
control to the 8051 at which point program execution continues as if it had never been
The topic of interrupts is somewhat tricky and very important. For that reason, an
entire chapter will be dedicated to the topic. For now, suffice it to say that
Interrupts can cause program flow to change.