ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 15.06.2025

Просмотров: 2106

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Calling Assembly-language Routines

Successful assembly is a good sign, but it doesn’t mean that the program is error-free. As in any programming language, a line of code may contain instructions that are valid, but that do not do what you intended. It’s a good idea to at least scan the listing created by the assembler before you try to run a routine, to look for obvious errors.

Different assemblers may have slightly different syntax rules. For example, some require org and end to have a leading period (.org, .end). Check your assembler’s documentation for the specifics.

Uploading a Program

When you’re ready to load the program into RAM, boot your 8052-BASIC system, connect the serial link to your personal computer, and run your communications software. Use the software to upload Listing B-1 or B-2, in the same way that you upload any BASIC-52 program from disk.

For loading Intel hex files, you can set up your host computer’s software so that it waits to receive the BASIC-52 “>” prompt (ASCII code 62) after each uploaded line. This will ensure that BASIC-52 has enough time to process each line before the next one arrives. Use this method only with Intel Hex files, not BASIC-52 programs. If a BASIC-52 program contains any “>” (greater than) operators, the software will think that these indicate the end of a program line. Intel Hex files contain no “>” characters, so there is no problem.

If you want to wait for the “>” character, in Procomm Plus, from the Setup menu, select Terminal Options, then Protocol Options, ASCII Options, and set the pace character to 62. Character pacing and line pacing can be 0. In the Windows terminal, select Settings, then Text Transfers, One Line at a Time, and enter “>” under Wait for Prompt String. Other software should have similar abilities.

If you wish, you can use BASIC-52’s (F)PROG command to store the program in NV memory so it’s available without having to upload each time.

To use Listing B-1 or B-2, run the program and, at the prompt, use your communications software to upload your object file. The file will load into the locations specified by your source file. The program will display error messages if it has problems with the uploading. For proper calculation of the programming-pulse width in Listing B-2, set BASIC-52’s XTAL operator to match your crystal’s frequency.

If the file loads successfully, you’re ready to test it. Connect a logic probe to pin 1 on the 8052, or set a voltmeter to measure the voltage from pin 1 to pin 20 (ground) on the chip. To call your subroutine, enter and run this BASIC-52 program:

The Microcontroller Idea Book

225

Chapter 13

10 CALL 3000h

20 END

If necessary, change the address in line 10 to match the value in your routine’s org directive.

Each time you run the program, you should see pin 1 on the 8052 change from high to low or low to high. The routine should then return you to the BASIC-52 prompt.

If the program crashes and does not return you to BASIC-52, you need to re-examine your listing file to see what went wrong. Remember that the address in BASIC-52’s CALL

Figure

13-2. By writing the appropriate values to an output port, you can

cause a sine wave to appear at VOUT.

226

The Microcontroller Idea Book


Calling Assembly-language Routines

statement must match the address in your file’s org directive. A missing ret instruction in the routine will also cause the system to crash.

Example: Creating a Sine Wave

When you have the simple routine working, you’re ready to move on to bigger things. For the sine-wave project, we’ll begin by generating a sine wave entirely with BASIC-52 statements. This way, we can first test the added circuits as well as the algorithm, or sequence of steps, that we plan to use to generate the sine wave. It also illustrates the speed limits of BASIC-52.

The Circuits

Figure 13-2 shows the circuit that interfaces to the 8052. I adapted the circuit from an example in National Semiconductor’s data sheet for the DAC0832.

U1 is a DAC0832 digital-to-analog converter, or DAC, which converts data inputs D0-D7 into an analog voltage. D0-D7 are controlled by an output port at E400h. You may change this address to match any output port on your system.

Listing 13-4. Sine-wave generator for Figure 13-2’s circuit.

10 REM Begins by calculating and storing sine values

20 REM for 256 locations along a sine wave.

30 REM Line 100 converts a position in the sine wave 40 REM (0-255) to the radians required by the sine

50 REM operator: (0.0246 = 2*PI/256). Adding 1 to the 60 REM sines makes all values positive, from 0 to +2. 70 REM Multiplying by 127.5 results in values that

80 REM range from 0 to 255.

90 FOR I=0 TO 255

100 XBY(3000H+I)=INT((SIN(I*.0246)+1)*127.5+.5)

110 NEXT I

120 PRINT “Sine values are stored in RAM (3000h-30FFh)” 130 PRINT “Press Control+C to quit”

140 REM Write the values in sequence to E400h

150 DO

160 FOR I=3000H TO 30FFH

170 XBY(0E400H)=XBY(I)

180 NEXT I

190 WHILE 1=1

200 END

The Microcontroller Idea Book

227

Chapter 13

The DAC is configured in its flow-through and voltage-switching modes. In flow-through mode, the analog output continuously reflects the data inputs. The chip has several control signals for latching inputs and outputs, but these aren’t needed by our circuit.

In voltage-switching mode, the analog output is a voltage proportional to the value of the byte formed by D0-D7. An LM385 2.5-volt reference is applied across current output terminals IOUT1 and IOUT2, and the output appears at VREF. (This configuration is the inverse of the device’s current-switching mode, where VREF is an input and IOUT1 and IOUT2 are outputs, as their names suggest.)

Op amp U2A buffers the output, and U2B is a low-pass filter that helps to smooth VOUT.

A BASIC Program

Listing 13-4 causes a sine wave to appear at VOUT. The sine wave represents the value of the trigonometric sine function for an angle that varies continuously from 0 to 360 degrees, or 0 to 6.28 (2*PI) radians. Lines 90-110 are a loop that selects 256 equally-spaced points along one cycle of the sine wave, calculates the sine for each, and stores the values in RAM. The program uses BASIC-52’s SIN operator in calculating the values. Sine values normally vary from +1 to -1, but line 100 adjusts the values so that they vary from 0 to 255, which is the range of inputs accepted by the 8-bit DAC. Using these values, 0 is the negative peak, 255 is the positive peak, and the zero crossing occurs midway between points 127 and 128.

To generate the sine wave, Lines 150-180 are a loop that reads each value in sequence from RAM and writes it to an output port at E400h. After writing a complete cycle, the program loops back and begins another. The sine wave repeats endlessly, until the user presses

CONTROL+C.

Listing 13-4 creates a perfectly good sine wave, but at a very low frequency. Using 12-Megahertz crystal to clock the 8052, the frequency is only about 0.7 Hertz, or 1.5 seconds per cycle.

Adding Assembly Language

To speed things up, Listing 13-5 is an assembly-language routine that performs the functions of lines 150-180 in Listing 13-4. As in the original program, Listing 13-5 copies values in sequence from RAM to E400h, repeating the sequence after 256 writes. The routine illustrates a couple of major differences between BASIC and assembly-language programming.

One is that assembly language has no built-in FOR, DO, or WHILE loops. Instead, you have to create loop structures from the instructions available. Listing 13-5 creates a 256-step

228

The Microcontroller Idea Book


Calling Assembly-language Routines

Listing 13-5. Assembly-language sine-wave routine for Figure 13-2’s circuit..

;Reads and copies values in sequence from locations 3000h ;to 30FFh to E400h. A DAC0832 generates a sine wave from ;the values.

;A keypress terminates the routine and returns to BASIC-52.

org

3100h

;load routine above the

;stored values

OutputPort

equ

0e400h

;address of port to write

;sine values to

;Begin generating the sine wave:

nextcycle

mov

20h,#0ffh

;store initial count at 20h

;in internal

;data memory

nextvalue

mov

dph,#30h

;put high byte of sine wave

;address (30h)

;in dptr

mov

dpl,20h

;copy low byte of sine wave

;address from 20h to dptr

movx

a,@dptr

;place sine wave value in

;acc.

mov

dptr,#OutputPort

;copy port address

;to dptr

movx

@dptr,a

;copy sine wave value to

;output port

djnz

20h,nextvalue ;do another if count > 0

jb

ri,return

;after writing one complete

;cycle, check serial receive

;flag and quit if set

sjmp

nextcycle

;if serial flag not set,

;begin another cycle

;Return to BASIC-52:

return

clr

ri

;clear serial receive flag

ret

;return to BASIC

end

The Microcontroller Idea Book

229


Chapter 13

FOR loop by loading FFh into register dpl (the lower byte of dptr), and decrementing dpl repeatedly until it equals zero.

In assembly language, you also do not have built-in conveniences like BASIC-52’s ability to terminate a program on CONTROL+C. You have to add these features yourself. In Listing 13-5, after each complete cycle of the sine wave, the program checks the serial port’s receive flag. If the flag is set, it means that the user has pressed a key, and the program returns to the BASIC-52 prompt. Otherwise, the program begins another cycle of the sine wave.

To run Listing 13-5, create a source file with your text editor, assemble it, and upload it to RAM as before. Edit Listing 13-4 by removing lines 150-180 and adding this line:

150 CALL 3100h

Now when you run Listing 13-4, you should again see a sine wave at VOUT, but at a much higher frequency.

With a 12-Megahertz crystal, the sine wave should be around 350 Hertz, or 2.8 milliseconds per cycle. You can verify this by consulting the 8052’s data book, which tells the number of machine cycles required to execute each instruction. At 12 Megahertz, each machine cycle is 1 microsecond, and one complete cycle requires 11 microseconds multiplied by 255 points on the wave, plus 6 microseconds to test the serial flag, or 2811 microseconds total.

With different crystal frequencies, the output frequency will vary in direct proportion. For example, with a 6-Megahertz crystal, the sine wave will be half as fast.

To slow down the sine wave, you can add “do-nothing” instructions to the code. For example adding a nop (no operation) instruction in the main loop will add 1 microsecond to the time between points on the wave, for a frequency of 326 Hertz. For long delays, you can insert a timing loop that executes after each point in the wave.

Listing 13-5 still relies on BASIC-52 to calculate the sine values and store them in RAM. Although you can also write these parts in assembly language, doing so in BASIC is much easier, and doesn’t affect the frequency of the sine wave that results. Even if you later decide to write this part in assembly language, with BASIC-52 you can test each section of the code as you go along.

When you have your assembly-language routine in the form you want it, you can use Listing B-2 or an EPROM programmer to store the code in EPROM. If your EPROM has different addressing than the RAM you used to test the code, you must change the ORG directive in the source file to match the new location, and reassemble the file before you program it into the EPROM.

230

The Microcontroller Idea Book

Calling Assembly-language Routines

Avoiding Program Crashes

It’s very easy to write an assembly-language program that crashes the system and forces you to reboot. To prevent this, you have to take care that your routines do not interfere with each other, or with BASIC-52. Remember that BASIC-52 is a program in itself, and it uses many of the registers and other memory locations, both inside and outside of the 8052, for its own purposes.

For example, BASIC-52 uses locations 13h and 14h in internal RAM to store the starting address of the current BASIC program in external RAM. If you overwrite these values, BASIC-52 will no longer be able to find your program.

The BASIC-52 programming manuals list the registers and other memory addresses used by BASIC. In general, you should avoid writing to these locations, unless you know what you’re doing and how to deal with the results.

Often, an assembly-language routine will alter some of the 8052’s registers. You are responsible for seeing that all critical values are unchanged when the routine returns control to the program that called it, whether it’s BASIC-52 or another assembly-language program.

The stack is a convenient way to preserve values on entering a routine, and to restore them on exiting. The stack is a special area of memory with a last-in, first-out structure, which means that you read values from the stack in the reverse order that you wrote them. Storing values in the stack area is called pushing, or placing, values on the stack. Retrieving values from the stack area is called popping them off the stack.

Assembly language has push and pop instructions for accessing the stack. (BASIC-52’s PUSH and POP instructions access a separate area called the argument stack.)

You can also preserve values by selecting a unique register bank for use by a routine. The 8052 has 32 registers arranged in four banks of eight, from 0 to 1Fh in internal data memory. You can access the registers by specifying the address, or by selecting a register bank and specifying a register from R0 to R7 within the bank. For example, if bank 0 is selected, R0 is location 00h, but if bank 1 is selected, R0 is location 08h.

BASIC-52 uses banks 0, 1, and 2, but uses bank 3 only with the PGM instruction, so this bank is usually free for other uses. Bits 3 and 4 of the 8052’s program status word (psw) select the register bank. When you call an assembly-language routine, BASIC-52 automatically selects register bank 0. To select bank 3, add this to the beginning of your routine:

push

psw

;save program status word

orl

psw,#18h

;select register bank 3

The Microcontroller Idea Book

231