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
Ian Rogers

Basic 8051 tutorial 2

Continuing the ASM and C on the 51 derivatives

  1. Ian Rogers
    Ok... Back on track.

    The next tutorial we need to read a 4 x 3 ( 12 key ) keypad...

    If we attach a keypad to port 0 and place some resistors as external pull up’s we can read can read the 12 possible on the keypad on only 7 pins... 4 pins as columns and 3 pins as rows.. Here is the connection I used... I have included a 7 segment LED as a simple visual response...

    7seg.png
    The pinout is shown above... We don't have enough power to sink the current so I used a line driver.. The 74C245 is a bidirectional buffer... We can output a small current on the micro and the buffer will allow more current to be used for the LED's, the maximum current is 24mA on each pin so with a 470 ohm current limiting resistor will still give a good visual output on the display..

    Attach a common cathode display to our circuit like so..

    Keypad.png

    The keypad will require pullup resistors ( I have used 1k ) on the row pins... The way I read a keypad is by making each column negative ( 0 volts ) in turn, then if a key is being pressed it will show on the 4 row pins 0~3..

    Here is the code in ASM to read a keypad and display the same value on the display.

    Code 7
    Code (asm):

        org    0        ; Reset vector
        sjmp    Start

        org    30H        ; Code starts here
    Start:
        clr    A        ; A = 0
    While:
        acall    keypad    ; Fetch keypress ( mono...only one key at a time )
        acall    delay    ; delay so we see it
        acall    Display    ; Show on display
        sjmp    While    ; do it again ( Forever loop )

    keypad:
        mov    R1,#0EFH    ; keymask
        mov    R2,#3        ; Three columns
        mov    A,#1
    OLoop:
        clr    C
        mov    P0,R1        ; ready keypad mask
        jb    P0.0,row2    ; Key pressed? row 1
        sjmp    keydone    ; found a key
    row2:
        jb    P0.1,row3    ; Key pressed? row 2
        add    A,#1
        sjmp    keydone    ; found a key
    row3:
        jb    P0.2,row4    ; Key pressed? row 3
        add    A,#2
        sjmp    keydone    ; found a key
    row4:
        jb    P0.3,nextcol    ; Key pressed? row 4
        add    A,#3
        sjmp    keydone    ; found a key
    nextcol:
        add    A,#4        ; add row count...0,4,8 + key press
        push    Acc        ; save count
        mov    A,R1        ; get mask
        setb    C        ; Rotate with
        rlc    A            ; carry R1 mask
        mov    R1,A        ; store new mask
        pop    Acc            ; restore the count
        djnz    R2,OLoop    ; Last column???
        clr    A            ; No keys detected...
    keydone:            ; return with keypad condition
        ret


    Display:
        mov    DPTR,#digits    ; Use A to get 7 segment pattern
        movc    A,@A+DPTR    ;
        ;cpl    A        ; Common cathode... Uncomment for common anode.
        mov    P1,A        ;  put pattern on port 1
        ret

    delay:    mov    R2,#225    ; 2 clock cycles (call)        = 2
        mov    R1,#0        ; 2 clock cycles (loading)    = 2
    d1:    
       djnz    R1,d1    ; 2 * 256 clock cycles *225    = 115200
        djnz    R2,d1    ; 2 * 225 clock cycles     = 450
        ret                ; 2 clock cycles (return)    = 2

    digits:    db    03FH,006H,005BH,04FH,066H,06DH,07DH,007H,07FH,06FH,077H,07CH,039H            ; 7 segment patterns 0 to C
        end
     
    This is getting near to pixel output... The patterns to create the digits 0 ~ C are stored similar to bitmaps... The code bitmaps are for common cathode displays.. If you use a common anode (as I have done ) then the complement “cpl A” command inverts the output...

    The key pad read function is looped three times whilst keeping an eye on the four row inputs.

    As the resistors keep the pins in a high state, the columns are pulsed low in turn, if the pin s 0 ~ 3 are low then a key press is detected and whilst we keep a track of the loop the count stored in A will give us the actual key pressed.

    There are some low level things we can't do in C so we have little work rounds.. Take this command.

    rlc A. We can't rotate left with carry, In C the shift left operator '<<' will clear the LSBit . ie.. 11101111 ( 0xEF) after the shift will become 11011110 ( 0xBE) so we have to remember in this

    instance to add one to make the shift work as we want...

    Here is the C version..

    Code 8
    Code (c):

    #include<8051.h>        // definition file.

    unsigned char digits[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D
                    ,0x07,0x7F,0x6F,0x77,0x7C,0x39};

    void delay(void)        // How to get 125mS..
        {
        int x = 10500;        // The while statement consumes 11.89uS (11 clock cycles )
        while(x--);        // So 10500 * 11.89uS = nearly 125mS.
        }          

    char keypad(void)
        {
        unsigned char keymask = 0xEF;
        char key = 0, x;
        for(x=0;x<3;x++)        // Three columns.
            {
            P0 = keymask;    // check each
            if(!P0_0) key = 1;    // bit for
            if(!P0_1) key = 2;
            if(!P0_2) key = 3;    // key detect.
            if(!P0_3) key = 4;
            if(key)
                {        // If we see a key press we
                key += (x*4);    // need to add in the loop.
                return key;
                }
            keymask<<=1;    // We have no status control in C so we manually
            keymask++;        // shift a bit into the mask register..
            }            // or the LSBit will be an output !sizzle!..
        return key;
        }
       
    void display(unsigned char dt)
        {
        P1 = ~digits[dt];    // Common anode uses '~' delete for common cathode.  
        }

    void main(void)            // Main entry point
        {
       
        while(1)            // Forever loop
            {
            display(keypad());    // we can nest functions in C like this
            delay();        // delay..
            }
        }
     
    Hopefully you can now start to see a difference in C when you are entering code..

    C has 28 lines of code and ASM has 46... We can optimise the ASM. code to use mackro's and use symbols for better readability, but with C identifiers we can read it quite well without remarks.. I know we can do the same in ASM but the readability is still not as good as C.

    The keypad function returns a key which can be used directly with the display function..

    This is the second tutorial in this little series... I'll post the next as soon as I havea little more time...
    RonaldB, DonPriceTech, absf and 3 others like this.

Recent Reviews

  1. RonaldB
    RonaldB
    5/5,
    Well explained. Now I can compare which is better-- I prefer C from the start. I just turned down my plan to study ASM. Nice one!