• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Learning 8051

absf

Active Member
I have started my own thread for learning the 8051 using the "MCU 8051 IDE" and ISIS. Instead of sharing a thread with ikelectro, I think this is better so it won't interfere with his progress...

Anyway I have ordered the 89S52 chips from Element 14, and they should be arriving next week if they have the stock. Meanwhile I would just play with the IDE and Proteus.

After reading the instructions set from PDF file uploaded by Ian. I was able to understand a little bit more on the "Addressing Modes"

Here's my first program on stepping the LEDs on Port1 from right to left..

Code:
 ORG 0000H
SJMP START
ORG 30H

start:
setb p2.1 ;SW1 = 1
setb p2.0 ;SW2 = 1

init: mov A,#01 ;Acc =b00000001
mov r0,8 ;r0 is a counter
cpl A ;complement Acc

while: mov p1,A ;LIGHT UP RIGHTMOST LED
acall delay ;FOR A WHILE
rl A ;shift to next LED on the left
djnz r0,while ;done 8 LED?
sjmp init ;start another round
delay:
mov r1,#40h
loop: djnz r1,loop
ret
end
Ian, is there any particular reason that you left a hole between 0000h to 0030h?

Allen
 

Attachments

Last edited:

absf

Active Member
My development board schematic

I have drawn the schematics for my 89S52 development board. It would be constructed on stripboard once the board is layout properly. I'll add a 7805 power supply and the socket for ISP programmer later..

Allen
 

Attachments

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
@Ian, is there any particular reason that you left a hole between 0000h to 0030h?
Yep!! The reset vectors are situated at the beginning of the program code space

Reset = 0x00... ( pin 9) micro boot up... Here we place the jump to main program..
INT0 = 0x03... ( P3.2) External Interrupt 0... Here we place the jump to the INT0 interrupt ( if enabled)
TMR0 = 0x0B.. Timer 0 overflow interrupt.. Here we place the jump to the TMR0 interrupt ( if enabled)
INT1 = 0x13... ( P3.3) External Interrupt 1... Here we place the jump to the INT1 interrupt ( if enabled)
TMR1 = 0x1B.. Timer 1 overflow interrupt.. Here we place the jump to the TMR1 interrupt ( if enabled)
SERIAL = 0x23... Rx and TX interrupts...... Same


Thus I start at 0x30.... just in case....
 

absf

Active Member
Thank you for explaining the vectors used in 8051. For now I have a few questions that I am anxious to know:

1. In the memory map of the 8051, it seems that a single address can be occupied by three (3 may be 4) items.
Using 0090H as an example
i) it can be program code.
ii) it can be address for P1.
iii) it can also be internal Ram if it is 89x52.
iv) If we have external SRAM (say 0000h-7FFFH) , it can also be external RAM address.
So, how can we know that we are accessing ii) to iv). Program code is self explained.

2. I don't see any DDR for the 4 ports. How do I set them if I want to use it as an output or input port?
On power-up, what are the default directions of the ports?

3. Is it true that only R0 and R1 can be used in indirect addressing?

4. When writing an assembly program, do we have to state whether it is AJMP, SJMP or LJMP. Can we just use "JMP" and let the assembler take care of it?

5 If I want to do a "block move" from (40H - 4FH) to (80H - 8FH), How would I do it?
Would the code below work?

Code:
init:    mov   R2, #16
          mov   R0, #40h
          mov   R1, #80h
move:  mov   A, @R0
          mov   @R1, A
          inc      R0
          inc      R1
          djnz    R2, move
          ret
6. How to use the instruction "MOVC" ?

cheers.

Allen
 
Last edited:

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
There is both Ram and Code.

Code is 0 to MAX_CODE... Data is 0 to MAX_DATA..

Also external code can be used MAX_CODE to MAX_EXT_CODE...

Each are addressed differently.. mov... movc.. and movx.

The 8051 doesn't have DDR registers... The port is latched and a small FET is used for input matching YOU must ensure that the port has a "1" written to it before a read is taken..

The other questions are in my reference book at home... They are listed on that PDF I sent you...
 

absf

Active Member
The tutorial you posted is very, very good. I have printed it out and bound it together with the instructions set two days ago. I have read about 30% every night before I went to bed.

It's true that most of the answers to my questions asked are in the tutorial. I'd think it is better for me to ask any new questions after I finished reading the tutorial.

My next project is to wire up a 2-digit 7 segment LED display to the 8051 and use muti-plexing method to count 0-99. I want to learn how to make the 7-segment patterns in the codes without using a 4511/7447 decoder.

Allen
 

absf

Active Member
I have made one digit displaying on the 4 digit multiplexed display. The code is as follows:

Code:
; 2 digit 7 segment counter 00 to 99
; date = 22.04.2013
; phase 1:  display one digit 0-F only
org 0000h
jmp start
org 0030h

sa equ 01h
sb equ 02h
sc equ 04h
sd equ 08h
se equ 10h
sf equ 20h
sg equ 40h
sdp equ 80h

start:
setb p2.0 ;Make 1st digit cathode GND
mov b, #0 ;B reg is counter
mov a, b
call display ;disp content of B
mov p1, a
loop: call delay
inc b ;counter ++
anl b, #0fh ;mask off lower nibble
mov a, b ;move to A to display
call display
mov p1, a ;display it
jmp loop
display:
inc a
movc a,@a+pc ;PC is pointing to address
ret ;after the "ret" instruction
table: db sa+sb+sc+sd+se+sf ; 0
db sb+sc ; 1
db sa+sb+sg+se+sd ; 2
db sa+sb+sc+sd+sg ; 3
db sb+sc+sf+sg ; 4
db sa+sc+sd+sf+sg ; 5
db sa+sc+sd+se+sf+sg ; 6
db sa+sb+sc ; 7
db sa+sb+sc+sd+se+sf+sg ; 8
db sa+sb+sc+sd+sf+sg ; 9
db sa+sb+sc+se+sf+sg ; A
db sc+sd+se+sf+sg ; b
db sa+sd+se+sf ; C
db sb+sc+sd+se+sg ; d
db sa+sd+se+sf+sg ; E
db sa+se+sf+sg ; F
delay:
mov r1,#0A0h
loop1: djnz r1,loop1
ret
end
It took me some time to figure out how to change the display from common Anode to common Cathode. ;)

If I want to display 2 digits. How long do I have to let the digit "ON" before switching to the next digit to have a continuous display? Is 20mS enough to fool our eyes?

Allen
 

Attachments

Last edited:

absf

Active Member
8051 clock speed control

Is it possible to control the clock speed of the 8051 simulator? When I first run the 7-segment program it was very fast and I have to set the delay from 40H to 0A0H, but when I exited and ran it a second time I found that it was very much slowed down and I have to set the delay constant back to 40H to have a normal display.

Allen
 

absf

Active Member
Dual 7 segment display is ready

Code:
; 2 digit 7 segment counter 00 to 99
; date = 22.04.2013
; phase 1:  display one digit 0-F only
; phase 2:  display 2 digits 00-99
;
org 0000h
jmp start
org 0030h

sa equ 01h
sb equ 02h
sc equ 04h
sd equ 08h
se equ 10h
sf equ 20h
sg equ 40h
sdp equ 80h

start: mov dptr,#table
mov r2, #0 ; unit digit
mov r3, #0 ; tenth digit
call display ; display them
repeat:
; call delay
inc r2 ; unit +1
cjne r2,#10,ok
mov r2,#0
inc r3 ; tenth +1
cjne r3,#10,ok
clr a ; clear r2 & r3 to 0
mov r2,a
mov r3,a
ok: call display
jmp repeat
display:
mov b,#10 ; disp counter
disp_loop:
mov a,r2
call show ; show unit digit
setb p3.0 ; ON transistor Q1
call delay_20ms
clr p3.0 ; OFF Q1
mov a,r3
call show ; show tenth digit
setb p3.1 ; ON transistor Q2
call delay_20ms
clr p3.1 ; OFF Q2
djnz b,disp_loop ; loop 50 times
ret
show: movc a,@a+dptr ; get number patter for display
mov p1,a
ret

table: db sa+sb+sc+sd+se+sf ; 0
db sb+sc ; 1
db sa+sb+sg+se+sd ; 2
db sa+sb+sc+sd+sg ; 3
db sb+sc+sf+sg ; 4
db sa+sc+sd+sf+sg ; 5
db sa+sc+sd+se+sf+sg ; 6
db sa+sb+sc ; 7
db sa+sb+sc+sd+se+sf+sg ; 8
db sa+sb+sc+sd+sf+sg ; 9
db sa+sb+sc+se+sf+sg ; A
db sc+sd+se+sf+sg ; b
db sa+sd+se+sf ; C
db sb+sc+sd+se+sg ; d
db sa+sd+se+sf+sg ; E
db sa+se+sf+sg ; F
delay_20ms:
mov r1,#1
loop0: djnz r1,loop0
ret
delay:
mov r1,#040h
loop1: djnz r1,loop1
ret
end
The above code is for dual digit display but the output doesn't look good on simulator. I'll try it on real hardware when my PCB and chip are ready.

I have found a 32x8 SRAM 61256-15 and I wish to interface it to my 8952 board. What are the signals required to interface to this memory chip. Is the external serial flash memory like 24C32 using i2c as fast as the SRAM.

Allen
 

Attachments

Last edited:

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Flash 24c32 are write limited... Its not advisable to use them as Random Access Memory.... You can get SPI Sram ... but the 8051 is geared up to connect to oodles of ram... I have a connection example on my computer at home... I'll post it later.....
 

absf

Active Member
Flash 24c32 are write limited... Its not advisable to use them as Random Access Memory.... You can get SPI Sram ... but the 8051 is geared up to connect to oodles of ram... I have a connection example on my computer at home... I'll post it later.....
Thank you for the info of using SPI sram. But I have never used SPI before so not sure how difficult it would be....

Anyway I have downloaded the datasheet of 23SK256 (32x8) and AN1287 (Using C18/HI-TECH C® Compiler to Interface Serial SRAM Devices to PIC16F/PIC18F Microcontrollers). I'll read it when I am free to see if it suits my project. Actually I am trying to implement the Intel BASIC in 89S52 and store the Basic program in external SRAM. But that would be the last project for me to do.

At the mean time I'd first make my 7-seg display working on timer interrupt on the background; so I can do other things on the foreground. Once the interrupt driven display is working I want to do the multiplication table program as highlighted by ikelectro here:

http://www.electro-tech-online.com/threads/simple-multiplication-of-2-4-6-8.133792/

After that, I would do the 3x4 keyboard (from a telephone) interfacing to display number I pressed on the LED display. Next would be 2x16 LCD interfacing and UART using MAX232 to PC com port.

Allen
 

absf

Active Member
I had to come off the computer last night... So I'll carry on tonight....

SPI is very easy to implement.... And fast...
Thanks, I'll study on it.

I am stuck with my interrupt driven 7-segment display. And this is my approach:

First I'd create a 10mS interrupt using timer 1. And since there are 2 digit to display, I will make them display alternately - 10mS for unit digit and 10mS for tenth digit. In that case I need a single bit variable called 'D_Flag' defined at 20H.0 of the RAM.

On entering the interrupt , it will be toggled. If it is "0", then unit digit would be displayed, and "1" the tenth digit would be displayed. The main loop would be just just incrementing the counter, converting the digits to 7-seg patterns and store it. How does it sound? Would this scheme work?

Here is the ISR code:

Code:
T1_ISR:
PUSH A
PUSH PSW
PUSH DPH
PUSH DPL
clr TR1 ;stop timer1
mov TL1,sav_tl1 ;restore t1
mov TH1,sav_th1
setb TR1 ;start timer1
cpl d_flag ;toggle d_flag
jb d_flag,upper ;1=upper 0=lower
lower: clr p3.0 ;switch off both digits
clr p3.1
mov p1,unit_dig ;get new value
setb p3.0 ;turn on lower digit
sjmp isr_exit
upper: clr p3.0 ;switch off both digits
clr p3.1
mov p1,ten_dig ;get new value
setb p3.1 ;turn on upper digit
isr_exit:
clr TF1 ;clear timer1 flag
POP DPL
POP DPH
POP PSW
POP A
reti
Allen
 
Last edited:

absf

Active Member
Code:
; 2 digit 7 segment counter 00 to 99
; date = 25.04.2013
; phase 1:  display one digit 0-F only
; phase 2:  display 2 digits 00-99
; phase 3:  interrupt driven display.
;
org 00h
jmp start
org 1bh
jmp T1_isr
org 30h

sa equ 01h
sb equ 02h
sc equ 04h
sd equ 08h
se equ 10h
sf equ 20h
sg equ 40h
sdp equ 80h
;
d_flag bit 20h.0 ; disp flag
sav_tl1 equ 80h ; temp for T1L
sav_th1 equ 81h ; temp for T1H
unit_dig equ 82h ; unit digit disp pattern
ten_dig equ 83h ; tenth digit disp pattern
;
start: mov sp,#90h ;init Stack Ptr to 80H
mov DPTR,#TABLE ; dptr = 7 segment table address
mov r2, #0 ; unit digit
mov r3, #0 ; tenth digit
mov TMOD,#0x10 ; set up timer1 for 10mS
mov TL1,#0xf0 ; Mode=1
mov TH1,#0xd8
mov sav_tl1,#0xf0
mov sav_th1,#0xd8
setb tr1 ; start timer1
call display ; display them
repeat:
; call delay
inc r2 ; unit +1
cjne r2,#10,ok ; r2<10 then ok
mov r2,#0 ; else zero it
inc r3 ; tenth +1
cjne r3,#10,ok
clr a ; zero both r2 & r3
mov r2,a
mov r3,a
ok: call display
jmp repeat ; repeat will br my main() loop

display:
mov a,r2
movc a,@a+dptr ; get number patter for display
mov unit_dig,a
mov a,r3
movc a,@a+dptr ; get number patter for display
mov ten_dig,a
ret

[COLOR="#FF0000"]T1_isr:
PUSH A
PUSH PSW
PUSH DPH
PUSH DPL
clr TR1 ;stop timer1
mov TL1,sav_tl1 ;restore t1
mov TH1,sav_th1
setb TR1 ;start timer1
cpl d_flag ;toggle d_flag
jb d_flag,upper ;1=upper 0=lower
lower: clr p3.0 ;switch off both digits
clr p3.1
mov p1,unit_dig ;get new value
setb p3.0 ;turn on lower digit
sjmp isr_exit
upper: clr p3.0 ;switch off both digits
clr p3.1
mov p1,ten_dig ;get new value
setb p3.1 ;turn on upper digit
isr_exit:
clr TF1 ;clear timer1 flag
POP DPL
POP DPH
POP PSW
POP A
reti
[/COLOR]
;
; 7 segment pattern table
;
table: db sa+sb+sc+sd+se+sf ; 0
db sb+sc ; 1
db sa+sb+sg+se+sd ; 2
db sa+sb+sc+sd+sg ; 3
db sb+sc+sf+sg ; 4
db sa+sc+sd+sf+sg ; 5
db sa+sc+sd+se+sf+sg ; 6
db sa+sb+sc ; 7
db sa+sb+sc+sd+se+sf+sg ; 8
db sa+sb+sc+sd+sf+sg ; 9

delay_20ms:
mov r1,#1
loop0: djnz r1,loop0
ret
delay:
mov r1,#040h
loop1: djnz r1,loop1
ret
end
Here is the complete code. It compiles well but crashes after a while . I haven't found out the cause yet ...... Could it be due to my ISR giving the problem?

Ian, how did you get color text inside you code tags ? What trick did you use ?

I'll be on vacation with my family starting tomorrow and will be back on 1st of May. During that time I will not be able to access a PC so unable to visit forum until my vacation is ended. So till then, cheers..

Allen
 
Last edited:

absf

Active Member
I think I just found out the problems in my interrupt driven display codes. I was using the upper 128 bytes 80h-83h in direct addressing mode and I didn't activate the IE register so the ISR never got started.

Here are the corrected codes:

d_flag bit 20h.0 ; disp flag
sav_tl1 equ 30h ; temp for T1L
sav_th1 equ 31h ; temp for T1H
unit_dig equ 32h ; unit digit disp pattern
ten_dig equ 33h ; tenth digit disp pattern

;
start:
mov DPTR,#TABLE ; dptr = 7 segment table address
mov r2, #0 ; unit digit
mov r3, #0 ; tenth digit
mov TMOD,#0x10 ; set up timer1 for 10mS
mov TL1,#0xf0 ; Mode=1
mov TH1,#0xd8
mov sav_tl1,#0xf0
mov sav_th1,#0xd8
setb tr1 ; start timer1
setb et1 ; **enable timer1 interrupt
setb ea ; **enable global interrupt

call display ; display them
But on simulation I found that both the ubit and tenth digits displayed are the same. May be it was due to the simulator was too slow and cannot catch up with the display rate. Anyway I will wire it up on a breadboard to test it on the real hardware.

Allen
 

Attachments

Last edited:

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
You delays are WAY to small.... about 130uS to be precise...

I've uped it a tad.. Its now watchable...
Code:
; 2 digit 7 segment counter 00 to 99
; date = 25.04.2013
; phase 1:  display one digit 0-F only
; phase 2:  display 2 digits 00-99
; phase 3:  interrupt driven display.
;
	org	00h
	jmp	start
	org	1bh
	jmp	T1_isr
	org	30h
 
sa	equ	01h
sb	equ	02h
sc	equ	04h
sd	equ	08h
se	equ	10h
sf	equ	20h
sg	equ	40h
sdp	equ	80h
;
d_flag	bit	20h.0		; disp flag

sav_tl1	equ	30h	 ; temp for T1L
sav_th1	equ	31h	 ; temp for T1H
unit_dig equ	32h	 ; unit digit disp pattern
ten_dig	equ	33h	 ; tenth digit disp pattern

;
start:	mov	sp,#90h		;init Stack Ptr to 80H
	mov	DPTR,#TABLE	; dptr = 7 segment table address
	mov	r2, #0		; unit digit
	mov	r3, #0		; tenth digit
	mov	TMOD,#010h	; set up timer1 for 10mS
	mov	TL1,#0f0h	; Mode=1
	mov	TH1,#0d8h
	mov	sav_tl1,#0f0h	 
	mov	sav_th1,#0d8h
	setb	et1	 	; **enable timer1 interrupt
	setb	ea	 	; **enable global interrupt
	setb	tr1		; start timer1 
	call	display		; display them
repeat:
	call	delay_200ms
	call	delay_200ms
	inc	r2		; unit +1
	cjne	r2,#10,ok	; r2<10 then ok
	mov	r2,#0		; else zero it
	inc	r3		; tenth +1
	cjne	r3,#10,ok
	clr	a		; zero both r2 & r3
	mov	r2,a
	mov	r3,a
ok:	call	display
	jmp	repeat		; repeat will br my main() loop
 
display:
	mov	a,r2
	movc	a,@a+dptr	; get number patter for display
	mov	unit_dig,a
	mov	a,r3
	movc	a,@a+dptr	; get number patter for display
	mov	ten_dig,a
	ret
 
T1_isr:
	PUSH	ACC
	PUSH	PSW
	PUSH	DPH
	PUSH	DPL
	clr	TR1		;stop timer1
	mov	TL1,sav_tl1	;restore t1
	mov	TH1,sav_th1
	setb	TR1		;start timer1
	cpl	d_flag		;toggle d_flag
	jb	d_flag,upper	;1=upper 0=lower
lower:	clr	p3.0		;switch off both digits
	clr	p3.1	
	mov	p1,unit_dig	;get new value
	setb	p3.0		;turn on lower digit
	sjmp	isr_exit
upper:	clr	p3.0		;switch off both digits
	clr	p3.1	
	mov	p1,ten_dig	;get new value
	setb	p3.1		;turn on upper digit
isr_exit:
	clr	TF1		;clear timer1 flag
	POP	DPL
	POP	DPH
	POP	PSW
	POP	ACC
	reti
;
; 7 segment pattern table
;
table:	db	sa+sb+sc+sd+se+sf	; 0  0x3F
	db	sb+sc			; 1  0x06
	db	sa+sb+sg+se+sd		; 2  0x53
	db	sa+sb+sc+sd+sg		; 3  0x4F
	db	sb+sc+sf+sg		; 4  0x66
	db	sa+sc+sd+sf+sg		; 5  0x6D
	db	sa+sc+sd+se+sf+sg	; 6  0x7D
	db	sa+sb+sc		; 7  0x07
	db	sa+sb+sc+sd+se+sf+sg	; 8  0x7F
	db	sa+sb+sc+sd+sf+sg	; 9  0x6F

delay_200ms: 
	mov	r1,#0ffh
	sjmp	delay

delay_20ms:
	mov	r1,#1
loop0:	djnz	r1,loop0
	ret
delay:
loop2:	mov	r1,#04Fh
loop1:	djnz	r1,loop1
	djnz	r5,loop1
	ret
	end
 

absf

Active Member
Ian, thanks for the fine tuning of my code. I just simulated it again and it displays perfectly.

Thanks again for helping. My next project would be to let it do the multiplication tables as I have mentioned in my previous post. I want to learn how to use the "MULT" and "DIV" instructions.

BTW, how would I access the the RAM above 0x7F? Do I have to use R0 and R1 in mov A,@Ri to access that area of RAM? That would be very troublesome and would take a lot of instruction cycles in order to access on those RAM locations.

Allen
 

Attachments

Latest threads

EE World Online Articles

Loading

 
Top