Microcontroller reverse engineer
Microcontroller reverse engineer
Everything they make, We can break! 
  HOME COMPANY PCB COPY MCU HACK FAQ CONTACT US
Disassembler Software   
WHY US ?
World first mcu hack company
In business since 1998
Reversed tens of thousands of chips
Copied thousands of pcbs
Foreseen all pertential problems
Integrity with payments
crack ic
 
 
Architecture and programming of 8051 MCU's for reverse engineering

Chapter 5: Assembly Language

Introduction

It was time that hardware-oriented to the core made compromise if they wanted to stay “in the game”. Namely, unlike other circuits which only need to be connected to other components and powered in order to be of any use, microcontrollers require to be programmed as well. Fortunately, they still didn't progress so far in their evolution, so that all microcontroller families “understand” only one language - machine language. That's a good thing. The bad one is that, even primitive, this language of zeros and ones can only be understood by microcontrollers and some of the experts working on its development. In order to bridge this gap between machine and humans, the first high-level programming language called Assembly language was created.

The main problem of remembering codes recognized as instructions by electronics was solved therefore, but another one, equally complicated to both us and “them”(microcontrollers) arose. This problem was also easily solved by means of the program for a PC called assembler and a simple device called programmer.

This program enables the PC to receive commands in the form of abbreviations and convert them unerringly into so called “executable file”. The moment of compiling a program into machine language is crucial as this file, called HEX file, represents a series of binary numbers understandable to microcontrollers only. The program written in assembly language cannot be executed practically unless this file is loaded into the microcontroller memory. This is the moment when the last link in the chain - the programmer - appears on the scene. It is a small device connected to a PC via some of the ports and has a socket for placing chip in.

5.1 Elements of Assembly Language

Assembly language is basically like any other language, which means that it has its words, rules and syntax. The basic elements of assembly language are:

  • Labels;
  • Orders;
  • Directives; and
  • Comments.
Elements of Assembler

Syntax of Assembly language

When writing a program in assembly language it is necessary to observe specific rules in order to enable the process of compiling into executable “HEX-code” to run without errors. These compulsory rules are called syntax and there are only several of them:

  • Every program line may consist of a maximum of 255 characters;
  • Every program line to be compiled, must start with a symbol, label, mnemonics or directive;
  • Text following the mark “;” in a program line represents a comment ignored (not compiled) by the assembler; and
  • All the elements of one program line (labels, instructions etc.) must be separated by at least one space character. For the sake of better clearness, a push button TAB on a keyboard is commonly used instead of it, so that it is easy to delimit columns with labels, directives etc. in a program.

Numbers

If octal number system, otherwise considered as obsolite, is disregarded, assembly laguage allows numbers to be used in one out of three number systems:

Decimal Numbers

If not stated otherwise, the assembly language considers all the numbers as decimal. All ten digits are used (0,1,2,3,4,5,6,7,8,9). Since at most 2 bytes are used for saving them in the microcontroller, the largest decimal number that can be written in assembly language is 65535. If it is necessary to specify that some of the numbers is in decimal format, then it has to be followed by the letter “D”. For example 1234D.

Hexadecimal Numbers

Hexadecimal numbers are commonly used in programming. There are 16 digits in hexadecimal number system (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F). The largest hexadecimal number that can be written in assembly language is FFFF. It corresponds to decimal number 65535. In order to distinguish hexadecimal numbers from decimal, they are followed by the letter “h”(either in upper- or lowercase). For example 54h.

Binary Numbers

Binary numbers are often used when the value of each individual bit of some of the registers is important, since each binary digit represents one bit. There are only two digits in use (0 and 1). The largest binary number written in assembly language is 1111111111111111. In order to distinguish binary numbers from other numbers, they are followed by the letter “b” (either in upper- or lowercase). For example 01100101B.

Operators

Some of the assembly-used commands use logical and mathematical expessions instead of symbols having specific values. For example:

IF (VERSION>1)
   LCALL Table_2
   USING VERSION+1
ENDIF
   ...

As seen, the assembly language is capable of computing some values and including them in a program code, thus using the following mathematical and logical operations:

Name Operation Example Result
+ Addition 10+5 15
- Subtraction 25-17 8
* Multiplication 7*4 28
/ Division (with no remainder) 7/4 1
MOD Remainder of division 7 MOD 4 3
SHR Shift register bits to the right 1000B SHR 2 0010B
SHL Shift register bits to the left 1010B SHL 2 101000B
NOT Negation (first complement of number) NOT 1 1111111111111110B
AND Logical AND 1101B AND 0101B 0101B
OR Logical OR 1101B OR 0101B 1101B
XOR Exclusive OR 1101B XOR 0101B 1000B
LOW 8 low significant bits LOW(0AADDH) 0DDH
HIGH 8 high significant bits HIGH(0AADDH) 0AAH
EQ, = Equal 7 EQ 4 or 7=4 0 (false)
NE,<> Not equal 7 NE 4 or 7<>4 0FFFFH (true)
GT, > Greater than 7 GT 4 or 7>4 0FFFFH (true)
GE, >= Greater or equal 7 GE 4 or 7>=4 0FFFFH (true)
LT, < Less than 7 LT 4 or 7<4 0 (false)
LE,<= Less or equal 7 LE 4 or 7<=4 0 (false)

Symbols

Every register, constant, address or subroutine can be assigned a specific symbol in assembly language, which considerably facilitates the process of writing a program. For example, if the P0.3 input pin is connected to a push button used to stop some process manually (push button STOP), the process of writing a program will be much simpler if the P0.3 bit is assigned the same name as the push button, i.e. “pushbutton_STOP”. Of course, like in any other language, there are specific rules to be observed as well:

  • For the purpose of writing symbols in assembly language, all letters from alphabet (A-Z, a-z), decimal numbers (0-9) and two special characters ("?" and "_") can be used. Assembly language is not case sensitive.

For example, the following symbols will be considered identical:

Serial_Port_Buffer
SERIAL_PORT_BUFFER
  • In order to distinguish symbols from constants (numbers), every symbol starts with a letter or one of two special characters (? or _).
  • The symbol may consist of maximum of 255 characters, but only first 32 are taken into account. In the following example, the first two symbols will be considered duplicate (error), while the third and forth symbols will be considered different:
START_ADDRESS_OF_TABLE_AND_CONSTANTS_1
START_ADDRESS_OF_TABLE_AND_CONSTANTS_2
TABLE_OF_CONSTANTS_1_START_ADDRESS
TABLE_OF_CONSTANTC_2_START_ADDRESS
  • Some of the symbols cannot be used when writing a program in assembly language because they are already part of instructions or assembly directives. Thus, for example, a register or subroutine cannot be assigned name “A” or “DPTR” because there are registers having the same name.

Here is a list of symbols not allowed to be used during programming in assembly language:

A AB ACALL ADD
ADDC AJMP AND ANL
AR0 AR1 AR2 AR3
AR4 AR5 AR6 AR7
BIT BSEG C CALL
CJNE CLR CODE CPL
CSEG DA DATA DB
DBIT DEC DIV DJNZ
DPTR DS DSEG DW
END EQ EQU GE
GT HIGH IDATA INC
ISEG JB JBC JC
JMP JNB JNC JNZ
JZ LCALL LE LJMP
LOW LT MOD MOV
MOVC MOVX MUL NE
NOP NOT OR ORG
ORL PC POP PUSH
R0 R1 R2 R3
R4 R5 R6 R7
RET RETI RL RLC
RR RRC SET SETB
SHL SHR SJMP SUBB
SWAP USING XCH XCHD
XDATA XOR XRL XSEG

Labels

A label is a special type of symbols used to represent a textual version of an address in ROM or RAM memory. They are always placed at the beginning of a program line. It is very complicated to call a subroutine or execute some of the jump or branch instructions without them. They are easily used:

  • A symbol (label) with some easily recognizable name should be written at the beginning of a program line from which a subroutine starts or where jump should be executed.
  • It is sufficient to enter the name of label instead of address in the form of 16-bit number in instructions calling a subroutine or jump.

During the process of compiling, the assembler automatically replaces such symbols with appropriate addresses.

Directives

Unlike instructions being compiled and written to chip program memory, directives are commands of assembly language itself and have no influence on the operation of the microcontroller. Some of them are obligatory part of every program while some are used only to facilitate or speed up the operation.
Directives are written in the column reserved for instructions. There is a rule allowing only one directive per program line.

EQU directive

The EQU directive is used to replace a number by a symbol. For example:

MAXIMUM EQU 99

After using this directive, every appearance of the label “MAXIMUM” in the program will be interpreted by the assembler as the number 99 (MAXIMUM = 99). Symbols may be defined this way only once in the program. The EQU directive is mostly used at the beginning of the program therefore.

SET directive

The SET directive is also used to replace a number by a symbol. The significant difference compared to the EQU directive is that the SET directive can be used an unlimited number of times:

SPEED SET 45
SPEED SET 46
SPEED SET 57

BIT directive

The BIT directive is used to replace a bit address by a symbol. The bit address must be in the range of 0 to 255. For example:

TRANSMIT BIT PSW.7 ;Transmit bit (the seventh bit in PSW register) 
                   ;is assigned the name "TRANSMIT"
OUTPUT BIT 6 ;Bit at address 06 is assigned the name "OUTPUT"
RELAY BIT 81 ;Bit at address 81 (Port 0)is assigned the name ;"RELAY"

CODE directive

The CODE directive is used to assign a symbol to a program memory address. Since the maximum capacity of program memory is 64K, the address must be in the range of 0 to 65535. For example:

RESET CODE 0 ;Memory location 00h called "RESET"
TABLE CODE 1024 ;Memory location 1024h called "TABLE"

DATA directive

The DATA directive is used to assign a symbol to an address within internal RAM. The address must be in the range of 0 to 255. It is possible to change or assign a new name to any register. For example:

TEMP12 DATA 32 ;Register at address 32 is named ;as "TEMP12"
STATUS_R DATA D0h ;PSW register is assigned the name ;"STATUS_R"

IDATA directive

The IDATA directive is used to change or assign a new name to an indirectly addressed register. For example:

TEMP22 IDATA 32 ;Register whose address is in register ;at address 32 is named as "TEMP22"
TEMP33 IDATA T_ADR ;Register whose address is in ;register T_ADR is named as "TEMP33"

XDATA directive

The XDATA directive is used to assign a name to registers within external (additional) RAM memory. The addresses of these registers cannot be larger than 65535. For example:

TABLE_1 XDATA 2048 ;Register stored in external
                   ;memory at address 2048 is named
                   ;as "TABLE_1"

ORG directive

The ORG directive is used to specify a location in program memory where the program following directive is to be placed. For example:

BEGINNING ORG 100
          ...
          ...
          ORG 1000h
TABLE     ...
          ...

This program starts at location 100. The table containing data is to be stored at location 1024 (1000h).

USING directive

The USING directive is used to define which register bank (registers R0-R7) is to be used in the program.

USING 0 ;Bank 0 is used (registers R0-R7 at RAM-addresses 0-7)
USING 1 ;Bank 1 is used (registers R0-R7 at RAM-addresses 8-15)
USING 2 ,Bank 2 is used (registers R0-R7 at RAM-addresses 16-23)
USING 3 ;Bank 3 is used (registers R0-R7 at RAM-addresses 24-31)

END directive

The END directive is used at the end of every program. The assembler will stop compiling once the program encounters this directive. For example:

...
END ;End of program

Directives used for selecting memory segments

There are 5 directives used for selecting one out of five memory segments in the microcontroller:

CSEG ;Indicates that the next segment refers to program memory;
BSEG ;Selects bit-addressable part of RAM;
DSEG ;Indicates that the next segment refers to the part of internal RAM accessed by ;direct addressing;
ISEG ;Indicates that the next segment refers to the part of internal RAM accessed by ;indirect addressing using registers R0 and R1); and
XSEG ;Selects external RAM memory.

The CSEG segment is activated by default after enabling the assembler and remains active until a new directive is specified. Each of these memory segments has its internal address counter which is cleared every time the assembler is activated. Its value can be changed by specifying value after the mark AT. It can be a number, an arithmetical operation or a symbol. For example:

DSEG       ;Next segment refers to directly accessed registers; and
BSEG AT 32 ;Selects bit-addressable part of memory with address counter
           ;moved by 32 bit locations relative to the beginning of that
           ;memory segment.

A dollar symbol "$" denotes current value of address counter in the currently active segment. The following two examples illustrate how this value can be used practically:

Example 1:

JNB FLEG,$ ;Program will constantly execute this
           ;instruction (jump instruction),until
           ;the flag is cleared.

Example 2:

MESSAGE DB ‘ALARM turn off engine’
LENGTH EQU $-MESSAGE-1

These two program lines can be used for computing exact number of characters in the message “ALARM turn off engine” which is defined at the address assigned the name “MESSAGE”.

DS directive

The DS directive is used to reserve memory space expressed in bytes. It is used if some of the following segments ISEG, DSEG or XSEG is currently active. For example:

Example 1:

DSEG     ;Select directly addressed part of RAM 
DS 32         ;Current value of address counter is incremented by 32
SP_BUFF DS 16 ;Reserve space for serial port buffer
              ;(16 bytes)
IO_BUFF DS 8  ;Reserve space for I/O buffer in size of 8 bytes

Example 2:

ORG 100       ;Start at address 100
DS 8          ;8 bytes are reserved
LAB ......... ;Program proceeds with execution (address of this location is 108)

DBIT directive

The DBIT directive is used to reserve space within bit-addressable part of RAM. The memory size is expressed in bits. It can be used only if the BSEG segment is active. For example:

          BSEG ;Bit-addressable part of RAM is selected
IO_MAP DBIT 32 ;First 32 bits occupy space intended for I/O buffer

DB directive

The DB directive is used for writing specified value into program memory. If several values are specified, then they are separated by a comma. If ASCII array is specified, it should be enclosed within single quotation marks. This directive can be used only if the CSEG segment is active. For example:

CSEG
DB 22,33,’Alarm’,44

If this directive is preceeded by a lable, then the label will point to the first element of the array. It is the number 22 in this example.

DW directive

The DW directive is similar to the DB directive. It is used for writing a two-byte value into program memory. The higher byte is written first, then the lower one.

IF, ENDIF and ELSE directives

These directives are used to create so called conditional blocks in the program. Each of these blocks starts with directive IF and ends with directive ENDIF or ELSE. The statement or symbol (in parentheses) following the IF directive represents a condition which specifies the part of the program to be compiled:

  • If the statement is correct or if the symbol is equal to one, the program will include all instructions up to directive ELSE or ENDIF.
  • If the statement is not correct or if the symbol value is equal to zero, all instructions are ignored, i.e. not compiled, and the program continues with instructions following directives ELSE or ENDIF.

Example 1:

IF (VERSION>3)
   LCALL Table_2
   LCALL Addition
ENDIF
   ...

If the program is of later date than version 3 (statement is correct), subroutines “Table 2” and “Addition” will be executed. If the statement in parentheses is not correct (VERSION<3), two instructions calling subroutines will not be compiled.

Example 2:

If the value of the symbol called “Model” is equal to one, the first two instructions following directive IF will be compiled and the program continues with instructions following directive ENDIF (all instructions between ELSE and ENDIF are ignored). Otherwise, if Model=0, instructions between IF and ELSE are ignored and the assembler compiles only instructions following directive ELSE.

IF (Model)
   MOV R0,#BUFFER
   MOV A,@R0
ELSE
   MOV R0,#EXT_BUFFER
   MOVX A,@R0
ENDIF
   ...

Control directives

Control directives start with a dollar symbol $. They are used to determine which files are to be used by the assembler during compilation, where the executable file is to be stored as well as the final layout of the compiled program called Listing. There are many control directives, but only few of them is of importance:

\$INCLUDE directive

This directive enables the assembler to use data stored in other files during compilation. For example:

\$INCLUDE(TABLE.ASM)

\$MOD8253 directive

This $MOD8253 directive is a file containing names and addresses of all SFRs of 8253 microcontrollers. By means of this file and directive having the same name, the assembler can compile the program on the basis of register names. If they are not used, it is necessary to specify name and address of every SFRs to be used at the beginning of the program.

 

 

  • Mikatech STC 8051 MCU reverse engineer list:
  • STC89Cxx Series MCU copy protection attack: STC89C51RC STC89C52RC STC89C53RC STC89C54RD+ STC89C58RD+ STC89C516RD STC89C516RD+ STC89C58RD ...

    STC89LExx/LVxx Series MCU copy protection attack: STC89LE51RC STC89LE52RC STC89LE53RC STC89LE54RD+ STC89LE58RD+ STC89LE516RD+ STC89LE516AD STC89LE516X2 STC89LE52AD STC89LE54AD STC89LE556AD STC89LE556X2 STC89LE58AD STC89LV516RD STC89LV58RD ...

    STC90Cxx Series MCU copy protection attack: STC90C51RC STC90C52RC STC90C54RD STC90C58RD STC90C516RD ...

    STC10Fxx Series MCU copy protection read: STC10F04 STC10F04XE STC10F08 STC10F08XE STC10F12 STC10F12XE STC10F14X ...

    STC11Fxx Series MCU copy protection attack: STC11F01E STC11F02E STC11F03E STC11F04E STC11F05E IAP11F06 STC11F60XE STC11F56XE STC11F52XE STC11F48XE STC11F40XE STC11F32XE STC11F20XE STC11F16XE STC11F08XE STC11F62X ...

    STC12Cxx Series MCU copy protection attack: STC12C1052 STC12C2052 STC12C4052 STC12C5052 STC12C5410 STC12C5410AD STC12C5402 STC12C5402AD STC12C5404 STC12C5404AD STC12C546 STC12C5406AD STC12C5408 STC12C5408AD STC12C5410 STC12C5410AD STC12C5412 STC12C5412RD ...

    STC12LExx Series MCU copy protection read: STC12LE1052 STC12LE2052 STC12LE4052 STC12LE5052 ...

 

 

Chapter 6 : Examples

Introduction

The purpose of this chapter is to provide basic information about microcontrollers that one needs to know in order to be able to use them successfully in practice. This is why this chapter doesn't contain any super interesting program or device schematic with amazing solutions. Instead, the following examples are better proof that program writing is neither a privilege nor a talent issue, but the ability of simply putting puzzle pieces together using directives. Rest assured that design and development of devices mainly consists of the following method “test-correct-repeat”. Of course, the more you are in it, the more complicated it becomes since the puzzle pieces are put together by both children and first-class architects...

6.1 Basic connecting

Basic connecting - Power Supply

As seen in the figure above, in order to enable the microcontroller to operate properly it is necessary to provide:

  • Power supply:
  • Reset signal: and
  • Clock signal.

Clearly, it is about very simple circuits, but it does not have to be always like that. If the target device is used for controlling expensive machines or maintaining vital functions, everything gets increasingly complicated. However, this solution is sufficient for the time being...

Power supply

Even though this microcontroller can operate at different power supply voltages, why to test “Murphy’s low”?! A 5V DC is most commonly used. The circuit, shown in the figure, uses a cheap integrated three-terminal positive regulator LM7805, and provides high-quality voltage stability and quite enough current to enable the microcontroller and peripheral electronics to operate normally (enough current in this case means 1Amp).

Reset signal

In order that the mucrocontroller can operate properly, a logic 0 (0V) must be applied to the reset pin RS. The push button connecting the reset pin RS to power supply VCC is not necessary. However, it is almost always provided because it enables the microcontroller safe return to normal operating conditions if something goes wrong. 5V is brought to this pin, the microcontroller is reset and program starts execution from the beginning.

Clock signal

Even though the microcontroller has a built-in oscillator, it cannot operate without two external capacitors and quartz crystal which stabilize its operation and determines its frequency (operating speed of the microcontroller).

Clock signal

Of course, it is not always possible to apply this solution so that there are always alternative ones. One of them is to provide clock signal from a special source through invertor. See the figure on the left.

6.2 Additional components

Regardless of the fact that the microcontroller is a product of modern technology, it is of no use without being connected to additional components. Simply put, the appearance of voltage on its pins means nothing if not used for performing certain operations (turn something on/off, shift, display etc.).

Switches and Push buttons

There are no simpler devices than switches and push-buttons. This is the simplest way of detecting appearance of a voltage on the microcontroller input pin.

Switches and Pushbuttons

Nevertheless, it is not so simple in practice... It is about contact bounce- a common problem with m e c h a n i c a l switches. When the contacts strike together, their momentum and elasticity act together to cause bounce. The result is a rapidly pulsed electrical current instead of a clean transition from zero to full current. It mostly occurs due to vibrations, slight rough spots and dirt between contacts. This effect is usually unnoticeable when using these components in everyday life because the bounce happens too quickly. In other words, the whole this process does not last long (a few micro- or miliseconds), but it is long enough to be registered by the microcontroller. When using only a push-button as a pulse counter, errors occur in almost 100% of cases!

RC Debounce

The simplest solution to this problem is to connect a simple RC circuit to suppress quick voltage changes. Since the bounce period is not defined, the values of components are not precisely determined. In most cases, it is recomended to use the values shown in figure below.

If complete stability is needed then radical measures should be taken. The output of the circuit, shown in figure (RS flip-flop), will change its logic state only after detecting the first pulse triggered by contact bounce. This solution is expensive (SPDT switch), but effecient, the problem is definitely solved. Since the capacitor is not used, very short pulses can also be registered in this way.

Filp Flop Debounce

In addition to these hardware solutions, there is also a simple software solution. When a program tests the state of an input pin and detects a change, the check should be done one more time after a certain delay. If the change is confirmed, it means that a switch or push button has changed its position. The advantages of such solution are obvious: it is free of charge, effects of noises are eliminated and it can be applied to the poorer quality contacts as well. Disadvantage is the same as when using RC filter, i.e. pulses shorter than program delay cannot be registered.

Optocoupler

Optocouplers

An optocoupler is a device commonly used to galvanically separate microcontroller’s electronics from any potentially dangerous current or voltage in its surroundings. Optocouplers usually have one, two or four light sources (LED diodes) on their input while on their output, opposite to diodes, there is the same number of elements sensitive to light (phototransistors, photo-thyristors or photo-triacs). The point is that an optocoupler uses a short optical transmission path to transfer a signal between the elements of circuit, while keeping them electrically isolated. This isolation makes sense only if diodes and photo-sensitive elements are separately powered. In this way, the microcontroller and expensive additional electronics are completely protected from high voltage and noises which are the most common cause of destroying, damaging or unstable operation of electronic devices in practice. The most frequently used optocouplers are those with phototransistors on their outputs. When using the optocoupler with internal base-to-pin 6 connection (there are also optocouplers without it), the base can be left unconnected. An optional connection which lessens the effects of noises by eliminating very short pulses is presented by the broken line in the figure.

Relay

Relays

A relays is an electrical switch that opens and closes under control of another electrical circuit. It is therefore connected to ouput pins of the microcontroller and used to turn on/off high-power devices such as motors, transformers, heaters, bulbs, antenna systems etc. These are almost always placed away from the board sensitive components. There are various types of relays but all of them operate in the same way. When a current flows through the coil, the relay is operated by an electromagnet to open or close one or many sets of contacts. Similar to optocouplers, there is no galvanic connection (electrical contact) between input and output circuits. Relays usually demand both higher voltage and current to start operation, but there are also miniature ones which can be activated by a low current directly obtained from a microcontroller pin.

The figure shows the solution specific to the 8051 microcontroller. A darlington transistor is used here to activate relays because of its high current gain. This is not in accordance with “rules”, but is necessary in the event that logic one activation is applied since the output current is then very low (pin acts as an input).

Basic connecting of the microcontroller - Relays

In order to prevent the appearance of self-induction high voltage, caused by a sudden stop of current flow through the coil, an inverted polarized diode is connected in parallel to the coil. The purpose of this diode is to “cut off” the voltage peak.

Light-emitting diode (LED)

Light-emitting diodes are elements for light signalization in electronics. They are manufactured in different shapes, colors and sizes. For their low price, low power consumption and simple use, they have almost completely pushed aside other light sources, bulbs at first place. They perform similar to common diodes with the difference that they emit light when current flows through them.

Light-emitting diode (LED)

It is important to limit their current, otherwise they will be permanently destroyed. For this reason, a conductor must be connected in parallel to an LED. In order to determine value of this conductor, it is necessary to know diode’s voltage drop in forward direction, which depends on what material a diode is made from and what colour it is. Typical values of the most frequently used diodes are shown in table below. As seen, there are three main types of LEDs. Standard ones get ful brightness at current of 20mA. Low Current diodes get ful brightness at ten times lower current while Super Bright diodes produce more intensive light than Standard ones.

Color Type Typical current Id (mA) Maximal current If (mA) Voltage drop Ud (V)
Infrared - 30 50 1.4
Red Standard 20 30 1.7
Red Super Bright 20 30 1.85
Red Low Current 2 30 1.7
Orange - 10 30 2.0
Green Low Current 2 20 2.1
Yellow - 20 30 2.1
Blue - 20 30 4.5
White - 25 35 4.4
Low current LED

Since the 8051 microcontroller can provide only low output current and since its pins are configured as outputs when voltage provided on them is 0V, direct connecting to LEDs is performed as shown in figure on the right (Low current LED, cathode is connected to the output pin).

LED displays

Basically, an LED display is nothing more than several LEDs moulded in the same plastic case. There are many types of displays composed of several dozens of built in diodes which can display different symbols.

LED displays

Most commonly used is a so called 7-segment display. It is composed of 8 LEDs, 7 segments are arranged as a rectangle for symbol displaying and there is an additional segment for decimal point displaying. In order to simplify connecting, anodes and catodes of all diodes are connected to the common pin so that there are common anode displays and common catode displays, respectively. Segments are marked with the latters from A to G, plus dp, as shown in the figure on the left. On connecting, each diode is treated separtely, which means that each must have its own current limiting resistor.

Displays connected to the microcontroller usually occupy a large number of valuable I/O pins, which can be a big problem especially if it is needed to display multy digit numbers. The problem is more than obvious if, for example, it is needed to display two 6-digit numbers (a simple calculation shows that 96 output pins are needed in this case). The solution to this problem is called MULTIPLEXING. This is how an optical illusion based on the same operating principle as a film camera is made. Only one digit is active at a time, but they change their state so quickly making impression that all digits of a number are simultaneously active.

Basic connecting of the microcontroller - LED displays

Here is an explanation on the figure above. First a byte representing units is applied on a microcontroller port and a transistor T1 is activated at the same time. After a while, the transistor T1 is turned off, a byte representing tens is applied on a port and a transistor T2 is activated. This process is being cyclically repeated at high speed for all digits and corresponding transistors.

The fact that the microcontroller is just a kind of miniature computer designed to understand only the language of zeros and ones is fully expressed when displaying any digit. Namely, the microcontroller doesn't know what units, tens or hundreds are, nor what ten digits we are used to look like. Therefore, each number to be displayed must be prepared in the following way:

First of all, a multy digit number must be split into units, tens etc. in a particular subroutine. Then each of these digits must be stored in special bytes. Digits get familiar format by performing “masking”. In other words, a binary format of each digit is replaced by a different combination of bits in a simple subroutine. For example, the digit 8 (0000 1000) is replaced by the binary number 0111 111 in order to activate all LEDs displaying digit 8. The only diode remaining inactive in this case is reserved for the decimal point. If a microcontroller port is connected to the display in such a way that bit 0 activates segment “a”, bit 1 activates segment “b”, bit 2 segment “c” etc., then the table below shows the “mask” for each digit.

Masking LED displays
Digits to display Display Segments
dp a b c d e f g
0 1 0 0 0 0 0 0 1
1 1 0 0 1 1 1 1 1
2 1 0 0 1 0 0 1 0
3 1 0 0 0 0 1 1 0
4 1 1 0 0 1 1 0 0
5 1 0 1 0 0 1 0 0
6 1 0 1 0 0 0 0 0
7 1 0 0 0 1 1 1 1
8 1 0 0 0 0 0 0 0
9 1 0 0 0 0 1 0 0

In addition to digits from 0 to 9, some letters of alphabet - A, C, E, J, F, U, H, L, b, c, d, o, r, t - can also be displayed by performing appropriate masking.
If the event that common chatode displays are used all units in the table should be replaced by zeros and vice versa. Additionally, NPN transistors should be used as drivers as well.

Liquid Crystal Displays (LCD)

An LCD display is specifically manufactured to be used with microcontrollers, which means that it cannot be activated by standard IC circuits. It is used for displaying different messages on a miniature liquid crysal display.

Liquid Crystal Displays (LCD)

The model described here is for its low price and great capabilities most frequently used in practice. It is based on the HD44780 microcontroller (Hitachi) and can display messages in two lines with 16 characters each. It displays all the letters of alphabet, Greek letters, punctuation marks, mathematical symbols etc. In addition, it is possible to display symbols made up by the user. Other useful features include automatic message shift (left and right), cursor appearance, LED backlight etc.

LCD Pins

There are pins along one side of a small printed board. These are used for connecting to the microcontroller. There are in total of 14 pins marked with numbers (16 if it has backlight). Their function is described in the table bellow:

Function Pin Number Name Logic State Description
Ground 1 Vss - 0V
Power supply 2 Vdd - +5V
Contrast 3 Vee - 0 - Vdd
Control of operating 4 RS 0
1
D0 – D7 are interpreted as commands
D0 – D7 are interpreted as data
5 R/W 0
1
Write data (from controller to LCD)
Read data (from LCD to controller)
6 E 0
1
From 1 to 0
Access to LCD disabled
Normal operating
Data/commands are transferred to LCD
Data / commands 7 D0 0/1 Bit 0 LSB
8 D1 0/1 Bit 1
9 D2 0/1 Bit 2
10 D3 0/1 Bit 3
11 D4 0/1 Bit 4
12 D5 0/1 Bit 5
13 D6 0/1 Bit 6
14 D7 0/1 Bit 7 MSB

LCD screen

LCD screen pixels

An LCD screen consists of two lines each containing 16 characters. Each character consists of 5x8 or 5x11 dot matrix. This book covers the most commonly used display, i.e. the 5x8 character display.

Display contrast depends on the power supply voltage and whether messages are displayed in one or two lines. For this reason, varying voltage 0-Vdd is applied on the pin marked as Vee. Trimmer potentiometer is usually used for that purpose. Some LCD displays have built-in backlight (blue or green LEDs). When used during operation, a current limiting resistor should be serially connected to one of the pins for backlight power supply (similar to LEDs).

LCD backlight

If there are no characters displayed or if all of them are dimmed when the display is on, the first thing that should be done is to check the potentiometer for contrast regulation. Is it properly adjusted? The same applies if the mode of operation has been changed (writing in one or two lines).

LCD Memory

The LCD display contains three memory blocks:

  • DDRAM Display Data RAM;
  • CGRAM Character Generator RAM; and
  • CGROM Character Generator ROM.

DDRAM Memory

DDRAM memory is used for storing characters to be displayed. The size of this memory is sufficient for storing 80 characters. Some memory locations are directly connected to the characters on display.

DDRAM Memory

It works quite simply: it is sufficient to configure the display so as to increment addresses automatically (shift right) and set the starting address for the message that should be displayed (for example 00 hex).

After that, all characters sent through lines D0-D7 will be displayed in the message format we are used to- from left to right. In this case, displaying starts from the first field of the first line since the address is 00 hex. If more than 16 characters are sent, then all of them will be memorized, but only the first sixteen characters will be visible. In order to display the rest of them, a shift command should be used. Virtually, everything looks as if the LCD display is a “window” which moves left-right over memory locations containing different characters. This is how the effect of message “moving” on the screen is made.

If the cursor is on, it appears at the location which is currently addressed. In other words, when a character appears at the cursor position, it will automatically move to the next addressed location.
Since this is a sort of RAM memory, data can be written to and read from it, but its contents is irretrievably lost when the power goes off.

CGROM Memory

CGROM memory contains the default chracter map with all characters that can be displayed on the screen. Each character is assigned to one memory location.

CGROM Memory

The addresses of CGROM memory locations match the characters of ASCII. If the program being currently executed encounters a command “send character P to port”, then the binary value 0101 0000 appears on the port. This value is the ASCII equivalent to the character P. It is then written to LCD, which results in displaying the symbol from 0101 0000 location of CGROM. In other words, the character “P” is displayed. This applies to all letters of alphabet (capitals and small), but not to numbers.

As seen on the previous “map”, addresses of all digits are pushed forward by 48 relative to their values (digit 0 address is 48, digit 1 address is 49, digit 2 address is 50 etc.). Accordingly, in order to display digits correctly, each of them needs to be added a decimal number 48 prior to be sent to LCD.

From their inception till today, computers can recognize only numbers, but not letters. It means that all data a computer swaps with a peripheral device has a binary format, even though the same is recognized by the man as letters (keyboard is an excellent example). Every character matches the unique combination of zeroes and ones. ASCII is character encoding based on the English alphabet. ASCII code specifies correspondance between standard character symbols and their numerical equivalents.

CGRAM memory

Apart from standard characters, the LCD display can also display symbols defined by the user itself. It can be any symbol in the size of 5x8 pixels. RAM memory called CGRAM in the size of 64 bytes enables it.

Memory registers are 8 bits wide, but only 5 lower bits are used. Logic one (1) in every register represents a dimmed dot, while 8 locations grouped together represent one character. It is best illustrated in figure below:

CGRAM memory

Symbols are usually defined at the beginnig of the program by simply writing zeros and ones to registers of CGRAM memory so that they form desired shapes. In order to display them it is sufficient to specify their address. Pay attention to the first coloumn in the CGROM map of characters. It doesn't contain RAM memory addresses, but symbols being discussed here. In this example, “display 0” means - display “č”, “display 1” means - display “ž” etc.

LCD Basic Commands

All data transferred to LCD through the outputs D0-D7 will be interpreted as a command or a data, which depends on the pin RS logic state:

RS = 1 - Bits D0-D7 are addresses of the characters to be displayed. LCD processor addresses one character from the character map and displays it. The DDRAM address specifies the location on which the character is to be displayed. This address is defined before the character is transferred or the address of previously transferred character is automatically incremented.

RS = 0 - Bits D0 - D7 are commands which determine the display mode. The commands recognized by the LCD are given in the table below:

Command RS RW D7 D6 D5 D4 D3 D2 D1 D0 Execution Time
Clear display 0 0 0 0 0 0 0 0 0 1 1.64mS
Cursor home 0 0 0 0 0 0 0 0 1 x 1.64mS
Entry mode set 0 0 0 0 0 0 0 1 I/D S 40uS
Display on/off control 0 0 0 0 0 0 1 D U B 40uS
Cursor/Display Shift 0 0 0 0 0 1 D/C R/L x x 40uS
Function set 0 0 0 0 1 DL N F x x 40uS
Set CGRAM address 0 0 0 1 CGRAM address 40uS
Set DDRAM address 0 0 1 DDRAM address 40uS
Read “BUSY” flag (BF) 0 1 BF DDRAM address -
Write to CGRAM or DDRAM 1 0 D7 D6 D5 D4 D3 D2 D1 D0 40uS
Read from CGRAM or DDRAM 1 1 D7 D6 D5 D4 D3 D2 D1 D0 40uS
I/D 1 = Increment (by 1)         R/L 1 = Shift right
    0 = Decrement (by 1)             0 = Shift left
    
S 1 = Display shift on           DL 1 = 8-bit interface
  0 = Display shift off             0 = 4-bit interface
  
D 1 = Display on                 N 1 = Display in two lines
  0 = Display off                  0 = Display in one line
  
U 1 = Cursor on                  F 1 = Character format 5x10 dots
  0 = Cursor off                   0 = Character format 5x7 dots
 
B 1 = Cursor blink on            D/C 1 = Display shift
  0 = Cursor blink off               0 = Cursor shift

What is the Busy flag?

Compared to the microcontroller, the LCD is an extremely slow component. Because of this, it was necessary to provide a signal which will, upon command execution, indicate that the display is ready to receive a new data. That signal, called the busy flag, can be read from line D7. When the BF bit is cleared (BF=0), the display is ready to receive a new data.

LCD Connection

Depending on how many lines are used for connecting the LCD to the microcontroller, there are 8-bit and 4-bit LCD modes. The appropriate mode is selected at the beginning of the operation. This process is called “initialization”. 8-bit LCD mode uses outputs D0-D7 to transfer data in the way explained on the previous page. The main purpose of 4-bit LED mode is to save valuable I/O pins of the microcontroller. Only 4 higher bits (D4-D7) are used for communication, while other may be left unconnected. Each data is sent to the LCD in two steps: four higher bits are sent first (normally through the lines D4-D7), then four lower bits. Initialization enables the LCD to link and interpret received bits correctly. Data is rarely read from the LCD (it is mainly transferred from the microcontroller to LCD) so that it is often possible to save an extra I/O pin by simple connecting R/W pin to ground. Such saving has its price. Messages will be normally displayed, but it will not be possible to read the busy flag since it is not possible to read the display either.

LCD Connection

Fortunately, there is a simple solution. After sending a character or a command it is important to give the LCD enough time to do its job. Owing to the fact that execution of the slowest command lasts for approximately 1.64mS, it will be sufficient to wait approximately 2mS for LCD.

LCD Initialization

The LCD is automatically cleared when powered up. It lasts for approximately 15mS. After that, the display is ready for operation. The mode of operation is set by default. It means that:

  1. Display is cleared
  2. Mode
    • DL = 1 Communication through 8-bit interface
    • N = 0 Messages are displayed in one line
    • F = 0 Character font 5 x 8 dots
  3. Display/Cursor on/off
    • D = 0 Display off
    • U = 0 Cursor off
    • B = 0 Cursor blink off
  4. Character entry
    • ID = 1 Displayed addresses are automatically incremented by 1
    • S = 0 Display shift off

Automatic reset is in most cases performed without any problems. In most cases, but not always! If for any reason the power supply voltage does not reach ful value within 10mS, the display will start to perform completely unpredictably. If the voltage supply unit is not able to meet this condition or if it is needed to provide completely safe operation, the process of initialization is applied. Initialization, among other things, causes a new reset enabling display to operate normally.

Refer to the figure below for the procedure on 8-bit initialization:

8-bit initialization

It is not a mistake!
In this algorithm, the same value is transferred three times in a row.

In case of 4-bit initialization, the procedure is as follows:

4-bit initialization

6.3 Examples

The schematic below is used in the several following examples:

LED connection schematic

Apart from components necessary for the operation of the microcontroller such as oscillator with capacitors and the simplest reset circuit, there are also several LEDs and one push button. These are used to indicate the operation of the program.

All LEDs are polarized in such a way that they are activated by driving a microcontroller pin low (logic 0).

LED Blinking

The purpose of this example is not to demonstrate the operation of LEDs, but the operating speed of the microcontroller. Simply put, in order to enable LED blinking to be visible, it is necessary to provide sufficient amount of time to pass between on/off states of LEDs. In this example time delay is provided by executing a subroutine called Delay. It is a triple loop in which the program remains for approximately 0.5 seconds and decrements values stored in registers R0, R1 or R2. After returning from the subroutine, the pin state is inverted and the same procedure is repeated...

;************************************************************************
;* PROGRAM NAME : Delay.ASM
;* DESCRIPTION: Program turns on/off LED on the pin P1.0
;* Software delay is used (Delay).
;************************************************************************
;BASIC DIRECTIVES
$MOD53
$TITLE(DELAY.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
        DSEG    AT    03FH
STACK_START:    DS    040H
 
;RESET VECTORS
       CSEG     AT    0
       JMP      XRESET                  ;Reset vector
       
       ORG      100H
       
XRESET: MOV     SP,#STACK_START         ;Define Stack pointer
        MOV     P1,#0FFh                ;All pins are configured as inputs
 
LOOP:
        CPL     P1.0                    ;Pin P1.0 state is inverted
        LCALL   Delay                   ;Time delay
        SJMP    LOOP
 
Delay:
        MOV     R2,#20                  ;500 ms time delay
F02:    MOV     R1,#50                  ;25 ms
F01:    MOV     R0,#230
        DJNZ    R0,$
        DJNZ    R1,F01
        DJNZ    R2,F02
 
END                                     ;End of program

Using Watch-dog Timer

This example describes how the watch-dog timer should not operate. The watch-dog timer is properly adjusted (nominal time for counting is 1024mS), but instruction used to reset it is intentionally left out so that this timer always "wins". As a result, the microcontroller is reset (state in registers remains unchanged), program starts execution from the beginning and the number in register R3 is incremented by 1 and then copied to port P1.

LEDs display this number in binary format...

;************************************************************************
;* PROGRAM NAME : WatchDog.ASM
;* DESCRIPTION : After watch-dog reset, program increments number in
;* register R3 and shows it on port P1 in binary format.
;************************************************************************
 
;BASIC DIRECTIVES
$MOD53
$TITLE(WATCHDOG.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
WMCON     DATA    96H
WDTEN     EQU     00000001B        ; Watch-dog timer is enabled
PERIOD    EQU     11000000B        ; Nominal Watch-dog period is set to be 1024ms 
 
;RESET    VECTOR
          CSEG    AT      0
          JMP     XRESET           ; Reset vector
 
          CSEG
          ORG     100H
 
XRESET:   ORL     WMCON,#PERIOD    ; Define Watch-dog period
          ORL     WMCON,#WDTEN     ; Watch-dog timer is enabled
 
          MOV     A,R3             ; R3 is moved to port 1
          MOV     P1,A
          INC     R3               ; Register R3 is incremented by 1
 
LAB:      SJMP    LAB              ; Wait for watch-dog reset
 
          END                      ; End of program

Timer T0 in mode 1

This program spends most of its time in an endless loop waiting for timer T0 to count up a full cycle. When it happens, an interrupt is generated, routine TIM0_ISR is executed and logic zero (0) on port P1 is shifted right by one bit. This is another way of demonstrating the operating speed of the microcontroller since each shift means that counter T0 has counted up 216 pulses!

;************************************************************************
;* PROGRAM NAME : Tim0Mod1.ASM
;* DESCRIPTION: Program rotates "0" on port 1. Timer T0 in mode 1 is
;* used
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(TIM0MOD1.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;DECLARATION OF VARIABLES
 
;STACK
 
        DSEG     AT     03FH
STACK_START:     DS     040H
 
;RESET VECTORS
       CSEG      AT 0
       JMP       XRESET             ; Reset vector
 
       ORG       00BH
       JMP       TIM0_ISR           ; Timer T0 reset vector
 
       ORG       100H
 
XRESET: MOV      SP,#STACK_START    ; Define Stack pointer
       MOV       TMOD,#01H          ; MOD1 is selected
       MOV       A,#0FFH
       MOV       P1,#0FFH
       SETB      TR0                ; Timer T0 is enabled
       MOV       IE,#082H           ; Interrupt enabled
       CLR       C
 
LOOP1: SJMP      LOOP1              ; Remain here
 
TIM0_ISR:        RRC     A          ; Rotate accumulator A through Carry flag
                 MOV     P1,A       ; Contents of accumulator A is moved to PORT1
                 RETI               ; Return from interrupt
 
       END                          ; End of program

Timer T0 in Split mode

Similarly to the previous example, the program spends most of its time in a loop called LOOP1. Since 16-bit Timer T0 is split into two 8-bit timers, there are also two interrupt sources.

The first interrupt is generated after timer T0 reset. Routine TIM0_ISR in which logic zero (0) bit on port P1 rotates is executed. Outside looking, it seems that LEDs move.

Another interrupt is generated upon Timer T1 reset. Routine TIM1_ISR in which the bit state DIRECTION inverts is executed. Since this bit determines direction of bit rotation then the moving direction of LED is also changed.
If you press a push button T1 at some point, a logic zero (0) on the P3.2 output will disable Timer T1.

;************************************************************************
;* PROGRAM NAME : Split.ASM
;* DESCRIPTION: Timer TL0 rotates bit on port P1, while TL1 determines
;* the rotation direction. Both timers operate in mode
;* 3. Logic zero (0) on output P3.2 disables rotation on port P1.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(SPLIT.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;DECLARATION OF VARIABLES
 
        BSEG    AT    0
 
;DECLARATION OF BIT-VARIABLES
 
SEMAPHORE:      DBIT    8
DIRECTION       BIT     SEMAPHORE
 
;STACK
        DSEG    AT    03FH
STACK_START:    DS    040H
 
;RESET VECTORS
 
        CSEG    AT    0
        JMP     XRESET                    ; Reset vector
        ORG     00BH
 
        JMP     TIM0_ISR                  ; Timer T0 reset vector
 
        ORG     01BH
        JMP     TIM1_ISR                  ; Timer T1 reset vector
 
        ORG     100H
XRESET: MOV     SP,#STACK_START           ; Define Stack pointer
        MOV     TMOD,#00001011B           ; Define MOD3
        MOV     A,#0FFH
        MOV     P1,#0FFH
        MOV     R0,#30D
        SETB    TR0                       ; TL0 is turned on
        SETB    TR1                       ; TL1 is turned on
        MOV     IE,#08AH                  ; Interrupt enabled
        CLR     C
        CLR     DIRECTION                 ; Rotate to the right
 
LOOP1:  SJMP    LOOP1                     ; Remain here
 
TIM0_ISR:
        DJNZ    R0,LAB3                   ; Slow down rotation by 256 times
        JB      DIRECTION,LAB1
        RRC     A                         ; Rotate contents of Accumulator to the right through
                                          ; Carry flag
 
        SJMP    LAB2
LAB1:   RLC     A                         ; Rotate contents of Accumulator to the left through
                                          ; Carry flag
LAB2:   MOV     P1,A                      ; Contents of Accumulator is moved to port P1
LAB3:   RETI                              ; Return from interrupt
 
TIM1_ISR:
        DJNZ    R1,LAB4                   ; Slow down direction of rotation by 256 times
        DJNZ    R2,LAB4                   ; When time expires, change rotation direction
        CPL     SMER
        MOV     R2,#30D
LAB4:   RETI
 
        END                               ; End of program

Simultaneous use of timers T0 and T1

This program can be considered as continuation of the previous one. They share the same idea, but in this case true timers T0 and T1 are used. In order to demonstrate the operation of both timers on the same port at the same time, timer T0 reset is used to shift logic zero (0) on the port, while Timer T1 reset is used to change rotation direction. This program spends most of its time in the loop LOOP1 waiting for an interrupt to be caused by reset. By checking the DIRECTION bit, information on rotation direction of both bits in accumulator as well as of moving port LED is obtained.

;************************************************************************
;* PROGRAM NAME : Tim0Tim1.ASM
;* DESCRIPTION: Timer TO rotates bit on port P1 while Timer1
;* changes rotation direction. Both timers are configured to operate in mode 1.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(TIM0TIM1.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;DECLARATION OF VARIABLES
 
       BSEG    AT    0
 
;DECLARATION OF BIT-VARIABLES
 
SEMAPHORE:      DBIT    8
DIRECTION       BIT     SEMAPHORE
 
;STACK
       DSEG    AT    03FH
STACK_START:   DS    040H
 
;RESET VECTORS
       CSEG    AT    0
       JMP     XRESET                     ; Reset vector
 
       ORG     00BH                       ; Timer 0 Reset vector
       JMP     TIM0_ISR
 
       ORG     01BH                       ; Timer 1 Reset vector
       JMP     TIM1_ISR
 
       ORG     100H
 
 
XRESET: MOV    SP,#STACK_START            ; Define Stack pointer
        MOV    TMOD,#11H                  ; Select MOD1 for both timers
        MOV    A,#0FFH
        MOV    P1,#0FFH
        MOV    R0,#30D                    ; R0 is initialized
        SETB   TR0                        ; TIMER0 is turned on
        SETB   TR1                        ; TIMER1 is turned on
        MOV    IE,#08AH                   ; Timer0 and Timer1 Interrupt enabled
        CLR    C
        CLR    DIRECTION                  ; Rotate to the right
 
LOOP1:  SJMP   LOOP1                      ; Remain here
 
 
TIM0_ISR:
        JB     DIRECTION,LAB1
        RRC A                             ; Rotate contents of accumulator to the right through
                                          ; Carry flag
        SJMP   LAB2
LAB1:   RLC    A                          ; Rotate contents of Accumulator to the left through
                                          ; Carry flag
LAB2:   MOV    P1,A                       ; Contents of Accumulator is moved to port P1
        RETI                              ; Return from interrupt
 
TIM1_ISR:
        DJNZ   R0,LAB3                    ; When time expires, change rotation direction
        CPL    DIRECTION
        MOV    R0,#30D                    ; Initialize R0
LAB3:
        RETI
        END                               ; End of program

Using Timer T2

This example describes the use of Timer T2 configured to operate in Auto-Reload mode. In this very case, LEDs are connected to port P3 while the push button used for forced timer reset (T2EX) is connected to the P1.1 pin.

Program execution is similar to the previous examples. When timer ends counting, an interrupt is enabled and subroutine TIM2_ISR is executed, thus rotating a logic zero (0) in accumulator and moving the contents of accumulator to the P3 pin. At last, flags which caused an interrupt are cleared and program returns to the loop LOOP1 where it remains until a new interrupt request arrives...

If push button T2EX is pressed, timer is temporarily reset. This push button resets timer, while push button RESET resets the microcontroller.

Using Timer T2
;************************************************************************
;* PROGRAM NAME : Timer2.ASM
;* DESCRIPTION: Program rotates log. "0" on port P3. Timer2 determines
;* the speed of rotation and operates in auto-reload mode
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(TIMER2.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;DEFINITION OF VARIABLES
 
        T2MOD    DATA     0C9H
;STACK
        DSEG     AT       03FH
STACK_START:     DS       040H
 
;RESET VECTORS
        CSEG     AT       0
        JMP      XRESET                   ; Reset vector
 
        ORG      02BH                     ; Timer T2 Reset vector
        JMP      TIM2_ISR
 
        ORG      100H
 
XRESET: MOV      SP,#STACK_START          ; Define Stack pointer
        MOV      A,#0FFH
        MOV      P3,#0FFH
        MOV      RCAP2L,#0FH              ; Prepare 16-bit auto-reload mode
        MOV      RCAP2L,#01H
        CLR      CAP2                     ; Enable 16-bit auto-reload mod 
        SETB     EXEN2                    ; Pin P1.1 reset is enabled
        SETB     TR2                      ; Enable Timer T2 
        MOV      IE,#0A0H                 ; Interrupt is enabled
        CLR      C
 
LOOP1:  SJMP     LOOP1                    ; Remain here
 
TIM2_ISR:        RRC      A               ; Rotate contents of Accumulator to the right through
                                          ; Carry flag
                 MOV      P3,A            ; Move the contents of Accumulator A to PORT3
                 CLR      TF2             ; Clear timer T2 flag TF2 
                 CLR      EXF2            ; Clear timer T2 flag EXF2 
                 RETI                     ; Return from interrupt
 
                 END                      ; End of program

Using External Interrupt

Here is another example of interrupt execution. An external iterrupt is generated when a logic zero (0) is present on pin P3.2 or P3.3. Depending on which input is active, one of two routines will be executed:

A logic zero (0) on the P3.2 pin initiates execution of interrupt routine Isr_Int0, thus incrementing number in register R0 and copying it to port P0. Logic zero on the P3.3 pin initiates execution of subroutine Isr_Int1, number in register R1 is incremented by 1 and then copied to port P1.

In short, each press on push buttons INT0 and INT1 will be counted and immediately shown in binary format on appropriate port (LED which emitts light represents a logic zero (0)).

Using External Interrupt
;************************************************************************
;* PROGRAM NAME : Int.ASM
;* DESCRIPTION : Program counts interrupts INT0 generated by appearance of high-to-low
;* transition signal on pin P3.2 Result appears on port P0. Interrupts INT1 are also 
;* counted up at the same time. They are generated byappearing high-to-low transition
;* signal on pin P3. The result appears on port P1.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(INT.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;RESET VECTORS
 
        CSEG     AT     0
        JMP      XRESET               ; Reset vector
 
        ORG      003H                 ; Interrupt routine address for INT0
        JMP      Isr_Int0
        ORG 013H                      ; Interrupt routine address for INT1
        JMP      Isr_Int1
 
        ORG      100H
XRESET:
        MOV      TCON,#00000101B      ; Interrupt INT0 is generated by appearing
                                      ; high-to-low transition signal on pin P3.2
                                      ; Interrupt INT0 is generated by appearing
                                      ; high-to-low transition signal on pin P3.3
        MOV      IE,#10000101B        ; Interrupt enabled
        MOV      R0,#00H              ; Counter starting value
        MOV      R1,#00H
        MOV      P0,#00H              ; Reset port P0
        MOV      P1,#00H              ; Reset port P1
 
LOOP:   SJMP     LOOP                 ; Remain here
 
Isr_Int0:
        INC R0                        ; Increment value of interrupt INT0 counter
        MOV P0,R0
        RETI
 
Isr_Int1:
        INC R1                        ; Increment value of interrupt INT1 counter
        MOV P1,R1
        RETI
        END                           ; End of program

Using LED display

The following examples describe the use of LED displays. Common chatode displays are used here, which means that all built-in LEDs are polarized in such a way that their anodes are connected to the microcontroller pins. Since the common way of thinking is that logic one (1) turns something on and logic zero (0) turns something of, Low Current displays (low power consumption) and their diodes (segments) are connected serially to resistors of relatively high resistance.

In order to save I/O pins, four LED displays are connected to operate in multiplex mode. It means that all segments having the same name are connected to one output port each and only one display is active at a time.

Tranzistors and segmenats on displays are quickly activated, thus making impression that all digits are active simultaneously.

Using LED display

Writing digits on LED display

This program is a kind of “warming up” exerciese before real work starts. The purpose of this example is to display something on any display. Multiplex mode is not used this time. Instead, digit 3 is displayed on only one of them (first one on the right).

Since the microcontroller “does not know” how we write number 3, a small subroutine called Disp is used (the microcontroller writes this number as 0000 0011). This subroutine enables all decimal digits (0-9) to be displayed (masked). The principle of operation is simple. A number to be displayed is added to the current address and program jump is executed. Different numbers require different jump length. Precisely determined combination of zeroes and ones appears on each of these new locations (digit 1 mask, digit 2 mask...digit 9 mask). When this combination is transferred to the port, the display shows desired digit.

;************************************************************************
;* PROGRAM NAME : 7Seg1.ASM
;* DESCRIPTION: Program displays number "3" on 7-segment LED display
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(7SEG1.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
          DSEG     AT     03FH
STACK_START:       DS     040H
 
;RESET VECTORS
          CSEG     AT     0
          JMP      XRESET               ; Reset vector
 
          ORG      100H
 
XRESET:   MOV      SP,#STACK_START      ; Define Stack pointer
          MOV      P1,#0                ; Turn off all segments on displays
          MOV      P3,#20h              ; Activate display D4
 
LOOP:
          MOV      A,#03                ; Send number “3” to display
          LCALL    Disp                 ; Perform appropriate masking for the number
          MOV      P1,A
          SJMP     LOOP
 
Disp:                                   ; Subroutine for displaying digits
          INC      A
          MOVC     A,@A+PC
          RET
          DB       3FH                  ; Digit 0 mask
          DB       06H                  ; Digit 1 mask
          DB       5BH                  ; Digit 2 mask
          DB       4FH                  ; Digit 3 mask
          DB       66H                  ; Digit 4 mask
          DB       6DH                  ; Digit 5 mask
          DB       7DH                  ; Digit 6 mask
          DB       07H                  ; Digit 7 mask
          DB       7FH                  ; Digit 8 mask
          DB       6FH                  ; Digit 9 mask
          END                           ; End of program

Writing and changing digits on LED display

This program is only an extended verson of the previous one. There is only one digit active- the first one on the right, and there is no use of multiplexing. Unlike the previous example, all decimal numbers are displayed (0-9). In order to enable digits to change at reasonable pace, a soubroutine L2 which causes a short time delay is executed prior to each change occurs. Basically, the whole process is very simple and takes place in the main loop called LOOP which looks as follows:

  1. R3 is copied to Accumulator and subroutine for masking digits Disp is executed;
  2. Accumulator is copied to the port and displayed;
  3. The contents of the R3 register is incremented;
  4. It is checked whether 10 cycles are counted or not. If it is, register R3 is reset in order to enable counting to start from 0; and
  5. Instruction labeled as L2 within subroutine is executed.
;************************************************************************
;* PROGRAM NAME: 7Seg2.ASM
;* DESCRIPTION: Program writes numbers 0-9 on 7-segment LED display
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(7SEG2.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG     AT     03FH
STACK_START:      DS     040H
 
;RESET VECTORS
         CSEG     AT     0
         JMP      XRESET                   ; Reset vector
 
         ORG      100H
 
XRESET:  MOV      SP,#STACK_START          ; Define Stack pointer
         MOV      R3,#0                    ; Counter initial value
         MOV      P1,#0                    ; Turn off all display segments
         MOV      P3,#20h                  ; Activate display D4
 
LOOP:
         MOV      A,R3
         LCALL    Disp                     ; Perform appropriate masking for number in
                                           ; Accumulator
         MOV      P1,A
         INC      R3                       ; Increment number in register by 1
         CJNE     R3,#10,L2                ; Check whether the number 10 is in R3
         MOV      R3,#0                    ; If it is, reset counter
L2:
         MOV      R2,#20                   ; 500 mS time delay
F02:     MOV      R1,#50                   ; 25 mS
F01:     MOV      R0,#230
         DJNZ     R0,$
         DJNZ     R1,F01
         DJNZ     R2,F02
         SJMP     LOOP
 
Disp:                                      ; Subroutine for writing digits
         INC      A
         MOVC     A,@A+PC
         RET
         DB       3FH                      ; Digit 0 mask
         DB       06H                      ; Digit 1 mask
         DB       5BH                      ; Digit 2 mask
         DB       4FH                      ; Digit 3 mask
         DB       66H                      ; Digit 4 mask
         DB       6DH                      ; Digit 5 mask
         DB       7DH                      ; Digit 6 mask
         DB       07H                      ; Digit 7 mask
         DB       7FH                      ; Digit 8 mask
         DB       6FH                      ; Digit 9 mask
 
         END                               ; End of program

Writing two-digit number on LED display

It is time for time multiplexing! This is the simplest example which displays the number 23 on two displays in such a way that one of them displays units, while the other displays tens. The most important thing in the program is time synchronization. Otherwise, everything is very simple. Transistor T4 enables display D4 and at the same time a bit combination corresponding to the digit 3 is set on the port. After that, transistor T4 is disabled and the whole process is repeated using transistor T3 and display D3 in order to display digit 2. This procedure must be continuosly repeated in order to make impression that both displays are active at the same time.

;************************************************************************
;* PROGRAM NAME: 7Seg3.ASM
;* DESCRIPTION: Program displays number "23" on 7-segment LED display
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(7SEG3.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG      AT      03FH
STACK_START:       DS      040H
 
;RESET VECTORS
         CSEG      AT      0
         JMP       XRESET                    ; Reset vector
 
         ORG       100H
XRESET:  MOV       SP,#STACK_START           ; Define Stack pointer
 
LOOP:    MOV       P1,#0                     ; Turn off all display segments
         MOV       P3,#20h                   ; Activate display D4
         MOV       A,#03                     ; Write digit 3 on display D4
         LCALL     Disp                      ; Find appropriate mask for that digit
         MOV       P1,A                      ; Put the mask on the port
         MOV       P1,#0                     ; Turn off all dislay segments
         MOV       P3,#10h                   ; Activate display D3
         MOV       A,#02                     ; Write digit 2 on display D3
         LCALL     Disp                      ; Find mask for that digit
         MOV       P1,A                      ; Put the mask on the port
         SJMP      LOOP                      ; Return to the label LOOP
 
Disp:                                        ; Subroutine for writing digits
         INC       A
         MOVC      A,@A+PC
         RET
         DB        3FH                       ; Digit 0 mask
         DB        06H                       ; Digit 1 mask
         DB        5BH                       ; Digit 2 mask
         DB        4FH                       ; Digit 3 mask
         DB        66H                       ; Digit 4 mask
         DB        6DH                       ; Digit 5 mask
         DB        7DH                       ; Digit 6 mask
         DB        07H                       ; Digit 7 mask
         DB        7FH                       ; Digit 8 mask
         DB        6FH                       ; Digit 9 mask
 
         END                                 ; End of program

Using four digit LED display

In this example all four displays, instead of two, are active so that it is possible to write numbers from 0 to 9999. Here, the number 1 234 is displayed. After initialization, the program remains in the loop LOOP where digital multiplexing is performed. The subroutine Disp is used to convert binary numbers into corresponding combinations of bits for the purpose of activating display lighting segments.

;************************************************************************
;* PROGRAM NAME : 7Seg5.ASM
;* DESCRIPTION : Program displays number"1234" on 7-segment LED display
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(7SEG5.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG     AT     03FH
STACK_START:      DS     040H
 
;RESET VECTORS
         CSEG     AT     0
         JMP      XRESET                  ; Reset vector
 
         ORG      100H
 
XRESET:  MOV      SP,#STACK_START         ; Define Stack pointer
 
LOOP:    MOV      P1,#0                   ; Turn off all display segments 
         MOV      P3,#20h                 ; Activate display D4
         MOV      A,#04                   ; Write digit 4 on display D4
         LCALL    Disp                    ; Find mask for that digit
         MOV      P1,A                    ; Put the mask on the port
         MOV      P1,#0                   ; Turn off all display segments
         MOV      P3,#10h                 ; Activate display D3
         MOV      A,#03                   ; Write digit 3 on display D3
         LCALL    Disp                    ; Find mask for that digit
         MOV      P1,A                    ; Put the mask on the port
         MOV      P1,#0                   ; Turn off all display segments
         MOV      P3,#08h                 ; Activate display D2
         MOV      A,#02                   ; Write digit 2 on display D2
         LCALL    Disp                    ; Find mask for that digit
         MOV      P1,A                    ; Put the mask on the port
         MOV      P1,#0                   ; Turn off all display segments
         MOV      P3,#04h                 ; Activate display D1
         MOV      A,#01                   ; Write digit 1 on display D1
         LCALL    Disp                    ; Find mask for that digit
         MOV      P1,A                    ; Put the mask on the port
         SJMP     LOOP                    ; Return to the lable LOOP
 
Disp:                                     ; Subroutine for writing digits
         INC      A
         MOVC     A,@A+PC
         RET
         DB       3FH                     ; Digit 0 mask
         DB       06H                     ; Digit 1 mask
         DB       5BH                     ; Digit 2 mask
         DB       4FH                     ; Digit 3 mask
         DB       66H                     ; Digit 4 mask
         DB       6DH                     ; Digit 5 mask
         DB       7DH                     ; Digit 6 mask
         DB       07H                     ; Digit 7 mask
         DB       7FH                     ; Digit 8 mask
         DB       6FH                     ; Digit 9 mask
 
         END ; End of program

LED display as a two digit counter

Things are getting complicated... In addition to two digit multiplexing, the microcontroller also performs other operations. In this example, contents of registers R2 and R3 are incremented in order to display number counting (97, 98, 99, 00, 01, 02...).

This time, transistors which activate displays remain turned on for 25mS. The soubroutine Delay is in charge of that. Even though digits shift much slower now, it is still not slow enough to make impression of simultaneous operation. After both digits of a number blink for 20 times, the number on displays is incremented by 1 and the whole procedure is repeated.

;************************************************************************
;* PROGRAM NAME : 7Seg4.ASM
;* DESCRIPTION: Program displays numbers 0-99 on 7-segment LED displays
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(7SEG4.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG      AT      03FH
STACK_START:       DS      040H
 
;RESET VECTORS
         CSEG      AT      0
         JMP       XRESET                   ; Reset vector
 
         ORG       100H
 
XRESET:  MOV       SP,#STACK_START          ; Define Stack pointer
         MOV       R2,#0                    ; Counter starting value
         MOV       R3,#0
         MOV       R4,#0
 
LOOP:    INC       R4                       ;Wait for display to be "refreshed" for 100 times 
         CJNE      R4,#20d,LAB1             ;before incrementing the counter
         MOV       R4,#0
         MOV       P1,#0                    ; Turn off all display segments 
         INC       R2                       ; Increment Register containing units by 1
         CJNE      R2,#10d,LAB1
         MOV       R2,#0                    ; Reset units
         INC       R3                       ; Increment Register with tens by 1
         CJNE      R3,#10d,LAB1             ;
         MOV       R3,#0                    ; Reset tens
 
LAB1:
         MOV       P3,#20h                  ; Activate display D4
         MOV       A,R2                     ; Copy Register containing units to A
         LCALL     Disp                     ; Call mask for that digit
         MOV       P1,A                     ; Write units on display D4
         LCALL     Delay                    ; 25ms delay
         MOV       P1,#0                    ; Turn off all display segments
         MOV       P3,#10h                  ; Activate display D3
         MOV       A,R3                     ; Copy Register contaning tens to A
         LCALL     Disp                     ; Call mask for that digit
         MOV       P1,A                     ; Write tens on display D3
         LCALL     Delay                    ; 25ms delay
         SJMP      LOOP
 
Delay:
         MOV       R1,#50                   ; 5 ms delay
F01:     MOV       R0,#250
         DJNZ      R0,$
         DJNZ      R1,F01
         RET
 
Disp:                                       ; Subroutine for displaying digits
         INC       A
         MOVC      A,@A+PC
         RET
         DB        3FH                      ; Digit 0 mask
         DB        06H                      ; Digit 1 mask
         DB        5BH                      ; Digit 2 mask
         DB        4FH                      ; Digit 3 mask
         DB        66H                      ; Digit 4 mask
         DB        6DH                      ; Digit 5 mask
         DB        7DH                      ; Digit 6 mask
         DB        07H                      ; Digit 7 mask
         DB        7FH                      ; Digit 8 mask
         DB        6FH                      ; Digit 9 mask
 
         END                                ; End of program

Handling EEPROM

This program writes data to on-chip EEPROM memory. In this case, the data is a hexadecimal number 23 which is to be written to the location with address 00.

To make sure that this number is correctly written, the same location of EEPROM is read 10mS later in order to compare these two numbers. If they match, F will be displayed. Otherwise, E will be displayed on the LED display (Error).

;************************************************************************
;* PROGRAM NAME: EEProm1.ASM
;* DESCRIPTION: Programming EEPROM at address 0000hex and displaying message
;* on LED display.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(EEPROM1.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
WMCON     DATA     96H
EEMEN     EQU      00001000B              ; Access to internal EEPROM is enabled
EEMWE     EQU      00010000B              ; Write to EEPROM is enabled
TEMP      DATA     030H                   ; Define Auxiliary register
 
THE END   EQU      071H                   ; Display "F" 
ERROR     EQU      033H                   ; Display "E" 
 
;STACK
          DSEG     AT     03FH
STACK_START:       DS     040H
 
;RESET VECTORS
          CSEG     AT     0
          JMP      XRESET                 ; Reset vector
 
          ORG      100H
 
XRESET:   MOV      IE,#00                 ; All interrupts are disabled
          MOV      SP,#STACK_START
 
          MOV      DPTR,#0000H            ; Choose location address in EEPROM
          ORL      WMCON,#EEMEN           ; Access to EEPROM is enabled
          ORL      WMCON,#EEMWE           ; Write to EEPROM is enabled
          MOV      TEMP,#23H              ; Number written to EEPROM is moved to
          MOV      A,TEMP                 ; register TEMP and Accumulator
          MOVX     @DPTR,A                ; Write byte to EEPROM
          CALL     DELAY                  ; 10ms delay
          MOVX     A,@DPTR                ; Read the same location and compare to TEMP,
          CJNE     A,TEMP,ERROR           ; If they don't match, jump to label ERROR
          MOV      A,#KRAJ                ; Display F (correct)
          MOV      P1,A
          XRL      WMCON,#EEMWE           ; Write to EEPROM is disabled
          XRL      WMCON,#EEMEN           ; Access to EEPROM is disabled
LOOP1:    SJMP     LOOP1                  ; Remain here
 
ERROR:    MOV      A,#ERROR               ; Display E (error)
          MOV      P1,A
LOOP2:    SJMP     LOOP2
 
DELAY:    MOV      A,#0AH                 ; Delay
          MOV      R3,A
LOOP3:    NOP
LOOP4:    DJNZ     B,LOOP4
LOOP5:    DJNZ     B,LOOP5
          DJNZ     R3,LOOP3
          RET
 
          END                             ; End of program

Data reception via UART

In order to enable successful UART serial communication, it is necessary to meet specific rules of the RS232 standard. It primarily refers to voltage levels required by this standard. Accordingly, -10V stands for logic one (1) in the message, while +10V stands for logic zero (0). The microcontroller converts accurately data into serial format, but its power supply voltage is only 5V. Since it is not easy to convert 0V into 10V and 5V into -10V, this operation is on both transmit and receive side left to a specialized IC circuit. Here, the MAX232 by MAXIM is used because it is widespread, cheap and reliable.

This example shows how to receive message sent by a PC. Timer T1 generates boud rate. Since the 11.0592 MHz quartz crystal is used here, it is easy to obtain standard baud rate which amouts to 9600 bauds. Each received data is immediately transferred to port P1 pins.

Receiving data via serial communication UART
;************************************************************************
;* PROGRAM NAME : UartR.ASM
;* DESCRIPTION: Each data received from PC via UART appears on the port
;* P1.
;*
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(UARTR.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG     AT     03FH
STACK_START:      DS     040H
 
;RESET VECTORS
         CSEG     AT     0
         JMP      XRESET                ; Reset vector
         ORG      023H                  ; Starting address of UART interrupt routine
         JMP      IR_SER
 
         ORG      100H
 
XRESET:  MOV      IE,#00                ; All interrupts are disabled
         MOV      SP,#STACK_START       ; Initialization of Stack pointer
         MOV      TMOD,#20H             ; Timer1 in mode2
         MOV      TH1,#0FDH             ; 9600 baud rate at the frequency of
                                        ; 11.0592MHz
         MOV      SCON,#50H             ; Receiving enabled, 8-bit UART
         MOV      IE,#10010000B         ; UART interrupt enabled
         CLR      TI                    ; Clear transmit flag
         CLR      RI                    ; Clear receive flag
         SETB     TR1                   ; Start Timer1
 
LOOP:    SJMP     LOOP                  ; Remain here
 
IR_SER:  JNB      RI,OUTPUT             ; If any data is received,
                                        ; move it to the port
         MOV      A,SBUF                ; P1
         MOV      P1,A
         CLR      RI                    ; Clear receive flag
OUTPUT   RETI
 
         END                            ; End of program

Data transmission via UART

This program describes how to use UART to transmit data. A sequence of numbers (0-255) is transmitted to a PC at 9600 baud rate. The MAX 232 is used as a voltage regulator.

;************************************************************************
;* PROGRAM NAME : UartS.ASM
;* DESCRIPTION: Sends values 0-255 to PC.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(UARTS.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;STACK
         DSEG    AT    03FH
STACK_START:     DS    040H
 
;RESET VECTORS
         CSEG    AT    0
         JMP     XRESET               ; Reset vector
 
         ORG     100H
 
XRESET:  MOV     IE,#00               ; All interrupts are disabled
         MOV     SP,#STACK_START      ; Initialization of Stack pointer
         MOV     TMOD,#20H            ; Timer1 in mode 2
         MOV     TH1,#0FDH            ; 9600 baud rate at the frequency of
                                      ; 11.0592MHz
         MOV     SCON,#40H            ; 8-bit UART
         CLR     TI                   ; Clear transmit bit
         CLR     RI                   ; Clear receive flag
         MOV     R3,#00H              ; Reset caunter
         SETB    TR1                  ; Start Timer 1
 
START:   MOV     SBUF,R3              ; Move number from counter to a PC
LOOP1:   JNB     TI,LOOP1             ; Wait here until byte transmission is
                                      ; complete
         CLR     TI                   ; Clear transmit bit
         INC     R3                   ; Increment the counter value by 1
 
         CJNE    R3,#00H,START        ; If 255 bytes are not sent return to the
                                      ; label START
 
LOOP:    SJMP    LOOP                 ; Remain here
 
         END                          ; End of program

Writing message on LCD display

This example uses the most frequently used type of LCD which displays text in two lines with 16 characters each. In order to save I/O ports, only 4 pins are used for communication here. In this way each byte is transmitted in two steps: first higher then lower nible.

LCD needs to be initialized at the beginning of the program. Besides, parts of the program which repeat in the program create special subroutines. All this may seem extremely complicated, but the whole program basically performs several simple operations and displays ”Mikroelektronika Razvojni sistemi”.

Write message on LCD display
*************************************************************************
;* PROGRAM NAME : Lcd.ASM
;* DESCRIPRTION : Program for testing LCD display. 4-bit communication
;* is used. Program does not check BUSY flag but uses program delay 
;* between 2 commands. PORT1 is used for connection
;* to the microcontroller.
;************************************************************************
 
;BASIC DIRECTIVES
 
$MOD53
$TITLE(LCD.ASM)
$PAGEWIDTH(132)
$DEBUG
$OBJECT
$NOPAGING
 
;Stack
          DSEG     AT     0E0h
Stack_Start:       DS     020h
 
Start_address      EQU    0000h
 
                                             ;Reset vectors
          CSEG     AT     0
          ORG      Start_address
          JMP      Inic
 
          ORG      Start_address+100h
 
          MOV      IE,#00                    ; All interrupts are disabled
          MOV      SP,#Stack_Start
 
Inic:     CALL     LCD_inic                  ; Initialize LCD
 
;*************************************************
;* MAIN PROGRAM
;*************************************************
 
START:    MOV      A,#80h                    ; Next character will appear on the first
          CALL     LCD_status                ; location in the first line of LCD display.
          MOV      A,#'M'                    ; Display character ‘M’.
          CALL     LCD_putc                  ; Call subroutine for character transmission.
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'r'                    ; Display character ‘r’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'l'                    ; Display character ‘l’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'t'                    ; Display character ‘t’.
          CALL     LCD_putc
          MOV      A,#'r'                    ; Display character ‘r’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'n'                    ; Display character ‘n’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'k'                    ; Display character ‘k’.
          CALL     LCD_putc
          MOV      A,#'a'                    ; Display character ‘a’.
          CALL     LCD_putc
 
          MOV      A,#0c0h                   ; Next character will appear on the first
          CALL     LCD_status                ; location in the second line of LCD display.
          MOV      A,#'R'                    ; Display character ‘R’.
          CALL     LCD_putc                  ; Call subroutine for character transmission.
          MOV      A,#'a'                    ; Display character ‘a’.
          CALL     LCD_putc
          MOV      A,#'z'                    ; Display character ‘z’.
          CALL     LCD_putc
          MOV      A,#'v'                    ; Display character ‘v’.
          CALL     LCD_putc
          MOV      A,#'o'                    ; Display character ‘o’.
          CALL     LCD_putc
          MOV      A,#'j'                    ; Display character ‘j’.
          CALL     LCD_putc
          MOV      A,#'n'                    ; Display character ‘n’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#' '                    ; Display character ‘ ’.
          CALL     LCD_putc
          MOV      A,#'s'                    ; Display character ‘s’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
          MOV      A,#'s'                    ; Display character ‘s’.
          CALL     LCD_putc
          MOV      A,#'t'                    ; Display character ‘t’.
          CALL     LCD_putc
          MOV      A,#'e'                    ; Display character ‘e’.
          CALL     LCD_putc
          MOV      A,#'m'                    ; Display character ‘m’.
          CALL     LCD_putc
          MOV      A,#'i'                    ; Display character ‘i’.
          CALL     LCD_putc
 
          MOV      R0,#20d                   ; Wait time (20x10ms)
          CALL     Delay_10ms                ;
          MOV      DPTR,#LCD_DB              ; Clear display
          MOV      A,#6d                     ;
          CALL     LCD_inic_status           ;
          MOV      R0,#10d                   ; Wait time(10x10ms)
          CALL     Delay_10ms
          JMP      START
 
;*********************************************
;* Subroutine for wait time (T= r0 x 10ms)
;*********************************************
 
Delay_10ms:  MOV   R5,00h                    ; 1+(1+(1+2*r7+2)*r6+2)*r5 approximately
             MOV   R6,#100d                  ; (if r7>10)
             MOV   R7,#100d                  ; 2*r5*r6*r7
             DJNZ  R7,$                      ; $ indicates current instruction.
             DJNZ  R6,$-4
             DJNZ  R5,$-6
             RET
 
;**************************************************************************************
;* SUBROUTINE: LCD_inic
;* DESCRIPTION: Subroutine for LCD initialization.
;*
;* (is used with 4-bit interface, under condition that pins DB4-7 on LCD
;* are connected to pins PX.4-7 on microcontroller’s ports, i.e. four higher
;* bits on the port are used).
;*
;* NOTE: It is necessary to define port pins for controlling LCD operation:
;* LCD_enable, LCD_read_write, LCD_reg_select,similar to port for connection to LCD.
;* It is also necessary to define addresses for the first character in each
;* line.
;**************************************************************************************
 
LCD_enable     BIT    P1.3                   ; Bit for activating pin E on LCD.
LCD_read_write BIT    P1.1                   ; Bit for activating pin RW on LCD.
LCD_reg_select BIT    P1.2                   ; Bit for activating pin RS on LCD.
LCD_port       SET    P1                     ; Port for connection to LCD.
Busy           BIT    P1.7                   ; Port pin on which Busy flag appears.
 
LCD_Start_I_red  EQU   00h                   ; Address of the first message character
                                             ; in the first line of LCD display.
LCD_Start_II_red EQU   40h                   ; Address of the first message character
                                             ; in the second line of LCD display.
 
LCD_DB:        DB     00111100b              ; 0 -8b, 2/1 lines, 5x10/5x7 format
               DB     00101100b              ; 1 -4b, 2/1 lines, 5x10/5x7 format
               DB     00011000b              ; 2 -Display/cursor shift, right/left
               DB     00001100b              ; 3 -Display ON, cursor OFF, cursor blink off
               DB     00000110b              ; 4 -Increment mode, display shift off
               DB     00000010b              ; 5 -Display/cursor home
               DB     00000001b              ; 6 -Clear display
               DB     00001000b              ; 7 -Display OFF, cursor OFF, cursor blink off
 
LCD_inic:                                    ;*****************************************
 
               MOV    DPTR,#LCD_DB
 
               MOV    A,#00d                 ; Triple initialization in 8-bit
               CALL  LCD_inic_status_8       ; mode is performed at the beginning
               MOV   A,#00d                  ; (in case of slow increment of
               CALL  LCD_inic_status_8       ; power supply when the power supply is on
               MOV   A,#00d
               lcall LCD_inic_status_8
 
               MOV   A,#1d                   ; Change from 8-bit into
               CALL  LCD_inic_status_8       ; 4-bit mode
               MOV   A,#1d
               CALL  LCD_inic_status
 
               MOV   A,#3d                   ; As from this point the program executes in
                                             ;4-bit mode
               CALL  LCD_inic_status
               MOV   A,#6d
               CALL  LCD_inic_status
               MOV   A,#4d
               CALL  LCD_inic_status
 
               RET
 
LCD_inic_status_8:
                                             ;******************************************
               PUSH  B
 
               MOVC  A,@A+DPTR
               CLR   LCD_reg_select          ; RS=0 - Write command
               CLR   LCD_read_write          ; R/W=0 - Write data on LCD
 
               MOV   B,LCD_port              ; Lower 4 bits from LCD port are memorized
               ORL   B,#11110000b
               ORL   A,#00001111b
               ANL   A,B
 
               MOV   LCD_port,A              ; Data is moved from A to LCD port
               SETB  LCD_enable              ; high-to-low transition signal
                                             ; is generated on the LCD's EN pin
               CLR   LCD_enable               
 
               MOV   B,#255d                 ; Time delay in case of improper reset

               DJNZ  B,$                     ; during initialization
               DJNZ B,$
               DJNZ B,$
 
               POP B
               RET
 
LCD_inic_status:
;****************************************************************************
               MOVC  A,@A+DPTR
               CALL  LCD_status
               RET
 
;****************************************************************************
;* SUBROUTINE: LCD_status
;* DESCRIPTION: Subroutine for defining LCD status.
;****************************************************************************
 
LCD_status:    PUSH  B
               MOV   B,#255d
               DJNZ  B,$
               DJNZ  B,$
               DJNZ  B,$
               CLR   LCD_reg_select          ; RS=O: Command is sent to LCD
               CALL  LCD_port_out
 
               SWAP  A                       ; Nibles are swapped in accumulator
 
               DJNZ  B,$
               DJNZ  B,$
               DJNZ  B,$
               CLR   LCD_reg_select          ; RS=0: Command is sent to LCD
               CALL  LCD_port_out
 
               POP   B
               RET
 
;****************************************************************************
;* SUBROUTINE: LCD_putc
;* DESCRIPTION: Sending character to be displayed on LCD.
;****************************************************************************
 
LCD_putc:      PUSH  B
               MOV   B,#255d
               DJNZ  B,$
               SETB  LCD_reg_select          ; RS=1: Character is sent to LCD
               CALL  LCD_port_out
 
               SWAP  A                       ; Nibles are swapped in accumulator
 
               DJNZ  B,$
               SETB  LCD_reg_select          ; RS=1: Character is sent to LCD
 
               CALL  LCD_port_out
               POP   B
               RET
 
;****************************************************************************
;* SUBROUTINE: LCD_port_out
;* DESCRIPTION: Sending commands or characters on LCD display
;****************************************************************************
 
LCD_port_out:  PUSH  ACC
               PUSH  B
               MOV   B,LCD_port              ; Lower 4 bits of LCD port are memorized
               ORL   B,#11110000b
               ORL   A,#00001111b
               ANL   A,B
 
               MOV   LCD_port,A              ; Data is copied from A to LCD port
 
               SETB  LCD_enable              ; high-to-low transition signal
                                             ; is generated on the LCD's EN pin
               CLR   LCD_enable               
 
               POP   B
               POP   ACC
               RET
 
               END                           ; End of program

Binary to decimal number conversion

When using LED and LCD displays, it is often necessary to convert numbers from binary to decimal. For example, if some register contains a number in binary format that should be displayed on a three digit LED display it is first necessary to convert it to decimal format. In other words, it is necessary to define what should be displayed on the most right display (units), middle display (tens) and most left display (hundreds).

The subroutine below performs conversion of one byte. Binary number is stored in the accumulator, while digits of that number in decimal format are stored in registers R3, R2 and accumulator (units, tens and hundreds, respectively).

;************************************************************************
;* SUBROUTINE NAME : BinDec.ASM
;* DESCRIPTION : Content of accumulator is converted into three decimal digits
;************************************************************************
 
BINDEC:            MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     R3,B           ; Move units to register R3
                   MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     R2,B           ; Move tens to register R2
                   MOV     B,#10d         ; Store decimal number 10 in B
                   DIV     AB             ; A:B. Remainder remains in B
                   MOV     A,B            ; Move hundreds to accumulator
                   RET                    ; Return to the main program

 

  • Mikatech SST 8051 MCU reverse engineer list:
  • SST89Cxx Series read mcu copy protection: SST89C54 SST89C58 SST89C583 SST89C5833 SST89C58RC SST89C59 ...

    SST89Exx Series break mcu copy protection: SST89E516RD SST89E516RD2 SST89E554 SST89E52RC SST89E52RD SST89E52RD2 SST89E54RC SST89E54RD SST89E54RD2 SST89E554RC SST89E564RD SST89E58RD SST89E58RD2 ...

    SST89Vxx Series read mcu copy lockbit protection: SST89V516RD SST89V516RD2 SST89V52RD SST89V52RD2 SST89V54RD2 SST89V554RC SST89V564RD SST89V58RD2...

    SST89VFxx Series break mcu lockbit copy protection: SST39VF1682 SST39VF1681 SST39VF6402B SST39VF6401B SST39VF6402 SST39VF6401 SST39VF3202 SST39VF3201 SST39VF1602 SST39VF1601 ...

 
 
     
 
PCB Copying Service
PCB Projects Overview
PCB Clone
PCB Reverse Engineering
PCB Prototype
PCB Assembly Production
 
 
 
Mcu Hacking Service
Atmel /Analog Mcu Hack
Actel Mcu Attack
Altera Microcontroller Crack
Cygnal Mcu Unlock
Cypress IC Reverse Engineer
Dallas / Elan Mcu Code Extract
Fujitsu Microprocessor Decryption
Freescale IC Code Extraction
Giga Device circuit Hack
Hitachi Mcu Code Extract
Holtek Chip Reverse Engineer
Infineon Microcontroller Dump
Intel Mcu Read Code Protection
ICT Microcontroller Duplication
Lattice Microcontroller Clone
Microchip Source Code Recovery
Motorola Microcontroller Crack
Maxim Mcu Attack
MDT Controller Hack
Megawin Microcontroller Unlock
NEC Mcu Reverse Engineer
NTK Microcontroller Code Extract
Nuvoton Chip Decryption
NXP Semiconductor Code Extraction
Philips integrated circuit Crack
Renesas Microcontroller Dump
ST Processor Reverse Engineer
Silicon Labs Mcu Read Protection
Samsung Mcu Duplication
SST Mcu Clone
Sinowealth Source Code Recovery
SyncMOS Mcu Unlock
Sonix Mcu Read Source Code
STC Microprocessor Code Extract
Tenx Microcontroller Decryption
Texas Instruments MCU Hack
Winbond MCU Code Extraction
Xilinx integrated circuit Crack
Zilog MCU Reverse Engineer
 
     
 
 
More MCU brands we can reverse engineer below, please contact us if yours not listed here:
AMD Feeling LG / Hyundai Myson STK
ChipON Hynix Mitsubishi National Semi Temic
Coreriver ICSI Mosel Vitelic Portek Toshiba
Dallas ISSI MXIC SSSC Gal / Pal / Palce
Copyright © 2013 Mikatech. All rights reserved. Full dedicated reverse engineering company