Sei sulla pagina 1di 16

; 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

Potrebbero piacerti anche