; SIMPLE MULTITASKING PROGRAM
$MOD51
$NOPRINT
$INCLUDE(MYPAULM2.EQU)
LED equ P1.7
CR EQU 13
DSEG AT 20H
DS 1
FLAG1:
TICK:
SEC:
MIN:
HOUR:
TIMER1:
TIMER2:
TIMER3:
TIMER4:
COMMAND:
DS
DS
DS
DS
DS
DS
DS
DS
DS
1
1
1
1
1
1
1
1
1
CSEG AT 8000H
jmp main
ORG 8100H
; 10ms tick
; ____|____|____|____|____
;
WAIT_TICK:
JNB TF0,$
CLR TF0
ORL TH0,#0DCH
INC TICK
RET
UPDATE_CLOCK:
MOV A,TICK
CJNE A,#100,EXIT_CLOCK
MOV TICK,#0
SETB FLAG1.0
SETB FLAG1.1
; flag that signals print time function
; for tick led
MOV A,SEC
ADD A,#1
DA A
MOV SEC,A
CJNE A,#60H,EXIT_CLOCK
MOV SEC,#0
MOV A,MIN
ADD A,#1
DA A
MOV MIN,A
CJNE A,#60H,EXIT_CLOCK
MOV MIN,#0
MOV A,HOUR
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,EXIT_CLOCK
MOV HOUR,#0
EXIT_CLOCK:
RET
; MAKE LED ON EVERY ONE SECOND
; ------______------------------------------______----------------;
|50ms|
;
|-------------------- 1000ms -------|
;
TICK_LED:
JNB FLAG1.1,EXIT1
CLR LED
INC TIMER1
MOV A,TIMER1
CJNE A,#5,EXIT1
SETB LED
CLR FLAG1.1
MOV TIMER1,#0
EXIT1:
RET
; check serial port every 10ms
; exit: COMMAND == -1 NO CHARACTER
;
COMMAND != -1 ASCII CODE
GETCHAR:
JNB
CLR
MOV
MOV
RET
EXIT2:
RI,EXIT2
RI
A,SBUF
COMMAND,A
MOV COMMAND,#-1
RET
; PRINT TIME TO TERMINAL EVERY SECOND
PRINT_TIME:
JNB FLAG1.0,EXIT_PRINT_TIME
CLR FLAG1.0
PRINT_TIME1:
MOV A,#CR
CALL COUT
MOV A,HOUR
CALL PHEX
MOV A,#':'
CALL COUT
MOV A,MIN
CALL PHEX
MOV A,#':'
CALL COUT
MOV A,SEC
CALL PHEX
EXIT_PRINT_TIME:
RET
HOUR_KEY:
MOV A,COMMAND
CJNE A,#'h',EXIT_HOUR_KEY
MOV A,HOUR
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,SKIP_CLEAR_HOUR
MOV HOUR,#0
SKIP_CLEAR_HOUR:
CALL PRINT_TIME1
EXIT_HOUR_KEY:
RET
MIN_KEY:
MOV A,COMMAND
CJNE A,#'m',EXIT_MIN_KEY
MOV A,MIN
ADD A,#1
DA A
MOV MIN,A
CJNE A,#60H,SKIP_CLEAR_MIN
MOV MIN,#0
SKIP_CLEAR_MIN:
CALL PRINT_TIME1
EXIT_MIN_KEY:
RET
;*************************** MAIN ***************************
main:
ORL TMOD,#1
SETB TR0
MOV SEC,#0
MOV MIN,#55H
MOV HOUR,#17H
MOV TICK,#0
CALL NEWLINE
; main 10ms loop
LOOP:
CALL WAIT_TICK
; following tasks will be executed every 10ms
CALL TICK_LED
CALL UPDATE_CLOCK
CALL GETCHAR
CALL PRINT_TIME
CALL HOUR_KEY
CALL MIN_KEY
JMP LOOP
END
>>>>>>>>>>>>week7:
; SIMPLE MULTITASKING PROGRAM
$MOD51
$NOPRINT
$INCLUDE(MYPAULM2.EQU)
LED equ P1.7
CR EQU 13
GPIO2 equ 200H ; 8-bit input port
DSEG AT 20H
DS 1
FLAG1:
TICK:
SEC:
MIN:
HOUR:
TIMER1:
TIMER2:
TIMER3:
TIMER4:
COMMAND:
DS
DS
DS
DS
DS
DS
DS
DS
DS
1
1
1
1
1
1
1
1
1
CSEG AT 8000H
jmp main
ORG 8100H
; 10ms tick
; ____|____|____|____|____
;
WAIT_TICK:
JNB TF0,$
CLR TF0
ORL TH0,#0DCH
INC TICK
RET
UPDATE_CLOCK:
MOV A,TICK
CJNE A,#100,EXIT_CLOCK
MOV TICK,#0
SETB FLAG1.0
SETB FLAG1.1
SETB FLAG1.2
; flag that signals print time function
; for tick led
; signals print lcd function
MOV A,SEC
ADD A,#1
DA A
MOV SEC,A
CJNE A,#60H,EXIT_CLOCK
MOV SEC,#0
MOV A,MIN
ADD A,#1
DA A
MOV MIN,A
CJNE A,#60H,EXIT_CLOCK
MOV MIN,#0
MOV A,HOUR
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,EXIT_CLOCK
MOV HOUR,#0
EXIT_CLOCK:
RET
; MAKE LED ON EVERY ONE SECOND
; ------______------------------------------______----------------;
|50ms|
;
|-------------------- 1000ms -------|
;
TICK_LED:
JNB
CLR
INC
MOV
FLAG1.1,EXIT1
LED
TIMER1
A,TIMER1
CJNE A,#5,EXIT1
SETB LED
CLR FLAG1.1
MOV TIMER1,#0
EXIT1:
RET
; check serial port every 10ms
; exit: COMMAND == -1 NO CHARACTER
;
COMMAND != -1 ASCII CODE
GETCHAR:
JNB
CLR
MOV
MOV
RET
EXIT2:
RI,EXIT2
RI
A,SBUF
COMMAND,A
MOV COMMAND,#-1
RET
; PRINT TIME TO TERMINAL EVERY SECOND
PRINT_TIME:
JNB FLAG1.0,EXIT_PRINT_TIME
CLR FLAG1.0
PRINT_TIME1:
MOV A,#CR
CALL COUT
MOV A,HOUR
CALL PHEX
MOV A,#':'
CALL COUT
MOV A,MIN
CALL PHEX
MOV A,#':'
CALL COUT
MOV A,SEC
CALL PHEX
EXIT_PRINT_TIME:
RET
HOUR_KEY:
MOV A,COMMAND
CJNE A,#'h',EXIT_HOUR_KEY
MOV A,HOUR
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,SKIP_CLEAR_HOUR
MOV HOUR,#0
SKIP_CLEAR_HOUR:
CALL PRINT_TIME1
EXIT_HOUR_KEY:
RET
MIN_KEY:
MOV A,COMMAND
CJNE A,#'m',EXIT_MIN_KEY
MOV A,MIN
ADD A,#1
DA A
MOV MIN,A
CJNE A,#60H,SKIP_CLEAR_MIN
MOV MIN,#0
SKIP_CLEAR_MIN:
CALL PRINT_TIME1
EXIT_MIN_KEY:
RET
; PRINT BYTE TO LCD
; INPUT BYTE MUST BE TWO DIGITS BCD NUMBER
PRINT_BYTE: PUSH ACC
ANL A,#0F0H
SWAP A
ADD A,#'0'
CALL PUTCH_LCD
POP ACC
ANL A,#0FH
ADD A,#'0'
CALL PUTCH_LCD
RET
PRINT_TIME_LCD:
JNB FLAG1.2, EXIT_PRINT_LCD
CLR FLAG1.2
PRINT_TIME_LCD1:
MOV A,#00H
MOV B,#00H
CALL goto_xy
MOV A,HOUR
CALL PRINT_BYTE
MOV A,#':'
CALL PUTCH_LCD
MOV A,MIN
CALL PRINT_BYTE
MOV A,#':'
CALL PUTCH_LCD
; A = X
; B = Y
MOV A,SEC
CALL PRINT_BYTE
EXIT_PRINT_LCD:
RET
READ_KEY: MOV DPTR,#GPIO2
MOVX A,@DPTR
JB ACC.4, CHECK_NEXT_KEY
MOV A,#1
RET
CHECK_NEXT_KEY:
JB ACC.5, EXIT_CHECK_KEY
MOV A,#2
RET
EXIT_CHECK_KEY:
MOV A,#-1
RET
EXE_KEY:
CALL READ_KEY
CJNE A,#1,EXE_KEY2
MOV A,HOUR
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,SKIP_CLEAR_HOUR1
MOV HOUR,#0
SKIP_CLEAR_HOUR1:
CALL PRINT_TIME_LCD1
EXIT_HOUR_KEY1:
RET
EXE_KEY2: CJNE A,#2,EXIT_KEY2
MOV A,MIN
ADD A,#1
DA A
MOV MIN,A
CJNE A,#60H,SKIP_CLEAR_MIN1
MOV MIN,#0
SKIP_CLEAR_MIN1:
CALL PRINT_TIME_LCD1
EXIT_KEY2:
RET
SCAN_KEY: INC TIMER2
MOV A,TIMER2
CJNE A,#20,EXIT_SCAN
; 200ms
MOV TIMER2,#0
CALL EXE_KEY
EXIT_SCAN: RET
;*************************** MAIN ***************************
main:
ORL TMOD,#1
SETB TR0
MOV SEC,#0
MOV MIN,#55H
MOV HOUR,#17H
MOV TICK,#0
CALL NEWLINE
CALL INITLCD
; main 10ms loop
LOOP:
CALL WAIT_TICK
; following tasks will be executed every 10ms
CALL TICK_LED
CALL UPDATE_CLOCK
CALL GETCHAR
CALL PRINT_TIME
CALL HOUR_KEY
CALL MIN_KEY
CALL PRINT_TIME_LCD
CALL SCAN_KEY
JMP LOOP
$include(lcddrv.asm)
END
>>>>>>>>>>>.
; LCD driver for 8051SBC
BUSY
EQU 80H
; below LCD's registers are mapped into external data memory
command_write
data_write
command_read
data_read
EQU
EQU
EQU
EQU
0000H
0001H
0002H
0003H
CSEG
; wait until LCD ready bit set
LcdReady:
?ready:
PUSH ACC
MOV DPTR,#command_read
MOVX A,@DPTR
JB ACC.7,?ready
; loop if busy flag = 1
POP ACC
RET
LCD_command_write: CALL LcdReady
MOV DPTR,#command_write
MOVX @DPTR,A
RET
LCD_data_write: PUSH DPL
PUSH DPH
CALL LcdReady
MOV DPTR,#data_write
MOVX @DPTR,A
POP DPH
POP DPL
RET
clr_screen:
CALL LcdReady
MOV A,#1
CALL LCD_command_write
RET
InitLcd:
MOV A,#38H
CALL LCD_command_write
MOV A,#0CH
CALL LCD_command_write
CALL clr_screen
MOV A,#00H
; A = X
MOV B,#00H
; B = Y
CALL goto_xy
RET
; goto_xy(x,y)
; entry: A = y position
;
B = x position
goto_xy:
CJNE A,#0,case1
MOV A,B
ADD A,#80H
CALL LCD_command_write
RET
case1:
CJNE A,#1,case2
MOV A,B
ADD A,#0C0H
CALL LCD_command_write
RET
case2:
RET
; send_string
; entry: DPTR
send_string:
MOVX A,@DPTR
CJNE A,#0,send_string1
send_string1:
RET
CALL LCD_data_write
INC DPTR
JMP send_string
; write ASCII code to LCD at current position
; entry: A
putch_lcd:
CALL LcdReady
CALL LCD_data_write
RET
>>>>>>>>>>>>>>>
After you have understood the tutorialon Introduction to assembly language which includes simple
instruction sets like input/output operations, now its time to learn how to create loops, function calls
and jumps while writing a code in assembly language.
Let us first discuss an important concept that relates RAM & ROM. You can skip this section if you wish
but it is an important to understand registers which helps in building up understanding of architecture
of microcontrollers.
How a program which is burned in ROM gets executed in RAM?
The program you write is burned in ROM and this program is executed in RAM. The data burned is in
the form of logics or binary digits (0 & 1) also called an Opcode or machine code. The programwritten
in assembly language is converted to opcode by assembler.
Each line of the assembly code is assigned a unique opcode by the assembler as shown below. These
opcodes are then stored in ROM one after another. There is a register called Program Counter
(PC) which always points to the current opcode being executed. When the power is switched on it sets
itself to zero and it keeps on incrementing itself as opcodes are executed one after another.
Thisinformation is used by RAM to extract correct opcode from ROM which is then executed. This
process goes on line by line till the whole program is executed.
Lets take an example:PC
Mnemonic, Operand
0000
ORG
0H
0000
MOV
R0, #0
0002
MOV
A, #55H
0004
JZ
0006
0007
AGAIN:
0008
0009
7800
7455
6003
INC
R0
08
INC
04
INC
04
ADD
A, #77H
000B
JNC
OVER
5005
000D
CLR
E4
000E
MOV
R0, A
F8
000F
MOV
R1, A
F9
0010
MOV
R2, A
FA
0011
MOV
R3, A
FB
ADD,
R3
2B
JNC
AGAIN
50F2
0012
NEXT:
NEXT
Opcode (Machine code)
OVER:
0013
0015
HERE:
0017
SJMP
HERE
2477
80FE
END
We can clearly see that the PC increases with execution of program. The PC starts with zero when
ORG 00H line is executed and then in subsequent lines PC keeps on incrementing as machine codes
are executed one after another.
Program Counter is a 2 byte or 16 bit register. Therefore we cannot have internal ROM of more than
the number this register can hold (i.e. not exceeding the FFFF hex value).
LOOP AND JUMP INSTRUCTIONS
Let us start with a simple example that will help you to learn how to create loops in assembly. In the
following code the instruction DJNZ is used to reduce the counter and is repeated till the counter
becomes zero.
Eg-1:
AGAIN:
ORG
0H
MOV
A, #0
; clear A
MOV
R1, #10
; load counter R1 =10
ADD
A, # 05
; add five to register A
DJNZ
R1, AGAIN
; repeat until R1=0 (10 times)
MOV
R3, A
; save A in R3
END
In this code R1 acts as a counter. The counter value is initialized i.e. 10 HEX is loaded to R1. In each
iteration, the instruction DJNZ decrements R1 by one until it becomes zero. This loop adds 5 HEX to A
every time it runs. After ten iterations R1 becomes zero and the instructions below it are executed.
Note: - Some Jump statements can only be performed on some special register A (or bit CY) as
mentioned in the table below.
Nested loops:
ORG 0H
MOV
A, #55H
; A= 55 hex
MOV
R1, #100
; the outer counter R1 =100
NEXT:
MOV
R2, # 20
; the inner counter
AGAIN:
CPL
A, # 05
; add five to register A
DJNZ
R2, AGAIN
; repeat until R1=0 (100 times)
DJNZ
R1, NEXT
; repeat till 20 times (outer loop)
END
SJMP refers to short jump and LJMP refers to long jump. All the conditional jumps are short jumps.
SJMP: This instruction is of two bytes in which first one is opcode & second is the address. The
relative address of the instruction called should be in between -127 to 127 bytes from the
currentprogram counter (PC).
LJMP: This instruction is of three bytes in which the first is the opcode and the second & third are for
address. The relative address of the instruction can be anywhere on the ROM.
So it is clear from the above examples that we can use different jump instructions with a
condition or counter called conditional loop. And when we create loop inside an existing
loop it is called nested loop.
CALL INSTRUCTIONS:
Example:
LCALL (long call)
ORG
BACK :
0H
MOV
A, #55H
; load A= 55 hex value
MOV
P1, A
; issue value of register A to port1
LCALL DELAY
; to call DELAY function created below
MOV A, #0AAH
;load AAH hex value to A
MOV P1,A
;issue value of register A to port 1
LCALL
DELAY
SJMP
BACK
; to call DELAY function as created below
; keep doing this
; ________ this is the delay subroutine
DELAY:
MOV
AGAIN:
DJNZ
RET
R5, #0FFH
R5, AGAIN
; R5= 255 hex, the counter
; stay here until R5 becomes zero
; return to caller
END
In this code we keep on toggling the value of the register of port 1 with two different hex values and a
DELAY subroutine is used to control how fast the value is changing. Here in DELAY subroutine
theprogram is kept busy by running an idle loop and counting 256 counts. After the DELAY subroutine
is executed once the value of port 1 is toggled and this process goes on infinitely.
By using DELAY we can create PWM (Pulse Width Modulation) to control motors or LED blinking for
further details view our tutorial on Input/ output instructions in Assembly Language[coming soon].
We can also use ACALL i.e. absolute call for calling a subroutine that is within 2K byte of PC.
http://www.botskool.com/tutorials/electronics/8051/input-output-instructions-8051assembly-language
http://www.botskool.com/tutorials/electronics/8051/input-output-instructions-8051assembly-language
http://www.hobbyprojects.com/8051_tutorial/
http://www.docstoc.com/docs/112797230/8051-Tutorial-en#
Code ASM 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[collapse]
org 0000h
sjmp start
org 0050h
start:
mov a,#00h
setb p0.0
x:jnb p1.0,is1
jnb p1.1,ds2
cjne a,#00h,x11
sjmp x
x11:
clr p0.0
mov r2,a
x1: lcall delay
djnz r2,x1
setb p0.0
mov r1,a
mov a,#64h
subb a,r1 ; a = a - r1
mov r2,a
; result into r2 reg
mov a,r1 ; a old value from r1
x12:
lcall delay
djnz r2,x12
sjmp x
is1:
add a,#10h
loop: jnb p1.0,loop
sjmp x11
ds2:
subb a,#10h
loop1: jnb p1.1,loop1
Code ASM 38
39
40
41
42
43
44
[collapse]
sjmp x11
delay:
mov r3,#0ffh
q:djnz r3,q
ret
end