Here are a number of code snippets that can be "Cut and Pasted" from this page into your applications to provide some basic functions in 8051 assembler. These routines were taken from "Programming and Customizing the 8051". 
  1. Timing Delays 
  2. Table Operations 
  3. Hex to ASCII Conversion 
  4. Loading the "Encryption Array" 
  5. Circular Buffers 

1. Timing Delays

The following loop uses two Bank Registers to provide a precisely timed delay: 
  mov  Ra, DelayLo

  mov  Rb, DelayHi



Loop:



  djnz Ra, Loop

  djnz Rb, Loop

             
To calculate the delay, use the formula: 
  TimeDelay = ( 12 * ( DelayLo + ( 257 * DelayHi ) - 254 )) / Freq

             
To determine the correct values for the two eight bit "Delay" values, I first find the highest "DelayHi" value that does not exceed the desired delay (with "DelayLo" set to zero). 

2. Table Operations

Using a standard table read (with the "movc A,@A+PC" instruction), up to 255 table entries can be returned from a byte index value. To return all the corresponding table value for a byte (all 256 different values), the following subroutine could be used: 
Read_Table:                   ;  Read the Table Entry from "A"



  inc  A                      ;  Point to Offset in Table/Get

                              ;   Test for 0FFh

  jnzRead_Table_Get



  mov  A,#Entry_0FFh          ;  Return the 0FFh Entry



  ret



InitGetTable:                 ;  Table Offset to Display

  movc A,@A+PC

  ret



InitTable:                    ;  The Control Store Table for 

  db   ...                    ;   Initializing "Array" - 255 Entries

             

3. Hex to Ascii Conversion

This is a port of my PICMicro code to convert a four bit nybble to it's corresponding ASCII Character ("0"-"9", "A"-"F"): 
ByteToASCII:            ;  Convert the Byte in "A" to two ASCII

                        ;   characters in "B" and "A"

  mov   B,A             ;  Save the Byte for Low Nybble Conversion

  

  swap  A               ;  Do High Nybble Conversion

  anl   A,#00Fh

  acall NybbleToASCII



  xch   A,B             ;  Save the ASCII of the High Byte



  anl   A,#00Fh         ;  Do Conversion on the Low Nybble

  acall NybbleToASCII



  ret

             
To convert the individual nybbles to ASCII, the following subroutine is used: 
NybbleToASCII:                ;  Convert the Contents of "ACC" to an 

                              ;   ASCII Character

  add  A,#036h                ;  If ( A & 0x00Fh ) + 6 > 0x010h

  jnb  AC,Skip

  add  A,#7                   ;   Add 7 to Jump to "A" to "F"

Skip:

  subb A,#6                   ;  Take Away Flag Set



  ret


             

4. Loading the "Encryption Array"

If there is any unused EPROM or the Encryption Array is left unprogrammed, somebody (ie a Pirate) could figure out what the EPROM or encryption array contents were by reading out the EPROM contents and checking to see if what's read back can be executed directly or, if the encryption array is programmed, looking for a repeating pattern. 

To prevent this, a non-repeating pattern should be put into both the Encryption Array as well as the unused EPROM. 

The following conditional assembler code could be used: 

ProgEnd EQU $           ;  Identify the End Address of the Code

 while ( $ < DEVEND )   ;  Repeat to the End Address of the Device

  db   ( ProgEnd + (( $ - ProgEnd ) * 3 ) & 0FFh

 wend

             
If the code above was put at the end of an 8051's program, the remainder of control store memory, no matter how large would be filled with a pattern increasing by three for each byte and starting with the least significant byte of the address after the end of the program. By incrementing by three, the pattern won't repeat at the same address for 768 bytes. This can be increased by using a larger prime number to multiply the current address by. 

5. Circular Buffers

In some applications which require incoming data to be processed serially and data may come in before the microcontroller can devote the cycles to processing it, the incoming data has to be "buffered" (saved) for some period of time. Ideally, the algorithms used for saving and retrieving this data, as well as maintaining the buffer should be as simple and fast executing as possible. Like most problems, there are many ways of solving it, with one of the best being the "circular buffer". 

A circular buffer is a memory area that has been set aside for an index to store data and another index to retrieve the data. Once an index has reached the end of the buffer, it is reset to the start of the buffer. In this way, the buffer is "circular" in that it never ends. 

To "Push" data into such a buffer, the following code could be used: 

Push:                   ;  Push the Contents of the Accumulator into the 

                        ;   Circular Buffer

  mov  @R0,A            ;  Save the Contents of A into Buffer Pointed to 

                        ;   by R0

  inc  R0               ;  Point to the next Location in the buffer



  cjne R0,#BufferEnd+1,PushEnd



  mov  R0,#BufferStart  ;  If at the End of the Buffer, Point to the 

                        ;   Start

PushEnd:



  ret

             
After "Push" has gone through each address, the data pointer ("R0") is reset to the start of the buffer. I used "R0" as the index because it can be compared to and updated without affecting the contents of the accumulator or PSW register. 

This can be improved by sizing and locating the buffer in such a way that it's starting address has a "0" at the least significant bit before the bits used to address within the buffer. For a sixteen byte circular buffer, having bit four of the address always reset will allow the "Push" routine to be simplified to: 

Push:                   ;  Push the Contents of the Accumulator into the 

                        ;   Circular Buffer

  mov  @R0,A            ;  Save the Contents of A into Buffer Pointed to 

                        ;   by R0

  inc  R0               ;  Point to the next Location in the buffer



  anl  R0,#(BufferStart+(BufferSize-1))



  ret

             
copyright © Myke Predko 1998