17 Ağustos 2007 Cuma

Macros and subprograms chapter6

Introduction

5.1 Macros
5.2 Subprograms
5.3 Macros used in the examples

Introduction

Same or similar sequence of instructions is frequently used during programming. Assembly language is very demanding. Programmer is required to take care of every single detail when writing a program, because just one incorrect instruction or label can bring about wrong results or make the program doesn't work at all. Solution to this problem is to use already tested program parts repeatedly. For this kind of programming logic, macros and subprograms are used.

5.1 Macros

Macro is defined with directive macro containing the name of macro and parameters if needed. In program, definition of macro has to be placed before the instruction line where macro is called upon. When during program execution macro is encountered, it is replaced with an appropriate set of instructions stated in the macro's definition.

macro_name
macro par1, par2,..
set of instructions
set of instructions
endm

The simplest use of macro could be naming a set of repetitive instructions to avoid errors during retyping. As an example, we could use a macro for selecting a bank of SFR registers or for a global permission of interrupts. It is much easier to have a macro BANK1 in a program than having to memorize which status bit defines the mentioned bank. This is illustrated below: banks 0 and 1 are selected by setting or clearing bit 5 (RP0) of status register, while interrupts are enabled by bit 7 of INTCON register. First two macros are used for selecting a bank, while other two enable and disable interrupts.



bank0 macro ; Macro bank0
bcf STATUS, RP0 ; Reset RP0 bit = Bank0
endm ; End of macro

bank1 macro ; Macro bank1
bsf STATUS, RP0 ; Set RP0 bit = Bank1
endm ; End of macro

enableint macro ; Interrupts are globally enabled
bsf INTCON, 7 ; Set the bit
endm ; End of macro

disableint macro ; Interrupts are globally disabled
bcf INTCON, 7 ; Reset the bit
endm ; End of macro



These macros are to be saved in a special file with extension INC (abbrev. for INCLUDE file). The following image shows the file bank.inc which contains two macros, bank0 and bank1.


Macros Bank0 and Bank1 are given for illustrational purposes more than practical, since directive BANKSEL NameSFR does the same job. Just write BANKSEL TRISB and the bank containing the TRISB register will be selected.

As can be seen above, first four macros do not have parameters. However, parameters can be used if needed. This will be illustrated with the following macros, used for changing direction of pins on ports. Pin is designated as input if the appropriate bit is set (with the position matching the appropriate pin of TRISB register, bank1) , otherwise it's output.



input macro par1, par2 ; Macro input
bank1 ; In order to access TRIS registers
bsf par1, par2 ; Set the given bit - 1 = input
bank0 ; Macro for selecting bank0
endm ; End of macro

output macro par1, par2 ; Macro output
bank1 ; In order to access TRIS registers
bcf par1, par2 ; Reset the given bit - 0 = output
bank0 ; Macro for selecting bank0
endm ; End of macro



Macro with parameters can be called upon in following way:

output TRISB, 7 ; pin RB7 is output

When calling macro first parameter TRISB takes place of the first parameter, par1, in macro's definition. Parameter 7 takes place of parameter par2, thus generating the following code:



output TRISB, 7 ; Macro output
bsf STATUS, RP0 ; Set RP0 bit = BANK1
bcf TRISB, 7 ; Designate RB7 as output
bcf STATUS, RP0 ; Reset RP0 bit = BANK0
endm ; End of macro



Apparently, programs that use macros are much more legible and flexible. Main drawback of macros is the amount of memory used - every time macro name is encountered in the program, the appropriate code from the definition is inserted. This doesn't necessarily have to be a problem, but be warned if you plan to use sizeable macros frequently in your program.

In case that macro uses labels, they have to be defined as local using the directive local. As an example, below is the macro for calling certain function if carry bit in STATUS register is set. If this is not the case, next instruction in order is executed.



callc macro label ; Macro callc
local Exit ; Defining local label within macro
bnc Exit ; If C=0 jump to Exit and exit macro
call label ; If C=1 call subprogram at the
; address label outside macro
Exit ; Local label within macro
endm ; End of macro



5.2 Subprograms

Subprogram represents a set of instructions beginning with a label and ending with the instruction return or retlw. Its main advantage over macro is that this set of instructions is placed in only one location of program memory. These will be executed every time instruction call subprogram_name is encountered in program. Upon reaching return instruction, program execution continues at the line succeeding the one subprogram was called from. Definition of subprogram can be located anywhere in the program, regardless of the lines in which it is called.



Label ; subprogram is called with "call Label"
set of instructions
set of instructions
set of instructions
return or retlw



With macros, use of input and output parameters is very significant. With subprograms, it is not possible to define parameters within the subprogram as can be done with macros. Still, subprogram can use predefined variables from the main program as its parameters.

Common course of events would be: defining variables, calling the subprogram that uses them, and then reading the variables which may have been changed by the subprogram.

The following example, addition.asm adds two variables, PAR1 and PAR2, and stores the result to variable RES. As 2-byte variables are in question, lower and higher byte has to be defined for each of these. The program itself is quite simple; it first adds lower bytes of variables PAR1 and PAR2, then it adds higher bytes. If two lower bytes total exceeds 255 (maximum for a byte) carry is added to variable RESH.


Basic difference between macro and subprogram is that the macro stands for its definition code (sparing the programmer from additional typing) and can have its own parameters while subprogram saves memory, but cannot have its own parameters.


5.3 Macros used in the examples

Examples given in chapter 6 frequently use macros ifbit, ifnotbit, digbyte, and pausems, so these will be explained in detail. The most important thing is to comprehend the function of the following macros and the way to use them, without unnecessary bothering with the algorithms itself. All macros are included in the file mikroel84.inc for easier reference.

5.3.1 Jump to label if bit is set

ifbit macro par1, par2, par3
btfsc par1, par2
goto par3
endm

Macro is called with : ifbit Register, bit, label

5.3.2 Jump to label if bit is cleared

ifnotbit macro par1, par2, par3
btfss par1, par2
goto par3
endm

Macro is called with : ifnotbit Register, bit, label

Next example shows how to use a macro. Pin 0 on port A is checked and if set, program jumps to label ledoff, otherwise macro ifnotbit executes, directing the program to label ledon.



5.3.3 Extracting ones, tens and hundreds from variable

Typical use for this macro is displaying variables on LCD or 7seg display.

digbyte macro par0
local Pon0
local Exit1
local Exit2
local Positive
local Negative
clrf Dig1
clrf Dig2
clrf Dig3
Positive
movf par0, w
movwf Digtemp
movlw .100
Pon0 incf Dig1 ;computing hundreds digit
subwf Digtemp
btfsc STATUS, C
goto Pon0
decf Dig1, w
addwf Digtemp, f
Exit1 movlw .10 ;computing tens digit
incf Dig2, f
subwf Digtemp, f
btfsc STATUS, C
goto Exit1
decf Dig2, f
addwf Digtemp, f
Exit2 movf Digtemp, w ;computing ones digit
movwf Dig3
endm


Macro is called with :

movlw .156 ; w = 156
movwf RES ; RES = w
digbyte RES ; now Dec1<-1, Dec2<-5, Dec3<-6

The following example shows how to use macro digbyte in program. At the beginning, we have to define variables for storing the result, Dig1, Dig2, Dig3, as well as auxiliary variable Digtemp.

5.3.4 Generating pause in miliseconds (1~65535ms)

Purpose of this macro is to provide exact time delays in program.

pausems macro par1
local Loop1
local dechi
local Delay1ms
local Loop2
local End
movlw high par1 ; Higher byte of parameter 1 goes to HIcnt
movwf HIcnt
movlw low par1 ; Lower byte of parameter 1 goes to LOcnt
movwf LOcnt
Loop1
movf LOcnt, f ; Decrease HIcnt and LOcnt necessary
btfsc STATUS, Z ; number of times and call subprogram Delay1ms
goto dechi
call Delay1ms
decf LOcnt, f
goto Loop1
dechi
movf HIcnt, f
btfsc STATUS, Z
goto End
call Delay1ms
decf HIcnt, f
decf LOcnt, f
goto Loop1
Delay1ms: ; Delay1ms produces a one milisecond delay
movlw .100 ; 100*10us=1ms
movwf LOOPcnt ; LOOPcnt<-100
Loop2:
nop
nop
nop
nop
nop
nop
nop
decfsz LOOPcnt, f
goto Loop2 ; Time period necessary to execute loop Loop2
return ; equals 10us
End
endm

This macro is written for an 4MHz oscillator. For instance, with 8MHz oscillator, pause will be halved. It has very wide range of applications, from simple code such as blinking diodes to highly complicated programs that demand accurate timing. Following example demonstrates use of macro pausems in a program. At the beginning of the program we have to define auxiliary variables HIcnt, LOcnt, and LOPcnt.

Hiç yorum yok:

Cascode stage
or “collector follower”
Jean-Paul Brodier
All microprocessors from the 8051 family have inputs and outputs that are ‘quasi-bidirectional’. This means that when power is first applied, the ports behave as inputs with a logic high level and a weak pull-up.,

Glitch
a relay or some other load such as When driving an optocou-pler or LED, there is a problem
at power on: the NPN transistor in the common emitter connec­tion (Figure 1) causes an unde­sirable excitation of the load from the moment power is applied until the microprocessor has had the chance to turn the output low. In addition, logic high outputs are seldom able to deliver enough current to drive the transistor into saturation because they have been designed to be active low.
Figure 1. An NPN transistor drives a load.
To solve both of these problems in one hit, we have to make the active level logic low. This can be done in three different ways: use an emitter follower as a buffer stage (Figure 2a), an inverter in a common emit­ter circuit (Figure 2b) or an inverter/open collector circuit (Figure 2c). The disadvantage of solution 2a is the fact that the voltage to the load is reduced. In the case of a relay with a 5-V coil there is the risk that the resulting voltage is too low. The disadvantage of examples 2b and 2c is that they require more parts.
Collector follower
That leaves the open collector buffer in the form of an IC type 7404. This solution, however, also has a few disadvantages. You do not always need all of the 6 buffers in one IC. Also, the SMD version can only handle 12 V. This is too low and dan­gerous if we happen to supply the load from an unregulated voltage.
The solution presented here com­bines in one transistor the advan­tages of the emitter follower (inactive when power is first applied) and open collector (higher power supply voltage, lower current). This circuit has been known since the valve era by the name cascode (drive via the cathode). The goal was to reduce the Miller-effect of the internal (parasitic) capacitances. Not having the option of reduc­ing the capacitance between the internal electrodes, a lower volt­age was used instead. The cas-code circuit is often used in pow­erful transmitters (tens of kW) to minimise the Miller-effect. This circuit was also used to limit tran­sistor conduction and to keep the dissipation within bounds, which increased the life of bipolar tran­sistors. This was in the IGBT and VMOS era.
The transistor conducts only when the output from the micro­processor is low (refer Fig­ure 3). The base current is lim­ited by resistor R. This current is determined by the current flow­ing through the load. When the power is switched on, both the base and emitter see the same potential, VCC, so the transistor remains blocked. One thing we have to keep in mind: we may not exceed the current rating of the microprocessor output because it has to cope with all the current flowing in the emitter of the transistor.
In the case of the quite common 80C51, this maximum current is typically 3.2 mA (two LS TTL loads). This is sufficient to drive an LED without overloading the 5-V regulator, or for driving a PNP power stage at the high side (Figure 3b). The parallel Philips PCF88574 I2C interfaces can handle 25 mA. For the Atmel AT89Cx051 as well as for the Philips P89LPC9xx the limit is 20 mA. For the latter type the cascode circuit or ‘collector fol­lower’ is even more interesting when the outputs are configured as open-drain because the nom­inal voltage is only 3.6 V. In all cases we have to make sure that the maximum dissipation of the
Figure 3. Cascode driver stage with discrete transistor.
package is not exceeded. 24 V is sufficient to energise its are determined by the power
Should this be the case, then the half Watt relay coil, which in PNP (or VMOS) transistor.
number of open collectors turn can drive a load of 16 A at The cascode transistor can be a required will probably justify 230V. ‘digital’ type with integrated resorting to a 7404. For loads driven from the positive base and emitter resistors.A current of around 20 mA at side, the voltage and current lim-


pot as interrupt generator

In battery-powered, microcon­troller driven circuits, as well as with microcontrollers operating in cars, it is desirable to switch the micro into power-down mode once a task has been completed. An interrupt request is then required to wake up the micro. This circuit allows an interrupt to be generated in a simple way using a common potentiometer. In the example circuit, the pot may also copy its spindle position to the ADC. This enables the pot to be used for continuously variable settings (like volume) as well for getting the micro out of its power-down mode.
IC1A is configured as a differen­tiator with R3 preventing oscillation by keeping the gain down to 10 times. Because the opamp oper­ates off a single-rail supply voltage, an 18k/10k potential divider (R1/R2) is able to create a virtual ground level at +1.75 V. This can be done because the LM358 can handle input levels of up to 3.5 V when supplied at 5.0 volts. IC1A supplies a brief High pulse at a falling input voltage, and a similar Low pulse when the input voltage rises. In order to get a High pulse when the potentiome­ter spindle is turned cw or ccw, IC1B is set up as an inverter. Next, each opamp output drives the base of a BC547 transistor. The 5 V-to-0 V transitions at both collector outputs are shaped and combined into a usable interrupt pulse by three NOR gates IC2A, IC2B and IC2C.If the potentiometer spindle is turned very slowly, it is possible that the circuit does not respond
That is why an LED has been added that lights briefly when a pulse is generated. Finally, a tip: a 100-pF capacitor may be connected in parallel with R5 for additional suppres­sion of self-oscillation.

elektor time standart


Elektor Time standard (1988)
Jan Buiting

The Elektor Time Standard and associated Slave Unit were spin-offs of another hugely successful project, the DCF77 Receiver / Locked Frequency Standard. The receiver was published in the January 1988 issue, the Time Standard and Slave display in the next two issues. All units were housed in then very fash­ionable and (expensive!) Ver-obox two-part ABS enclosures which had also been used for a number of Elektor test instrument designs published between 1984 and 1987. The Time Standard box was designed to process seconds pulses received from the VLF (77.5 kHz) DCF77 time standard transmitter in Mainflingen, Ger­many, and display time (with atomic accuracy) and date on an LC display. The circuit was based on then extremely popular 8052AH-BASIC microcontroller from Intel, a device, we can safely claim, that made it to fame & glory thanks to Elektor Electron-
ics. The 40-way DIL chip con­tained a BASIC interpreter capa­ble of executing ‘tokenised’ code from an external EPROM. This, we were told by our resident designer Peter Theunissen, made writing the DCF77 time signal decoding routines ‘a doddle’ using his specially adapted BASIC computer and interpreter. For example, when concerns were raised (by myself) that not all of Europe was in the time zone served by DCF77 (i.e., CET or GMT+1h), a menu option was quickly added to allow users to select between UTC and GMT+1h. As a relative novelty, a ready-made self-adhesive front panel foil with built-in membrane keys was designed into the proj­ect. This expensive item had been produced specially for Elektor. However, when the article went into print (using a rather glum page layout and black & white print), there were yet other con­cerns regarding the range of the DCF77 transmitter. This is offi­cially claimed as “approximately 1,000 km by groundwave propa-

gation”. A quick use of a com­pass and a map of Europe sug­gested that the signal would only cover the south-eastern part of the UK, possibly including Greater London. For a couple of months we waited with baited breath for readers’ responses, only to receive two enthusiastic reception reports, one from the East coast of Ireland and another from Riyadh, Saudi Arabia! The latter report came from a reader work­ing at a chemical laboratory. I remember he wrote that DCF77 could be received for a few min­utes a day only, synchronising the clock, usually around nightfall despite heavy ‘static’. A huge wire antenna was used (nothing like the 1-inch ferrite rods we used in our lab, which is less than 100 km away from Mainflingen). Although the BASIC program list-
ing for the Time Standard was freely distributed to interested readers (on paper, in an enve­lope, by snail mail!), only very advanced readers were able to compile the program into tokenised code and burn it into an EPROM. Most other readers had to rely on a ready-pro­grammed 27C64 supplied through our Readers Services. Apart from displaying time and date at atomic accuracy, the Time Standard was also capable of outputting time/date information

in the form of ASCII character strings for other (intelligent) equip­ment to use, for example, a timer or switching clock. Although sales figures of the PCB and EPROM were in the hundreds, I never heard from anyone actually hav­ing enjoyed the wonders of the ASCII output so extensively described in the article. The Slave unit published in March 1988 was connected to the Time Standard via screened (micro­phone) cable, the idea being that one or more Slave units could be installed on walls in rooms at some distance from the main clock unit. Central timekeeping deluxe for offices, labs, schools and workshops, but at what an expense and design effort! Not too many PCBs were sold for this extension of the Time Standard.