1. 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.
    Dismiss Notice

Learning 8051

Discussion in '8051/8951' started by absf, Apr 17, 2013.

  1. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,170
    Likes:
    910
    Location:
    Rochdale UK
    ONLINE
    You use the DPTR to access RAM... Its 16bits wide

    Code (ASM):
    mov DPTR, memory_location
    mov a,a@DPTR
    You have already used this in your code...
     
    • Like Like x 1
  2. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA
    DPTR is primarily used for accessing external RAM with the movx instruction. Also, it can be used for table reads with the movc instruction (movc a,@a + DPTR). In this case, DPTR would hold the 16-bit address that is the first line of the table while A would hold the line of the table that you wish to read.

    Example...if DPTR contained address 0xCF51 and A contained 0x1F, the above instruction would read line 31 of a table that starts at code address 0xCF51.

    R0 and R1 can be used as indirect pointers for internal RAM.

    Code (text):

    ;write accumulator to external RAM

                  movx          @DPTR,A

    ;write external RAM to accumulator

                  movx          A,@DPTR
     
    • Like Like x 1
  3. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Thanks, Ian and Jon.

    Now I know there are 3 ways to access the 128 bytes of upper RAM in 8052. I'll write a short program to do a block move from $80-$BF to $C0-$FF using the 8051 IDE and see how it works.

    cheers.

    Allen
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA

    The 128 upper bytes of internal RAM is accessed via indirect addressing -

    Code (text):

                       mov         R0,#0x80
                       mov         A,@R0               ;write value stored in address that is stored in R0 to accumulator

    or

                       mov          @R0,A              ;write value in accumulator to address stored in R0
     
    The above code will access upper RAM region 0x80, or location 128. You can also write to the upper RAM region using the stack as well by moving the stack pointer to the location you wish to write to, then store a value in the accumulator, then push the accumulator onto the stack -

    Code (text):

                     mov            SP,#0x7F
                     mov            A, <DATA>
                     push           ACC
     
    The stack pointer is incremented before the value is written to the address in the stack pointer when a push instruction is executed. This means you would write the address - 1 to the stack pointer prior to pushing the stack. The above code will access location 0x80.

    In most of my 8052 code, I use the upper 128 region as the stack. The first instruction in all of my code is mov SP,#0x7F. This gets the stack pointer out of the R register space. The upper 128 is then used as a 128 byte stack, while I use the lower 128 for all of my variable processing.
     
    • Like Like x 1
  6. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Normally I wouldn't mess around storing my data on the stack using it as a temporary storage. But I have seen subroutines using the stack for storing ASC messages for printing, something like this:

    Code (asm):
    HELLO:
         call  prt_mess
         DB   'HELLO, WORLD',00
          ...................
    prt_mess:
         pop   Acc
         mov  dpl, Acc          
         pop   Acc
         mov   dph, Acc
         print the message after CALL
         ..................
         mov  Acc, dph
         push  reg          ;restore return address
         mov  Acc, dpj
         push  reg
         ret
     
    I would come to this later... And here's my block move program:

    Code (asm):
    ; Internal RAM testing using indirect addressing
    ; start date = 5.05.2013
    ;
    ; phase 1:  initial program.
    ; block move from $80-$bf to $c0-$ff
    ; first fill up $80-$bf with 00-3f
    ;
    org 00h
    jmp start
    org 30h

    source equ R0
    dest equ R1
    ;
    start:
    ; fill $80-$BF with numbers 00-#F
    mov source, #0x80 ; source address
    mov B,#0x40 ; 64 bytes to fill
    mov A,#00 ; start number
    next: mov @R0,A ; write Acc to source RAM
    inc A ; A=A+1
    inc source ; R0=R0+1
    djnz B,next ; Do it 64 times
    ;Block move
    mov source, #0x80 ; source address
    mov dest, #0xC0 ; destination address
    mov B,#0x40 ; number of bytes to move

    repeat: mov A,@R0
    mov @R1,A
    inc source
    inc dest
    djnz b,repeat
    here: jmp here ; stop here

    end
     
    Allen
     
    Last edited: Oct 12, 2013
  7. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    I attach here with the circuit for doing multiplication.

    The DIP switches on P2.0-P2.3 are used for the multiplier in binary format. The button at P2.7 is used to step the multiplicand from 2 - 16. For each push of the button, the multiplicand would increment by 1.

    The result is displayed on the 7-segment LED. If the result is greater than 99, it would stop. I am not sure if a reset button is needed. I would know this once I complete the flowchart.
     

    Attached Files:

    Last edited: May 4, 2013
  8. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Comparing Numbers

    I have problems comparing numbers....

    Let's say Acc = #90, and I am comparing Acc with #X. When Acc <> #X, a CJNE instruction would be able to test that.

    But how do I test if 1) Acc >= #X, 2) Acc > #X, 3) Acc =< #X , 4) Acc < #X ?

    There is no Zero flag on the PSW and what's the use of OV flag and P flag? Do I need to do a SUBB A,#X before comparison?

    Do I need to clear the Carry flag before doing a subtraction?

    Thanks

    Allen
     
  9. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,170
    Likes:
    910
    Location:
    Rochdale UK
    ONLINE
    You have some instructions

    JNZ... jump not zero
    JZ.... jump if zero
    DJNZ.. decrease and jump not zero

    should be enough..
     
  10. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    I have some codes from one of my books:

    Code (asm):

    FCTL: SETB KYF ;SET KEY FLG
    CJNE A,#20H,$+3 ;A<20H ?
    JC FCTL1 ;YES
    CJNE A,#7FH,$+3 ;A<7FH ?
    JNC FCTL1 ;NO
    CLR KYF
    FCTL1: RET
     
    Does it mean that after failing the CJNE test, Acc can be "=20H" or <20H ?
    The JC is to make sure that it is actually "<20H", right?

    Allen
     
    Last edited: Oct 12, 2013
  11. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA
    No...cjne means -

    "Compare,Jump if Not Equal"

    The values within the two registers being compared do not change. What happens is that if the values within the two registers are not equal, the program counter will jump to the address that is present in the 3rd operand (compare, jump if NOT equal). However, if they are equal, the jump will not happen and the program counter continues on as if the jump never existed.
     
  12. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    You're absolutely right about the CJNE instruction. I simulated the program I attached on the IDE with all sort of values for "Acc" and now I have a clearer picture of how the instruction works. Thanks.

    Still struggling with my multiplication program due to lack of time this week.

    cheers.

    Allen
     
  13. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA
    Do you not know about the "mul" instruction?

    You place the two values to be multiplied in the A (accumulator, or ACC) and B registers. Then you execute "mul AB". Once this instruction executes, the A register contains the low order byte of the 16-bit result while the B register contains the high order byte of the 16-bit result.

    Example, if the result of a mul AB instruction is 0xC5D9, the A register will contain the value of 0xD9 while the B register will contain the value of 0xC5.

    Hope this helps.
     
  14. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Thanks for the info. The "MUL" instruction is the easy part. As I discard the the Product High and only use the product Low in Acc. The difficulty is that I need to convert the Binary in Acc to BCD and then to 7 segments form for displaying. I was almost there and I need a little more time for the final tunning. Looks like the easiest way to do BIN2BCD conversion is to use the "DIV" instruction.

    I'll list it here ASAP when I have it ready.

    Next I would include a 32x8 SRAM interface to the 8051 P0 & P2 using 74HC573. My 89S52 just arrived yesterday and I am busy working on the PCB.

    Allen
     
    Last edited: May 8, 2013
  15. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA
    I'm working up a code example for you right now. Is your segment display common cathode or common anode?
     
  16. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Thanks for helping. They are common cathode display as in the schematic attached.

    Allen
     

    Attached Files:

  17. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    859
    Likes:
    82
    Location:
    Fresno, CA
    OK...this code does not contain anything that will drive the display yet. But what it does do is convert a value that is in the accumulator (ACC) to BCD, stores the 3 BCD bytes in registers HUND, TEN and ONE for the hundreds, tens and ones place digits, then converts them to LED display segment data and stores the segment pattern data for each digit in registers HUND, TEN and ONE. You will see that a look up table for the segment data was used to convert BCD to segment data, while the BCD values were used to call the appropriate table line for each digit's segment pattern data -

    Code (text):

           
           
    HUND        DATA        0x30            ;hundreds place digit register
    TEN     DATA        0x31            ;tens place digit register
    ONE     DATA        0x32            ;ones place digit register

            org     0x0000          ;reset vector
            ajmp        START           ;jump to start of main code
           
           
    ;this space reserved for IRQ space


            org     0x0100          ;main code starts past IRQ space
    START:      mov     A,#0xFF         ;place value to convert to BCD in A
            acall       BIN2BCD         ;convert to BCD using this routine
            acall       LEDSegFetch     ;convert to LED segment data using this routine
            ajmp        $           ;replace this line with rest of your code
           
           
    ;*************************************************************************************************
    ;*************************************************************************************************
    ;**                                             **
    ;**             LED Segment Pattern Fetch                   **
    ;**                                             **
    ;*************************************************************************************************
    ;*************************************************************************************************

    ;The following function takes the BCD values in registers HUND, TEN and ONE, and replaces
    ;them with table values that will light up the LED segments in the correct digit pattern
    ;that matches the replaced BCD value. After this code execution completes, the segment patterns
    ;will be stored in registers HUND, TEN and ONE -

    ;HUND - Contains segment data for hundreds place digit
    ;TEN - Contains segment data for tens place digit
    ;ONE - Contains segment data for ones place digit
           
    LEDSegFetch:    mov     DPTR,#CCDisplay     ;DPTR to first line of table
            mov     A,HUND          ;fetch BCD value from HUND, place in accumulator
            movc        A,@A+DPTR       ;fetch LED pattern from table line number in A
            mov     HUND,A          ;store in HUND, replacing original BCD value
            mov     A,TEN           ;fetch BCD value from TEN, place in accumulator
            movc        A,@A+DPTR       ;fetch LED pattern from table line number in A
            mov     TEN,A           ;store in TEN, replacing original BCD value
            mov     A,ONE           ;fetch BCD value from ONE, place in accumulator
            movc        A,@A+DPTR       ;fetch LED pattern from table line number in A
            mov     ONE,A           ;store in ONE, replacing original BCD value
            ret                 ;done
                   
    ;*************************************************************************************************
    ;*************************************************************************************************
    ;**                                             **
    ;**             8-bit Binary to BCD Converter                   **
    ;**                                             **
    ;*************************************************************************************************
    ;*************************************************************************************************

    ;The following subroutine converts a single byte into 3 binary coded decimal bytes, and
    ;stores them into buffer registers in RAM.
           
    BIN2BCD:    mov     B,#0x64         ;divisor = 100
            div     AB          ;divide value in accumulator by 100
            mov     HUND,A          ;store integer in HUND register
            mov     A,B         ;transfer remainder to accumulator
            mov     B,#0x0A         ;divisor = 10
            div     AB          ;divide value in accumulator by 10
            mov     TEN,A           ;store integer in TEN register
            mov     ONE,B           ;store remainder in ONE register
            ret                 ;done
           
    ;*************************************************************************************************
    ;*************************************************************************************************
    ;**                                             **
    ;**         Common Cathode 7-Segment LED Display Patterns               **
    ;**                                             **
    ;*************************************************************************************************
    ;*************************************************************************************************

    ;The following look up table holds the binary patterns to light up the segments of a
    ;7 segment LED display in a pattern which resembles digits.
           
    CCDisplay:  db      00111111b       ;0
            db      00000110b       ;1
            db      01011011b       ;2
            db      01001111b       ;3
            db      01100110b       ;4
            db      01101101b       ;5
            db      01111101b       ;6
            db      00000111b       ;7
            db      01111111b       ;8
            db      01101111b       ;9

            end
           
           
    Read through all of my comments and all should become clear. You can then transfer the data in registers HUND, TEN and ONE out to the port that drives the segment display to display the digits.
     
    Last edited: May 9, 2013
    • Like Like x 1
  18. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,170
    Likes:
    910
    Location:
    Rochdale UK
    ONLINE
    Well documented code John!! Thanks for chipping in.

    Cheers.
     
  19. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Wow, that was really quick. I inserted your codes for BIN2BCD into the IDE and assembled and tested it in ISIS and it worked well.

    Thanks so much for the code and that was a very good style of writing programs which I should learn how to do it in future....

    Anyway, the complete code is attached as below:

    Code (asm):
    ; Multiplication Table x2 to x9
    ; Max output is Decimal 99
    ;
    ; start date = 5.05.2013
    ; phase 1:  Make use of the 7 seg display routine
    ; phase 2:  initial trial 6.05.2013
    ; phase 3:  tested with John's "MULT codes" on 10.05.2013
    ;
    org 00h
    jmp start
    org 1bh
    jmp T1_isr
    org 100h

    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
    ovf bit 20h.2 ; overflow flag
    button bit p2.7 ; button
    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
    m_cand equ 34h ; multiplicand
    product equ 35h

    unit equ R2 ; unit digit
    tenth equ R3 ; tenth digit
    hund equ R4
    ;
    start:
    mov SP,#0x80 ; move stack to upper RAM 0x80
    call init
    call display ; display them
    nxt_num:
    mov M_cand,#01 ; init multiplicand
    but_loop:
    call delay_200ms ; debounce button
    jb button,but_loop ; button not pressed, loop
    call mult ; do multiplication
    call chk_product ; check if product out of range
    jb ovf,nxt_num ; O.O.R. goto next number
    call bin2BCD ; convert binary to BCD
    call display ; convert to 7S pattern
    call delay_200ms
    call delay_200ms
    jmp but_loop ; wait for next button press

    mult: mov a,p2 ; get multiplier
    anl a,#0x0f ; mask of upper nibble
    mov b,m_cand ; get multiplicand
    mul ab ; do the multiplication
    mov product,a ; discard MSB byte
    inc m_cand ; multiplicand +1
    ret ; Acc is LSB of product
    chk_product:
    clr ovf ; clear overflow flag
    mov a,product
    cjne a,#99,$+3 ; Is product <100?
    jc chk_exit ; yes
    setb ovf ; set over flow flag
    chk_exit: ret

    BIN2BCD:
    mov B,#0x64 ;divisor = 100
    div AB ;divide value in accumulator by 100
    mov HUND,A ;store integer in HUND register
    mov A,B ;transfer remainder to accumulator
    mov B,#0x0A ;divisor = 10
    div AB ;divide value in accumulator by 10
    mov TENTH,A ;store integer in TEN register
    mov UNIT,B ;store remainder in ONE register
    ret ;done

    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

    init:
    mov DPTR,#TABLE ; dptr = 7 segment table address
    mov unit, #0 ; unit digit
    mov tenth, #0 ; tenth digit
    mov TMOD,#0x10 ; set up timer1 for 10mS
    mov TL1,#0xf0 ; Mode=1
    mov TH1,#0xd8 ; 0xD8F0 is 10ms counting
    mov sav_tl1,#0xf0
    mov sav_th1,#0xd8
    setb tr1 ; start timer1
    setb et1 ; enable timer1 interrupt
    setb ea ; enable global interrupt
    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
    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_200ms:
    mov r4,#0ffh
    sjmp delay
    delay_20ms:
    mov r4,#1
    loop0: djnz r4,loop0
    ret
    delay:
    loop2: mov r5,#04Fh
    loop1: djnz r5,loop1
    djnz r4,loop1
    ret

    end

     
    Allen
     

    Attached Files:

    Last edited: Oct 12, 2013
  20. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Attached is my 8051 development board with 32Kx8 SRAM 61256.

    Where do the 3 wires on the SRAM ie. /OE, /WR & /CE go to?

    Can I leave the /EA & /PSEN not connected? I know I need to put 10K pullup resistors on port 0. The schematic is done in a rush.

    Allen
     

    Attached Files:

    Last edited: May 9, 2013
  21. absf

    absf Active Member

    Joined:
    Jun 18, 2012
    Messages:
    206
    Likes:
    27
    Location:
    Malaysia
    Here's the bin2bcd subroutine I wrote:

    Code (asm):

    conv2BCD:
    ;divider in Acc
    mov b,#100 ; put divisor in B
    div ab ; A/B  ans. in A, rem. in B
    jz bcd2 ; If quotient = 0
    nop ; discard 100's digit
    bcd2: mov a,#10 ; put in new divisor
    xch a,b ; divisor in B and remainder in Acc
    div ab ; Acc/B
    mov tenth,a ; get 10th digit
    xch a,b ; Put B in ACc
    mov unit,a ; get unit digit
    ret

     
    Allen
     
    Last edited: Oct 12, 2013

Share This Page