(1) The most commonly used PAGE and BANK EMC
ICs are divided into several pages and banks. Low-end EM78P156 and others only have one bank and one page, so there is no need to switch. Newer
ICs basically need to switch. This frequently used bank is most suitable to be made into a macro. The code is as follows:
/*********************************************************
* BANK SELECTION
*********************************************** *******/
BANK macro num
if num == 0
bc R4,6
bc R4,7
elseif num == 1
bs R4,6
bc R4,7
elseif num == 2
bc R4,6
bs R4,7
elseif num == 3
bs R4,6
bs R4,7
else
message "warring!"
endif
endm
/**************************** ***************************
* PAGE SELECTION *
********************* **********************************/
PAGE macro num
if num == 0
bc psw,5
bc psw,6
elseif num == 1
bs psw,5
bc psw,6
elseif num == 2
bc psw,5
bs psw,6
elseif num == 3
bs psw,5
bs psw,6
else
message "warring!"
endif
endm
calling format is
BANK num (num is 0 to 3, representing 4 BANKs)
PAGE num (num is 0 to 3, representing 4 PAGEs)
This is much more convenient and will not go wrong.
(2) Macros with parameters
As an example, let’s assume that we define a macro “ FUNC ", with two parameters, the function is to simply transfer the incoming data to PORT5 and
PORT6, to demonstrate the usage.
First look at the definition:
FUNC MACRO ARG1,ARG2
MOV A,@ARG1
MOV PORT5,A
MOV A,ARG2
MOV PORT6 ,A
ENDM
Notice why there is an @ symbol in front of ARG1? This means that the first parameter received by the macro is an immediate value, while ARG2
does not have that symbol, which means that the second parameter received by the macro is a The address of the register.
OK, let's see how to use it in the main program:
FUNC 0X10, 0X20
This is OK. When the editor compiles, it will automatically perform macro replacement, passing the immediate value 0X10 as the first parameter, and
the content of the 0X20 register , passed as the second parameter, the result after macro replacement is equivalent to:
MOV A,@0x10
MOV PORT5,A
MOV A,0x20
MOV PORT6,A
(3) Let’s talk about a good style of C
language There is a better programming style in the language. Let's take a C51 example:
we want to set TIMER0 in mode 1 and TIMER1 in mode 2.
The general thinking and code of the tutorial is:
look up the definition of TMOD bits in the data, and then slowly calculate , what values should be given to mode 1 and mode 2, and finally write the instruction:
TMOD = 0x21;
completed...
In fact, we can also have another way, that is to write:
TMOD = CT0_MODE1 | CT1_MODE2;
some macros are used in it , the specific definition is:
#define CT0_MODE0 0x00 // Timer0/Counter0 Mode
#define CT0_MODE1 0x01
#define CT0_MODE2 0x02
#define CT0_MODE3 0x03
#define CT1_MODE0 0x00 // Timer1/Counter1 Mode
#define CT1_MODE1 0x10
#define CT1_MODE2 0x20
#define CT1_MODE3 0x30
TMOD = CT0_MODE1 | CT1_MODE2;
This should It is easy to understand, right? The "|" in the middle is the OR operation, which is the operation performed by the compiler before compiling. Specifically, CT
0_MODE1 represents 0X01 and CT1_MODE2 represents 0x20, and then the result after the "AND operation" is 0X21. Same as above. But
honestly , which method would you prefer? I would choose the second one without hesitation.
(4) Use our EMC assembly compiler to imitate this style.
Our EMC assembly compiler also supports this type of compilation operation. Let the compiler help us handle some basic operations first. Faced with the small C
compiler The functions are not surprising, but the assembly compiler can also do it, which is a little unexpected.
The function register allocation of EMC chips is really a mess. Alas, it makes me vomit blood. It's okay to use a fixed type of IC. Used a few
If it's this kind of IC, it's called depressing. An example is EM78P447 and EM78P156. The former is originally an upgraded version, but why are some controls so
different ? I have to check the DATASHEET frantically every time. In order to slow down the death of brain cells, I decided to use macros... For example: We need to turn on the TCC
A counter of EM78P260 , and we use macros with parameters to implement the initialization work. Divide into several steps 1 First define a macro, which can be used to initialize TCCA_SETUP MACRO TCCACNT clr 0x04 ; 0x04 is used as a temporary register ior 0x08 ; 0x08 is the register that controls TCCA and a,@0xf8 ; Mask TCCA-related MOV 0x04,a MOV a,@TCCACNT ; Read the passed parameters or a,0x04 iow 0x08 MOV a,@TCCACNT ; If TCCA is allowed, open TCCA interrupt and a,@0x04 ; Otherwise jump out directly jbc 0x03,2 jmp $+4 ior 0x0f or a,@0x08 iow 0x0f ENDM _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ TCCA_EDGE_FALL Starting string selection */ TCCA_SETUP TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE See it? (TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE) A bunch of meaningful parameters, XORed and passed as a parameter to the macro TCCA_SETUP. When modifying, we can do it very easily, and we don’t even need to look up information. For example, if we want to change to external TCCA pulse counting, we only need to simply modify TCCA_SETUP TCCA_DISABLE|TCCA_SRC_EXT|TCCA_EDGE_RISE to complete. If you want to disable TCCA, change it to TCCA_DISABLE and it’s OK
(5) Automatic register allocation
Finally, we have come to the end. We have come to the most BT part, which is also the most rewarding part. How to make registers automatically allocate space? A
big difference between assembly and C is that C variables are automatically allocated. I am jealous of it. It is such a good thing. After being abused by assembly for a long time, I
suddenly found that our EMC assembly compiler also has this function. I am so happy! Maybe some seniors have already known how to use it. So I will just
show off my skills and give you
some advice. When writing programs, we usually define a meaningful and easy-to-remember name to replace the abstract register name. For example, we define a register for temporary
variables
TEMP EQU 0X10
. In this way, we define TEMP and use TEMP to replace the 0X10 register in the future. This is the most common way. However, the problem is that
we have to redefine TEMP EQU 0X10 every time before writing a program. Of course, it is not annoying, but we all have some
subroutines with common functions. If registers are used in the subroutines, they also need to be defined. Then when doing a project, copy a
subroutine a subroutine there. Well, there are a lot of conflicting register definitions, which must be checked carefully and slowly. If you are unlucky,
two names are defined on the same register. Well, it's terrible. A very hidden logic error comes, which is a nightmare.
However, macros can be used to automatically allocate
variables. The WICE manual also says that the usage is
TEST VAR 1
MOV A, @TEST
TEST VAR TEST+1
MOV A, @TEST.
Comparing the values of A twice, we find that the first value of A is 1 and the second value of A is 2! ! This is the basic principle of variable macros. The compiler treats
it as a variable and can change it, but this change only occurs during compilation and is useless after the code is generated.
Okay, let's talk about our core and how to allocate it specifically.
First, define a macro for assigning variables. The code is as follows:
ADDR_ASSIGN MACRO REGISTER
REGISTER EQU ADDRESS
ADDRESS VAR ADDRESS+1
ENDM
uses a parameter, the name of the variable passed in. For example, we wrote
ADDRESS VAR 0X10 in the main program (first define the address to start assigning, we start from 0X10)
ADDR_ASSIGN Temp0
Temp0 is passed in as a parameter, which actually executes
Temp EQU 0X10
ADDRESS = ADDRESS+1 (now ADDRESS is 0X11! Because it is a variable macro!)
Next time, if we continue to define
ADDR_ASSIGN Temp1,
Temp1 is now automatically defined as 0X11, and then ADDRESS rolls to 0X12 for the next register definition.
This is very convenient. For example, we define a bunch of registers
ADDR_ASSIGN Temp0
ADDR_ASSIGN Temp1
ADDR_ASSIGN Temp2
ADDR_ASSIGN Te MP3
Oh my god, this is so easy to use! ! ! We don't need to worry about which register is allocated to it. Anyway, it is allocated and
can be used. Ha~~TEST and you will know.
Involved issues 1.
Out-of-bounds problem. When it is allocated to 0X3F, a page ends, but ADDRESS continues to be added. Are you afraid? Don't worry, the compiler
has reported an error and cannot compile. In this way, there is no need to worry about out-of-bounds, and you can safely define
the involved issues 2.
How to allocate multiple banks? In fact, you can add an extra parameter when defining the macro, and then use the conditional macro to jump to the definition, but I
was afraid of trouble, so I used the following method:
/*---------------------------BANK 0 entry address-------------------------------------*/
ADDRESS VAR 0X10 ; Allocatable 0x10 ~ 0x3f
/*--------------------------- BANK 0 ----------------------------------------*/
Here are the registers we need to define./*---------------------------BANK0
debug information output----------------------------------*/
MESSAGE "Bank0 maximum allocated RAM:"
ADDR_DISP ADDRESS-1
/*-------------------------------------------------------------------------------*/
/*---------------------------BANK 1 entry address-------------------------------------*/
ADDRESS VAR 0X20 ; Allocatable 0x20 ~ 0x3f
/*--------------------------- BANK 1 ----------------------------------------*/
Here are the bank 1 we need to define
/*---------------------------BANK1 debug information output----------------------------------*/ MESSAGE
"Bank 1 maximum allocated RAM:"
ADDR_DISP ADDRESS-1
/*-------------------------------------------------------------------------------*/
How is it? Harmony, right? Strictly separate the variables. If you need to put it in bank0, fill it in the area of bank0. If you need to put it in bank1,
fill it in bank1. Because at the beginning of bank1, ADDRESS is redefined as 0X20, so you can continue to
allocate . If there are multiple pages, follow the same method.
At the end of each bank, I also put two macros, they are
MESSAGE "Bank0 maximum allocated RAM:"
ADDR_DISP ADDRESS-1.
The first one simply displays text. The second one ADDR_DISP is used to show which register the maximum total allocation is.
The prototype is:
ADDR_DISP macro reg
IF reg==0x10
MESSAGE "0x10"
ELSEIF reg==0x11
MESSAGE "0x11"
ELSEIF reg==0x12
MESSAGE "0x12"
ELSEIF reg==0x13
…
…
(I wrote the following myself…)
ENDM
is very simple. It just passes the last address of ADDRESS in and shows it. Because ADDRESS executes an extra self-increment instruction,
we subtract it back, and then it's OK.
Previous article:em78p153 driver 1602 source program
Next article:Elan MCU PT2262 wireless decoding program
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- From probes to power supplies, Tektronix is leading the way in comprehensive innovation in power electronics testing
- From probes to power supplies, Tektronix is leading the way in comprehensive innovation in power electronics testing
- Sn-doped CuO nanostructure-based ethanol gas sensor for real-time drunk driving detection in vehicles
- Design considerations for automotive battery wiring harness
- Do you know all the various motors commonly used in automotive electronics?
- What are the functions of the Internet of Vehicles? What are the uses and benefits of the Internet of Vehicles?
- Power Inverter - A critical safety system for electric vehicles
- Analysis of the information security mechanism of AUTOSAR, the automotive embedded software framework
- Live broadcast with prizes | Sign up for TI's June Embedded Processing Live Theme Week to get a glimpse of new products in industrial scenarios!
- [MSP430] Practical ADC use, internal temperature measurement use
- STM32F401CC spi flash recognition problem
- [Raspberry Pi 4B Review] + Building an OPENCV Environment
- Design and Application of Saber Simulation Software
- [2022 Digi-Key Innovation Design Competition] ESP32S2 button control RGB light
- New wearable technology developed, more skin-friendly and stronger
- A collection of autonomous driving technical materials, download now without any points!
- Switch OUT?! Nintendo's latest recruitment may be aimed at the next generation console
- 【ST NUCLEO-H743ZI Review】+ 3. Key input