1.1 The C-51 compiler supports the following data types:
type of data |
length |
range |
bit |
1 byte |
0 or 1 |
signed char |
1 byte |
-128~+127 |
unsigned char |
1 byte |
0~255 |
signed int |
2 bytes |
-32768~+32867 |
unsigned int |
2 bytes |
0~65535 |
signed long |
4 bytes |
-2147483648~+2147483647 |
unsigned long |
4 bytes |
0~4294967295 |
float |
4 bytes |
±1.176E-38~±3.40E+38 |
pointer |
1~3 bytes |
Object Address |
spit |
1 person |
0 or 1 |
sfr |
1 byte |
0~255 |
sfr16 |
2 bytes |
0~65535 |
Compiled data types (such as structures) contain the data types listed in the table above. Since the 8051 series is an 8-bit machine, there is no byte alignment issue. This means that the data structure members are placed sequentially.
Data type conversion: When the result of a calculation implies another data type, the data type can be automatically converted. For example, when a bit variable is assigned to an integer variable, the bit value is automatically converted to an integer value, and the sign of a signed variable is also automatically processed. These conversions can also be performed manually using standard C language instructions.
1.2 Physical Structure of Data Types
1.2.1 bit
The "bit" type has only 1 bit, and bit pointers and bit arrays are not allowed. Bit objects are always located in the addressable RAM space of the 8051 CPU. L51 overlaps bit objects if the program control flow allows it.
1.2.2 signed/unsigned char;data/idata/pdata 指针
"char" type scalars and memory based "data/idata/pdata" pointers have a length of 1 byte (8 bits).
1.2.3 signed/unsigned int/short;xdata/code 指针
Scalars of type "int" and "short" and pointers to xdata/code areas have a length of 2 bytes (16
bits)。
The integer value (or offset) 0x1234 is stored in memory as follows:
Address: +0 +1
Content: 0x12 0x34
1.2.4 signed/unsigned long
A scalar of type "long" is 4 bytes (32 bits) long, and the value 0x12345678 is placed in the following way:
Address: +0 +1 +2 +3
Content: 0x12 0x34 0x56 0x78
1.2.5 "General" pointers
A "normal" pointer consists of 3 bytes: 2 bytes of offset and 1 byte of memory type:
Address: +0 +1 +2
Contents: Memory type Offset high Offset low
The first byte represents the pointer's storage type. The storage type is encoded as follows:
Memory Type IDATA XDATA PDATA DATA CODE
Value 1 2 3 4 5
Using values of other types may result in unpredictable program behavior.
The XDATA type 0x1234 address is represented as a pointer as follows:
Address: +0 +1 +2
Content: 0x02 0x12 0x34
When using constants as pointers, you must be careful to correctly define the memory type and offset. The following example writes the value 0x41 to the external data memory at the absolute address 0x8000:
#define XBYTE ((char *)0x20000L)
XBYTE[0x8000]=0x41;
The above example also works with other constant indexes or index variables. In this way, absolute addresses of various memory types can be accessed in a very efficient way. There is one exception, namely SFR.
Note: The absolute address is defined as a "long" constant, the lower 16 bits contain the offset, and the upper 8 bits indicate the xdata type. In order to represent this pointer, a long integer must be used to define the memory type.
The C51 compiler does not check pointer constants; the user must choose meaningful values.
1.2.6 float
The "float" type is 4 bytes (32 bits), and the format used is consistent with the IEEE-754 standard (32 bits) with 24 bits of precision. The high bit of the mantissa is always "1" and is therefore not saved. The bit distribution is as follows:
l 1-bit symbol
l 8-bit exponent
l 23-digit mantissa
The sign bit is the highest bit, the mantissa is the lowest bit, and the bytes are stored in memory as follows:
Address: +0 +1 +2 +3
内容: MMMM MMMM MMMM MMMM E MMM MMMM S EEE EEEE
Where: S: sign bit, 1 = negative, 0 = positive
E: exponent (in two bytes), offset 127
M: 23-digit mantissa, the highest digit is "1"
The floating point value 12.5 is 0xC1480000 in hexadecimal, which is stored as follows:
Address: +0 +1 +2 +3
Contents: 0x00 0x00 0x48 0xc1
The 8051 does not include an interrupt vector to catch floating point errors (exceptions). The user software must therefore react appropriately to error conditions. The following is a recommended method (other reliable methods can also be used): a "union" is used to store floating point values. This "union" must include a "float" and an "unsigned long" to respond to errors according to IEEE. In addition to the usual floating point values, the IEEE standard possible error conditions are represented by the following binary values. In order to check for possible calculation errors, they can be checked after the calculation. Because when an operation is performed, the error status of each operator is taken into account and the status is sent to the result.
NaN 0xFFFFFFF is not a number
+INF 0x7F80000 Positive infinity (positive overflow)
-INF 0XFF80000 negative infinity (negative overflow)
1.3 Expanded Definition of C-51
1.3.1 Declaration of Special Function Registers
The MSC-51 series includes a variety of registers, some of which have special functions, such as timers, port control registers, etc. In order to be able to directly access these registers, the C51 compiler provides an autonomous form of definition, which is necessary because these definitions are incompatible with the standard C language.
To support the declaration of these special function registers (SFRs), the keyword "sfr" is introduced, with the following syntax:
sfr-dcl:sfr sfr_name=int_constant
example:
sfr p0=0x80;
sfr p1=0x90;
It must be noted that "sfr" is not followed by an address but a name. Therefore, in the above example, the names P0 and P1 (port0 and port1) are defined as special function registers and are assigned corresponding absolute addresses. The names can be freely selected as desired, and there should be no sfr names defined in the source file.
The address after the "=" sign must be a constant. Expressions with operators are not allowed. This constant expression must be within the address range of the special function register, between 0X80 and 0XFF.
The number and type of registers in the 8051 family are extremely different, so it is recommended that all special "sfr" declarations be placed in a header file that includes the SFR definitions for some members of the 8051 family. Further definitions can be generated by the user using a text editor.
1.3.2 16-bit data access to SFR
In the new 8051 series, SFRs are often functionally combined into 16 bits. In order to effectively access such SFRs, the definition "sfr16" is used. When the high end of "SFR" is directly after the low end, access to SFR16 bits is possible. For example, this is the case with Timer 2 of 8052. The syntax of the 16-bit declaration is the same as "sfr". The low address part of the SFR must be used as the address of sfr16:
例:sfr16 T2=0xCC /*Timer2:T2L=0CCH,T2H=0CDH */
sfr16 RCAP2=0xCA /*RCAP2L=0CAH,PCAP2H=0CBH */
In this example, T2 (consisting of T2L and T2H) and RCAP2 (consisting of RCAP2L and RCAP2H) are defined as 16-bit SFRs. Even in this case, the name in the declaration is not followed by an assignment statement, but by an SFR address. The high byte must be directly after the low byte. This declaration applies to all new SFRs, but not to Timer0 and Timer1.
1.3.3 SBIT: Special Function Bit Declaration
In typical 8051 application problems, it is often necessary to access the bits in SFR individually. C51 expansion functions make this possible. Special bits, like SFR, are not compatible with standard C language. The reserved word "sbit" can be used to access bit addressing objects. As with SFR declarations, the reserved word "sbit" is used to declare certain special bits to accept symbolic names. The statement after "=" assigns the absolute value address to the variable name. There are three methods for this address assignment:
Method 1: sfr_name^int_constant
This method can be used when the byte is the address of a special function register. sfr_name must be the name of a defined SFR, and the statement after "^" defines the position of the special bit on the base address, which must be a number from 0 to 7.
例: sfr PSW="0xD0";
sfr LE="0xA8";
sbit OV="PSW"^2;
sbit CY="PSW"^7;
方法2:int_constant^int_constant
This method uses an integer constant as the base address. The value must be between 0x80 and 0xFF and divisible by 8. The method for determining the bit position is the same as above.
例: sbit OV="0xD0"^2;
sbit CV="0xD0"^7;
sbit EA="0xA8"^7;
Method 3: int_constant
This method assigns the absolute address of the bit to the variable, and the address must be between 0x80 and 0xFF.
例: sbit OV="0xD2";
sbit CY="0xD7";
sbit EA="0xAF";
Special function bits represent a separate class of declarations that are not interchangeable with other declarations and bit fields.
1.3.4 BIT: Bit Scalar Declaration
In addition to the usual C data types, the C51 compiler supports the "bit" data type, with the following extensions and restrictions:
(1) A function can have parameters of type "bit" and can also return them.
bit bfunc(bit b0,bit b1){
/*……*/
return(b1);
}
Note: Functions that disable interrupts (#pragma disable) or contain explicit register bank switching (using n) cannot return bit values. In this case, the compiler will recognize this and generate an error message.
(2) Syntax of bit scalar declaration and semantics of C declaration
static bit dirction_bit;
extern bit lock_printer_port;
bit display_invers;
(3) Restrictions on bit declarations
l Bit cannot be declared as a pointer (bit *bit_pointer)
l The bit array does not exist (bit b_array[5])
The memory type can be defined in the bit declaration. The bits are placed in a bit segment, which is always in the internal RAM of 8051. Therefore, the memory type is limited to DATA or IDATA. Declaring other memory types will result in compilation errors.
1.3.5 Bit-addressable objects
A bit-addressable object is an object that can be addressed by a byte or bit. This happens when the object is located in the MSC-51 addressable RAM. C51 allows objects with the "bdata" type to be placed in bit-addressable memory.
bdata int ibase; /*bit addressing pointer int*/
bdata char bary[4]; /*bit addressable array arrray*/
Use "sbit" to declare bits of a bit-addressable object that can be accessed independently:
sbit mybit0=ibase^0;
sbit mybit15=ibase^15;
sbit ary07=bary[0]^7;
sbit ary37=bary[3]^7;
The objects "ibase" and "bary" are also bit-addressable:
ary37 = 0; /*Addressing bit 7 in "bary[3]"*/
ibase=-1; /*addressing byte address*/
mybit15 = 0; /* addressing bit 15 of "ibase" */
The sbit declaration requires the base object to have storage type "bdata", otherwise only the absolute bit declaration method is legal. The maximum value of the bit position (after the '^' operator) depends on the specified base type, which is 0 to 7 for char/uchar, 0 to 15 for int/uint/short/ushort, and 0 to 31 for long/ulong.
In the compiler, the memory type bdata is operated in the same way as data, and only operates with relocatable sbits. Note: The maximum length of a bit-addressable segment cannot exceed 16 bytes. Relocatable sbit declarations are automatically converted to public (PBULIC) so that they can be used by other C modules.
Module 1: sbit ary37=bary[3]^7;
Module 2: extern bit ary37;
The sbit declaration can also be used for structures and functions:
union lft {float mf;long ml;} ;
bdata struct bad { char ml; union lft u; }tcp;
sbit tcpf31=tcp.u.ml^31; /*floating point limit*/
sbit tcpml0=tcp.ml^0;
sbit tcmpl7=tcp.ml.^7;
Note: Bit position specification cannot be used directly with float types. If this is required, the floating point scalar must be placed in a union with a long integer scalar and the bit position must be specified using the long integer header (see example above).
1.4 Memory Type
The C51 compiler fully supports the architecture of the 8051 microprocessor and its series, and can fully access all parts of the MCS-51 hardware system. Each variable can be accurately assigned a different storage type (data, idata, pdata, xdata, code). Accessing the internal data storage (idata) is relatively faster than accessing the external data storage (xdata). Therefore, frequently used variables can be placed in the internal data storage, while larger and rarely used data units can be placed in the external data storage.
Memory Type |
describe |
data |
Directly address internal data memory, fastest access to variables (128 bytes) |
bdata |
Bit-addressable internal data memory, allowing mixed bit and byte access (16 bytes) |
iData |
Indirect addressing of internal data memory, access to the entire address space (256 bytes) |
pPdata |
Paged (256 bytes) external data memory, accessed by opcode MOVX @Ri |
xdata |
External data memory (64K), accessed by MOVX @DPTR |
code |
Code data memory (64K), accessed by MOVC @A+DPTR |
Example of variable declaration:
data char charvar;
char code msg[]=”ENTER PARAMETER:”;
unsigned long xdata array[100];
float idata x,y,z;
unsigned char xdata vector[10][4][4];
sfr p0=0x80;
sbit RI="0x98";
char bdata flags;
sbit flago="flags"^0;
If the storage type identifier is omitted when declaring a variable, the compiler automatically selects the default storage type. The default storage type is further limited by the control instructions SMALL, COMPACT, and LARGE. For example: if char charvar is declared, the default storage mode is SMALL, and charvar is placed in the data storage; if the COMPACT mode is used, charvar is placed in the idata storage area; when the LARGE mode is used, charvar is placed in the external storage area or the xdata storage area.
1.5 Memory Mode
The memory mode determines automatic variables and the default memory type, parameter passing area and instructions for no explicit memory type. Parameter passing in fixed memory address variables is a standard feature of C51. In SMALL mode, parameter passing is done in the internal data storage area. LARGRE and COMPACT modes allow parameters to be passed in external memory. C51 also supports mixed modes. For example, a program generated in LARGE mode can page some functions into SMALL mode to speed up execution.
Memory Mode |
describe |
SMALL |
Parameters and local variables are placed in directly addressable internal registers (maximum 128 bytes, default memory type is DATA) |
COMAPCT |
Parameters and local variables are placed in the external internal storage area (maximum 256 bytes, the default storage type is PDATA) |
LARGE |
Parameters and local variables are directly placed in external data memory (maximum 64K, default memory type is XDATA) |
1.6 Pointers
The Franklin C-51 supports both "memory-based" and "general pointers".
1.6.1 Memory-Based Pointers
Memory-based pointers are determined by the memory type in the C source code and determined at compile time. Objects can be accessed efficiently with this pointer and only require one byte (idata*, data*, pdata*) or 2 bytes (code*, xdata*). Code that operates on shorter pointers is shortened and is generally coded "inline"; library calls are no longer necessary.
Statement example:
char xdata *pt |
Declare a pointer to an object of type "char" in the xdata memory. The pointer is stored in the default memory area (depending on the compilation mode) by default, with a length of 2 bytes. (The value is 0 to 0xFFFF) |
char xdata *data pdx; |
Same as above, except the pointer is explicitly located in internal data memory (data). It is independent of the compilation mode. |
data char xdata *pdx; |
This example is identical to the previous one. The storage type definition can be placed at the beginning of the declaration or directly before the object being declared. This form is for compatibility with earlier versions of the C-51 compiler. |
The above examples illustrate the general declaration and use of pointers. They are relevant to all data types and memory types. All operations for general pointers can also be used for memory-based pointers.
1.6.2 General pointers
A "general" pointer requires 3 bytes: 1 byte for the storage type and 2 bytes for the offset. The storage type determines the 8051 memory space used by the object, and the offset points to the actual address. A "general" pointer can access any variable regardless of its location in the 8051 memory space. This allows general functions such as memcpy to copy data from any address to another address space.
1.6.3 Conversion between memory-based pointers and general pointers
A positioned pointer can be converted to a normal pointer (3 bytes) and a copy. This is sometimes useful. For example, library functions like printf(), sprintf(), gets() etc. contain a normal pointer variable, as in previous compiler and library versions. These functions are therefore widely applicable.
例:extern int printf(void *format,…);
In the printf call, the 2-byte pointer is automatically converted to a 3-byte pointer, and the prototype of printf expects a normal pointer (3 bytes) as its first argument.
Note: If there is no function prototype, the pointer in the function call parameter is always converted to a general pointer. If the function does require a short pointer as a parameter, this will cause an error. In order to avoid such errors in the program, you need to use header files or some function declarations to declare function prototypes. This will ensure that the compiler converts to the required type, otherwise a type mismatch error will occur.
Example: Pointer definition
Pointer Description |
length |
direction |
float *p; |
3 bytes |
All "float" (general pointers) in the 8051 memory space |
char data *dp; |
1 byte |
"char" in "data" memory |
int idata *ip; |
1 byte |
"int" in "idata" |
long pdata *pp; |
1 byte |
'long' in 'pdata' |
char xdata *xp; |
2 bytes |
"char" in "xdata" |
int code *cp; |
2 bytes |
"int" in "code" |
1.6.4 Abstract pointer types
Abstract pointer types are used to access any absolute address in each storage area, or to generate absolute CALLs. In this process, constant types or character types, integer types are modified in principle (type arrangement) with abstract types to allow absolute access or calls.
example:
char xdata *px;
char idata *pi;
char code *pc;
char c;
int i;
pc = (void*)main;
i = ((int(code*)(void))0xFF00(); /*LCALL 0FF00H */
c = *((char code*)0x8000); /*char [code[0x8000]]*/
i = *((int code*)0x1200); /*int from code[0x1200]*/
px = *((char xdata *xdata*)0x4000); /*x ptr from xdata[0x4000]*/
px = ((char xdata *xdata*)0x4000)[0]; /*same as above*/
px = ((char xdata *xdata *)0x4000)[1] /*x ptr from xdata[0x4002]*/
1.7 Register Group Definition
The 8051 series devices contain four identical register banks, each of which contains eight registers (R0 to R7). The C51 compiler makes it possible to decide which register bank to use in a function. Absolute register access can be controlled using AREGS/NOAREGS and REGISTERBANK.
The syntax for defining a function with extensibility is as follows:
return type function name ([parameters]) [mode] [reentrant] [interrupt n] using n
Reentry and interruption are discussed in the next two sections.
例:void rb_function(void) using 3;
"using" is not allowed for external functions. It affects the object code of the function as follows:
l Save the current register into the stack at the function entry;
l means that its register will also change;
l The register set is restored before the function exits.
The "using" definition is useless for functions that return a value in a register. The programmer must be very careful to ensure that any register switching occurs only in carefully controlled areas. Failure to do this will produce incorrect function results. Even when the programmer uses the same register set, a function with the "using" attribute cannot in principle return a bit value.
The actual code generated depends on the compiler and different switch conditions. Sometimes commands are used to generate absolute register addresses. When such address calculations are required, the use of the REGISTERBANK instruction only affects the calculation of the address used by the Arn register, and actual switching is not required.
1.8 Interrupt Service Routine
The C51 compiler and its extensions to the C language allow programmers to control all aspects of interrupts. This support enables system programmers to create efficient interrupt service routines. Users only need to care about interrupts and necessary register bank switching operations in normal and advanced modes, and the C51 compiler will generate the most appropriate code.
1.8.1 Definition of Interrupt Service Routine
The complete syntax for using an interrupt service function is as follows:
return value function name ([parameters]) [mode] [reentry] interrupt n [using n]
"interrupt" is followed by a constant from 0 to 31. Expressions are not allowed.
Interrupts are not allowed in external functions. Their effects on the function's target code are as follows:
When a function is used, ACC, B, DPH, DPL, and PSW (when needed) in SFR are pushed onto the stack;
If register bank switching is not used, even all working registers (Rn) required by the interrupt function are pushed onto the stack;
Before the function exits, all register contents are popped from the stack;
l The function is terminated by the 8051 control command "RETI".
1.8.2 Rules for developing interruption procedures
l Parameter passing is not possible. If the interrupt procedure includes any parameter declaration, the compiler will generate an error message;
l No return value. If you want to define a return value, an error will occur. However, if an integer value is returned, the compiler will not generate an error message because the integer value is the default value and the compiler cannot clearly identify it.
The compiler will recognize direct calls to interrupt procedures and reject them. In any case, an interrupt procedure cannot be called directly because exiting the procedure is accomplished by the opcode RETI. RETI affects the hardware interrupt system of the 8051 chip. Since no interrupt request exists in the hardware, the results of this opcode are undefined and usually fatal. It is worth noting that it is possible to call it indirectly using a pointer due to inadvertent errors.
The compiler generates an interrupt vector from the absolute address 8n+3, where n is the interrupt number. The vector includes a jump to the interrupt procedure. The vector generation can be compressed by the instruction NOINTVECTOR. Thus, the user has the ability to provide interrupt vectors from a separate assembly module.
The C51 compiler allows 0 to 31 interrupts. Which interrupts are allowed depends on the 8051 series chip used and cannot be checked by the compiler.
l If there is floating-point operation in the interrupt program, the floating-point register status must be kept. When no other program performs floating-point operation, it may not be saved. The functions "fsave" and "fprestore" are used to save the floating-point status.
l The registers used by the function called by the interrupt procedure must be the same as those used by the interrupt procedure. When the "using" directive is not used, the compiler will select a register group for absolute register access. An error will occur when the subroutine uses another register group. The user must ensure that the corresponding register group is used as required. The C compiler will not check this.
example:
unsigned int interruptent;
unsigned char second;
time() interrupt 1 using 2 /*Timer 0 interrupt service routine, working register uses area 2*/
{
if(++interruptcnt==4000) {
second++; /*second count plus one*/
interruptcnt=0; /*clear interrupt count*/
}
}
1.9 Reentry Function
Reentrant functions can be called recursively, and the call can occur at any time, even during an interrupt. Reentrant functions are often required in real-time processing applications.
The keyword "reentrant" can be used to optionally define a function as reentrant. A stack area is simulated in internal or external memory for the reentrant function based on the memory model. Since the MCS-51 lacks a suitable addressing method, the use of a stack structure is quite necessary. Therefore, the use of reentrant functions should be minimized.
The syntax for defining a reentrant function is as follows:
return value function name ([parameters]) [mode] reetrant [interrupt n] [using n]
example:
int calc(char i,int b) reentrant {
int x;
x=table[i];
return(x*b);
}
The following rules apply to the use of reentrant functions:
l You cannot pass a parameter of type "bit". You cannot declare a local scalar, and reentrant functions cannot include bit operations and MCS-51 bit-addressable areas.
l You cannot call a reentrant function from an "alien" function.
Reentrant functions can also have other attributes, such as the "using" function mode and "interrupt".
Reentrant functions cannot also have the "alien" attribute, thus complying with PL/M rules.
l The return address and possible PUSH/POP operations are stored in the MCS-51 stack or executed (not in the re-stack).
In the same module, reentrant functions of any module (small reentrant, lage reentrant, compact reentrant) cannot be mixed with reentrant functions with different modes.
Reentrant function example:
/*This reentrant function can be called from "main" and interrupt routines*/
int calc(char i,int b)reentrant {
int x;
x=table[i];
return(x*b);
}
1.10 Parameter Passing
Up to three parameters can be passed through the CPU registers. This produces an effective parameter mechanism equivalent to that of an assembler subroutine. If registers are occupied or "#pragma NOREGPARMS" is specified, the parameter variables will use fixed memory locations. The memory mode determines the locations provided by the 8051 memory for the parameters.
Table: Candidate parameter registers
Parameter Type |
char, 1-byte pointer |
int, 2-byte pointer |
long,float |
General pointers |
One parameter |
R7 |
R6,R7 |
R4~R7 |
R1,R2,R3 |
Two parameters |
R5 |
R4,R5 |
R4~R7 |
R1,R2,R3 |
Three parameters |
R3 |
R2,R3 |
… |
R1,R2,R3 |
The return value of the function is placed in a fixed register of the CPU, as shown below. This makes it very easy to interface with the assembly subroutine.
Table: Register usage of function return values
return value |
register |
significance |
bit |
Carry flag C |
|
(unsigned) char |
R7 |
|
(unsigned) int |
R6,R7 |
High position is at R6, low position is at R7 |
(unsigned) long |
R4~R7 |
High position is at R4, low position is at R7 |
float |
R4~R7 |
32-bit IEEE format |
pointer |
R1,R2,R3 |
Type selection is in R3, high position is in R2, low position is in R1 |
1.11 PL/M51 interface
Franklin C51 provides a direct and simple interface to Intel PL/M-51 using the keyword "alien", which is available for "extern" and "public" functions in all memory modes. Existing PL/M-51 programs can be connected to Franklin C-51 using the powerful functions of the C language.
Using the keyword "alien", C51 can work with the parameter passing method specified by PL/M-51. "alien" can be used for external or public functions and can be used in any mode, so that existing PL/M-51 programs can be added to C-51. Alien functions always contain a standard number of parameters, so the three-dot (...) notation defined in C is not accepted and an error message is generated.
example:
extern alien char plm_function(unsigned char,unsigned int);
extern char c_function(unsigned char x,unsigned char y) {
return(x*y);
}
PL/M-51 compatible functions must be defined with the keyword "alien". In this way, the parameter passing and parameter return rules of the PL/M function are considered by the C compiler.
1.12 Assembly Interface
Parameters are passed to the assembler through fixed CPU registers. When "#pragma NOREGPARMS" is used, parameters are passed through fixed memory locations. This provides a very simple interface between the assembler and Franklin C-51. The return value is in the CPU register.
The following example shows the "toupper" function coded in assembly, where parameter passing occurs in registers.
UPPER SEGMENT CODE; program code segment
PUBLIC _toupper ; Entry address
RESG UPPER ; Select program code segment
toupper: MOV A,R7; char parameter is in register R7
CJNE A,#'a',UPP1
UPP1: JC UPPERT
CJNE A,#’z’+1,UPP2
UP2: JNE UP
CLR ACC.5
UPPRET: MOV R7,A ; char return value is in register R7
RET ; Return to C
1.13 Internal functions
The Franklin C-51 supports the following intrinsic functions. Intrinsic functions are both reentrant and valid.
Table: C51 internal functions
function |
describe |
memcpy,memsset,memchr,memmove,memcmp |
ANSI memory manipulation functions |
strcmp,strcpy |
ANSI string processing functions |
_crol_,_irol_,lrol_ |
Shift character, integer, long integer left |
_crolr_,_irolr_,lrolr_ |
Shift right a character, integer, or long integer |
_nop_ |
No Operation |
_test piece_ |
Test and clear (JBC instruction) |
1.14 Code Optimization
Franklin C51 can optimize the code written by even experienced programmers. The user can select 6 optimization levels. In addition, the use of OPTIMIZE (SIZE), NOREGPARMS and NOAREGS will affect the type of generated code. All optimizations of C51 are as follows:
(1) General optimization:
l Constant folding: Several constant values occurring in an expression or address calculation are combined into one constant.
l Jump optimization: Jump to the final target address to improve program efficiency.
l Dead code elimination: Non-executable code (dead code) can be removed from the program.
l Register variables: Whenever possible, automatic variables and parameters are placed in registers, and the data memory reserved for these variables is removed.
l Passing parameters through registers: Up to three parameters can be passed in registers.
Global common subexpression elimination: Identical subexpressions or address calculations that occur multiple times in the same function are identified and, whenever possible, evaluated only once.
(2) Optimization based on 8051:
l Peephole optimization: Complex operations are simplified whenever possible to save storage space or execution time.
l Access optimization: constants and variables are directly included in the operation.
l Data overlay: The function's data and displacements are marked as OVERLAYABLE and are overwritten by L51 with other data and bits.
l CASE/SWITCH optimization: SWITCH/CASE statements are optimized to one jump or a series of jumps.
(3) Code generation options:
l OPTMIZE (SIZE): Common "C" operations are replaced by subroutines: program code length is compressed.
l NOAREGS: Absolute register access is not used. The program code is independent of the register group in this way.
l NOREGPARMS: Parameter passing is always done in this data segment, and the program code is compatible with earlier C-51 versions.
1.15 C Library
The C-51 compiler contains 6 different compiled libraries that can be optimized according to the needs of different functions. These libraries support almost all ANSI function calls. Therefore, C programs using this standard can run immediately after compilation and linking.
Library |
describe |
C51S.LIB |
SMALL mode, no floating point operations |
C51FPS.LIB |
Floating point math library (SMALL mode) |
C51C.LIB |
COMPACT mode, no floating point operations |
C51FPC.LIB |
Floating point arithmetic library (COMPACT mode) |
C51L.LIB |
LARGE mode, no floating point operations |
C51FPL.LIB |
Floating point arithmetic library (LARGE mode) |
The C51 compiler contains library modules with source code that can be modified to suit the hardware. Users can modify all library functions by changing two modules for the existing hardware input and output structures. They can also quickly reconstruct functions such as "printf" and "puts" for LCD display.
The L51 linker checks thus ensure that all modules are compiled with one mode and automatically selects the compiled library, thus completely freeing the user from the details of the different libraries.
1.16 Configuration Files
The C51 compiler can be modified by 4 files according to different hardware environments. The following configuration files are included in the C-51 software package:
STARTUP51.51:
|
The startup routine of the C51 compiler, all stack pointers and memories, as long as they are needed, will be initialized. |
HEAT.A51:
|
The variables are initialized explicitly in the file. If the system has a watchdog installed, this file may contain additional watchdog updates. |
PUBCHAR.C: |
The character output core program of functions such as "printf", "puts", etc., which can be modified according to the user's hardware (such as LCD display). |
GETKEY.C: |
The character input core program of functions such as "getchar", "scanf", etc., which can be modified according to the hardware (such as matrix keyboard). |
All files are included in the C runtime library, so they cannot be called when linking. If the user changes a file, it can be compiled and linked with other target files, so there is no need to change the runtime library. The original files in the library are automatically ignored.
example:
L51 DEMO1.OBJ,DEMO2.OBJ,STARTUP.OBJ,PUTCHAR.OBJ
This example connects the STARTUP.OBJ and PUTCHAR.OBJ created by the user.
STARTUP.A51
The beginning of the file STARTUP.51 contains some EQU statements used by the C compilation structure. The function of each EQU statement is described as follows:
IDATALEN declares how much memory needs to be initialized with 0 when the system starts. The default value is 80H, because almost every
The 8051 instruction set includes at least 128 bytes of internal RAM. For the 8052 with 256 bytes of internal RAM, 100H can be used. This change is only necessary when the user program needs to use zero-initialized memory at the beginning. If the memory initialization must keep the power-down mode system completely suppressed, IDATALEN should be set to 0. In this case, at least all variables located in the segments ?C_LIB_DATA and ?C_LIB_DBIT must be set to 0. Otherwise, some library functions will not work completely. The length of the ?C_LIB_DATA segment varies depending on the application problem. Its current length can be found in the MAP file.
XDATASTART
XDATALEN indicates the starting address and length of the PDATA area that needs to be initialized with 0, XDATASTART indicates the starting address of the XDATA area, and XDATALEN indicates the number of bytes that need to be initialized.
PDATA START
PDATALEN indicates the starting address and length of the PDATA area that needs to be initialized with 0, PDATASTART indicates the starting address, and XDATALEN specifies the length.
LBPSTACK
LBPSTACKTOP defines the stack area used by reentrant functions created in SMALL mode. LBPSTACK indicates whether the stack pointer (variable? C_LBP) is initialized, and LBPSTACKTOP indicates the top address of the stack. For 8051 systems with 256 bytes of internal RAM, when the storage area is used as a stack with a starting address of 0XFF, it can be left uninitialized. C51 does not check whether the stack area meets the requirements of a specific application, and the user must test it himself.
XBPSTACK
XBPSTACKTOP defines the stack area for reentrant functions created in LARGE mode. XBPSTACK indicates whether the pointer (variable? C_XBP) is initialized, and XBPSTACKTOP specifies the top address of the stack. When the storage area is used as a stack with the first address 0Xffff (in the XDATA area), initialization is not required. As above, C51 does not perform stack checking, and users need to test it themselves.
PBPSTACK
PBPSTACKTOP defines the stack area for reentrant functions created in COMPACT mode. PBPSTACK indicates whether the stack pointer (variable? C_PBP) is initialized. PBPSTACKTOP specifies the top address of the stack. When the storage area is used as a stack with the first address 0Xff (in the PDATA area), initialization is not required. As above, C51 does not perform stack checking, and users need to test it themselves.
PPAGEENABLE
PPAGE These instructions are needed when using 16-bit addressing of the XDATA memory area in COMPACT mode. They can be used to increase the speed or reduce the code size of programs using LARGE mode. PPAGEENABLE allows the initialization of port 2 of the 8051. Addressing port 2 allows the mapping of 256 bytes of variable space in any XDATA page. These two instructions must be used in conjunction with the L51 control instruction PDATA. PDATA specifies the first address of the PDATA area in XDATA memory. Example: In STARTUP.A51, PPAGEENABLE is set to 1 and PPAGE is set to 10H. In this case, the first address of the PDATA area is 1000H (page 10H), and L51 must contain a control statement with a value between 1000 and 10FFH: L51 PDATA (1050H). Note: Neither the L51 nor the C51 checks the correctness of the PPAGE/PDATA instructions. The user must ensure that PPAGE and PDATA contain an appropriate value.
HEAT.A51:
The file INIT.A51 contains a macro that defines the refresh of the "watchdog". This macro must be changed when the system includes a "watchdog" and the user variable initialization time is longer than the refresh time of the "watchdog". In this case, the macro WATCHCOG must contain the code for the refresh of the "watchdog".
例: ;Watchdog refresh for 80515 system
WATCHDOG MACRO
SETB WDT
SETB SWDT
ENDM
PUTCHAR.C
The file PUTCHAR.C contains the core program for character output, which is output through the serial port. In this case, the XON/XOFF protocol is taken into account, and the character LF() is converted to the string CR, LF, which is required in many terminals. Users can change the putchar() function according to their requirements.
GETKEY.C
The file GETKEY.C contains the core program for character input. This file reads a character from the serial interface without performing data conversion. The user can modify the getkey() function as needed.
This section contains several notes on how to improve the efficiency of 8051 programs.
Positioning variables
Frequently accessed data objects should be placed in the on-chip data RAM, which can be achieved by inputting the memory type in either mode (COMPACT/LARGE). Accessing the on-chip data RAM is much faster than accessing the external data memory. The on-chip RAM is shared by the register group, the bit data area stack and other variables defined by the user with the "data" type. Due to the limited capacity of the on-chip RAM (128 to 256 bytes, determined by the processor used), a trade-off must be made to resolve the contradiction between access efficiency and the number of these objects.
Always use the smallest possible data type
The 8051 series CPUs are all 8-bit machines, so it is obviously much more convenient to operate on objects of type "char" than on objects of type "int" or "long". It is recommended that programmers use the smallest data type as long as it meets the requirements.
The C51 compiler directly supports all byte operations, so if it is not required by the operator, no "int" type conversion is performed. This can be clearly illustrated by a product operation. The product of two "char type" objects just matches the 8051 operation code "MUL AB". If the same operation is performed with integer quantities, a library function needs to be called.
Whenever possible, use the "unsigned" data type
The 8051 series CPU does not directly support operations on signed numbers. Therefore, the C51 compiler must generate more code to solve this problem. If unsigned types are used, much less code is generated.
Whenever possible, use local function variables
The compiler always tries to keep local variables in registers. Thus, it is best to declare index variables (such as counter variables in FOR and WHILE loops) as local variables, and this optimization step is performed only for local variables. Using "unsigned char/int" objects usually gives the best results.
2 C51 Compiler Control Instructions
Compiler options may be enabled, disabled, or changed by control directives. These directives may be entered on the command line or by adding #pragma to the preprocessor in the source file. Control directives are divided into two groups, primary and general, and into three categories: source control, target control, and list control. See Table 2.1 for Compiler Control Directives. The "P/G" column indicates whether the directive is primary or general. Primary directives appear only once, while general directives may appear as many times as needed.
Table 2.1 Compilation control instructions
Classification |
P/G
|
instruction |
abbreviation |
default value |
source |
P G G G P |
DEFINE SAVE RESTORE DISABLE [NO]EXTEND |
DF — — — —— |
— — — — EXTEND |
Target |
P P P P P P G G G P P P |
[NO]DEBUG [NO]OBJECT OPTIMIZE(n) SMALL COMPACT LARGE [NO]REGPARMS REGISTERBANK(n) [NO]AREGS [NO]INTVECTER OBJECTEXTEND ROM() |
[NO]DB [NO]S OT SM CP THE [NO]RP RB [NO]AR [NO]IV ARE YOU — |
NODEBUG OBJECT(name.OBJ) OPTIMIZE(2) SMALL — — REGPARMS REGISTER BANK(0) AREGS INTVECTOR — ROM(LARGE) |
List |
P P P P P P P G P |
[NO]LISTINCLUDE [NO]SYMBOLS [NO]PREPRINT [NO]CODE [NO]PRINT [NO]CODE PAGELENGTH(n) EJECT PAGEWIDTH(n) |
[NO]LC [NO]SB [NO]PP [NO]CD [NO]PR [COME ON PL NOT PW |
NOLISTINCLUDE NOSYMBOLS NOPREPRINT NOCODE PRINT(name.OBJ) CODE PAGELENGTH(69) — PAGEWIDTH(132) |
2.1 Source Control
2.1.1 DEFINE
Name: DEFINE
Abbreviation: DF
Variable: One or more names separated by commas, consistent with the command specifications of the C language.
Default value: None
The DEFINE directive defines names used on the command line. It can be used for conditional compilation of preprocessing commands such as "if", "ifdef" and "ifndef". The defined names are copied exactly and are therefore case sensitive.
例: C51 DEMO.C DEFINE(check,NoExtRam)
2.1.2 SAVE/RESTORE
Name: SAVE/RESTORE
Abbreviation: None
Variable: None
Default value: None
The SAVE directive stores the current ARGES, REGPARMS, OPTIMIZE factors, and SPEEDSIZE settings for the optimization options. In this way, the settings described above are preserved, e.g. by saving with SAVE before a #INCLUDE statement and then restoring with the RESTORE directive.
SAVE/RESTORE can only appear as a parameter of the #pragma statement in the source file and cannot be used on the command line.
example:
#pragma save
#pragma noregparms
extern void test1(char c,int I);
extern char test2(long l,float f);
#pragma restore
The in-register parameter passing of the two external functions is disabled, and then the settings at the time of the SAVE instruction are restored.
2.1.3 DISABLE
Name: DISABLE
Abbreviation: None
Variable: None
Default: None
The DISABLE directive disables interrupts during the execution of a function. DISABLE must be specified with #pragma before the function and can only be used in one function, so it is set internally by the compiler. Each interrupt to be disabled must include a separate #pragma specification before the function and cannot be used on the command line.
例: typedef using char uchar;
#pragma disable /*Disable interrupts */
fly dfunc(fly p1,fly p2) {
return(p1*P2+P2*p1);
}
2.1.4 EXTEND/NOEXTEND
Name: EXTEND/NOEXTEND
Abbreviation: None
Variable: None
Default value: EXTEND
The EXTEND directive supports special extensions of ANSI-C to C51. The NOEXTEND directive makes the compiler process only ANSI-C. Various reserved words such as bit, reentrant, using, etc. are unknown to the compiler.
Example: C51 DEMO.C NOEXTEND
#pragma NOEXTEND
2.2 Target Control
2.2.1 DEBUG/NODEBUG
Name: DEBUG/NODEBUG
Abbreviation: DB/NODB
Variable: None
Default value: NODEBUG
The DEBUG directive instructs the compiler to add debugging information to the target file. This information is necessary for symbolic debugging, and includes the definitions and addresses of global and local variables, as well as function names and line numbers. The debugging information in the target module remains valid during the connection process with L51, and it can also be used by emulators compatible with dscope-51 or Intel. The NODEBUG directive indicates that debugging information is not added to the target file. QTH recommends that users add DB information.
Example: C51 DEMO.C DEBUG
#pragma db
2.2.2 OBJECT/NOOBJECT
Name: OBJECT/NOOBJECT
Abbreviation: OJ/NOOJ
Variable: The file name in brackets
Default value: OBJECT(bname.OBJ)
The OBJECT(filename) directive changes the name of the generated target file. The default value is the path name plus the basic extension ".OBJ". The NOOBJECT directive does not generate a target file.
Example: C51 DEMO.C NOOBJEECT
#pragma oj(demo.obj)
2.2.3 OBJECTEXTEND
Name: OBJECTEXTEND
Abbreviation: OE
Variable: None
Default value: None
OBJECTEXTEND causes the compiler to generate an object file containing additional variable type definition information. This information can be used to distinguish object modules with the same name for use by different simulators.
Note: This control is not required for QTH series simulators.
2.2.4 OPTIMIZE
Name: OPTIMIZE
Abbreviation: OT
Variable: A decimal number between 0 and 5 in brackets, and optional OPTIMIZE (SIZE) and OPTIMIZE (SPEED)
To decide whether to focus on code size or execution speed.
Default value: OPTIMIZE(2,SPEED).
The OPTIMIZE directive sets the optimization level. In this setting, a higher optimization level includes the settings of the previous lower optimization level.
(1) OPTIMIZE(0)
l Constant folding: Whenever possible during compile time, the compiler performs calculations involving constants, including performing address calculations.
l Simplified access: Optimize access to internal data and addresses of the 8051 system.
l Jump optimization: The compiler always delays the jump to the final target, so the jump instruction is eliminated.
(2) OPTIMIZE(1)
l Dead code elimination: Useless code will be eliminated.
l Jump veto: Based on a test feedback, conditional jumps are carefully examined to determine whether they can be simplified or eliminated.
(3) OPTIMIZE(2)
l Data coverage: Data and bit segments suitable for static coverage are identified and marked. L51 has such a function, through the analysis of the global data flow, to select the segments that can be statically covered.
(4) OPTIMIZE(3)
l "Peephole" optimization: redundant MOV instructions are deleted, including unnecessary operations of loading objects and constants from memory. In addition, when it can save memory space or execution time, complex operations are replaced by simple operations.
(5) OPTIMIZE(4)
l Register variables: Automatic and parameter variables are located in registers. Whenever possible, no data memory space will be reserved for these variables.
l Extended access optimization: Variables from the IDATA, XDATA and CODE areas are directly included in the operation, so loading intermediate registers is unnecessary most of the time.
Elimination of local common subformulas: If there is a repeated calculation in an expression, the result of the first calculation will be used for subsequent calculations whenever possible, thus eliminating complex calculations from the code.
l CASE/SWITCH optimization: CASE/SWITCH statements are optimized as jump tables or jump strings.
(6) OPTIMIZE(5)
l Global common subexpression elimination: Whenever possible, identical subexpressions within a function are calculated only once. Intermediate results are stored in a register instead of being recalculated.
Simple loop optimization: loops that occupy a memory segment with constants are transformed and optimized at runtime. OPTIMIZE (5) includes all optimizations from level 0 to level 4.
例: C51 SAMPLE.C OPTIMIZE(4)
#pragma ot(5,SIZE)
#pragma ot(size)
Note: Global optimization starts at optimization level 4. Also, when a complete function is optimized, if
Insufficient memory for data structures necessary for optimizing code, global optimizations are performed only partially or not at all.
2.2.5 SMALL/COMPACT/LARGE
Name: SMALL/COMPACT/LARGE
Abbreviation: None
Variable: None
Default value: SMALL
The instructions SMALL, COMPACT, LARGE control the memory mode selection. The memory mode has an impact on different variable definitions.
SMALL:
All functions and process variables and local data segments are defined in the 8051 system internal data memory, so accessing data objects in this mode is very efficient. The disadvantage of this mode is that the address space is limited.
COMPACT:
All functions and process variables and local data segments are defined in the 8051 system external data memory, which can be up to 256 bytes (1 page). This mode uses a concise form of accessing the external data memory (@R0/R1).
LARGE:
All variables and local variable data segments are defined in the external data memory of the 8051 system, which can access up to 64K bytes of address space. Therefore, it needs to pass the data pointer (DPTR), which is an inefficient form of data access.
Note: The stack for calling subroutines is always placed in internal memory.
例: C51 SAMPLE.C LARGE
#pragma compact
2.2.6 REGPARMS/NOREGPARMS
Name: REGPARMS/NOREGPARMS
Abbreviation: RP/NORP
Variable: None
Default value: REGPARMS
When using the REGPARMS directive, the compiler passes up to three parameters in registers. The parameter passing code generated by this directive is compatible with earlier C51 versions.
The REGPARMS and NOREGPARMS directives can be defined multiple times in a source program. This allows a section of the program to use registers for parameter passing, while other functions still use the original passing method, and the assembly language functions and library files (which already exist) do not need to be changed.
例: C51 DEMO.C NOREGPARMS
#pragma RP
2.2.7 REGISTER BANK
Name: REGISTERBANK
Abbreviation: RB
Variable: A number between 0 and 3 in brackets
Default value: REGISTERBANK (0)
The REGISTERBANK directive selects the register bank to be used in the current call, unless the "using" flag is used. Generated code may use the absolute form of register access, represented by the mnemonic "Arn", when the absolute number of registers can be calculated.
Compared to "using n", REGISTERBANK does not switch the register bank!
Functions that return values must always use the same register bank. Otherwise, the return value may be placed in the wrong register bank.
例: C51 DEMO.C REGISTERBANK
#pragma rp(3)
2.2.8 AREGS/NORWAYS
Name: AREGS/NOAREGS
Abbreviation: AR/NOAR
Variable: None
Default value: AREGS
AREGS causes the compiler to use absolute register addressing, which improves efficiency. For example, the PUSH and POP instructions can only be addressed directly (absolutely). The REGSITERBANK instruction can be used to establish a specific register bank. The NOAREG instruction turns off absolute addressing. Functions compiled without the NOAREGS instruction do not depend on the register bank, that is, they can use all the registers of the 8051. The AREGS/NOAREGS instructions can be defined multiple times in a program, however, they can only be used outside of a function.
例: C51 DEMO.C NOAREGS
#pragma AREGS
2.2.9 INTVECTOR/NOINTVECTOR
名 字: INTVECTOR/NOINTVECTOR
Abbreviation: IV/NOIV
Variable: None
Default value: INTVECTOR
The INTVECTOR instruction causes the compiler to generate a 3-byte jump (LJMP) target value. These vectors are placed at absolute address 8n+3, where n is the interrupt number. The NOINTVECTOR instruction prevents these interrupt vectors from being generated. This flexibility allows users to take advantage of interrupt service routines provided by other programming tools.
例: C51 SAMPLE.C NOINTVECTOR
#pragma noiv
2.2.10 ROM
The ROM instruction is used to determine the size of the program memory, which affects the encoding of jump instructions.
ROM(SMALL):
Using CALL and JMP instructions as the encoding of ACALL and AJMP instructions, the maximum program space can reach 2K bytes, and the entire user program must be distributed within this 2K byte space.
ROM(COMPACT):
The CALL instruction is encoded as LCALL, and the JMP instruction within the function is encoded as AJMP. Therefore, the function length must not exceed 2K bytes, and the entire program length must not exceed 64K bytes. This usage must be determined according to different purposes to see if it is better than the standard setting ROM (LARGE).
ROM(LARGE)
The CALL and JMP instructions are encoded as LCALL and LJMP. This allows the entire address space to be used without restriction, and the user program can be up to 64K bytes.
Example: C51 DEMO.C ROM(SMALL)
#pragma ROM(SMALL)
2.3 List Control
2.3.1 LISTINCLUDE
Name: LISTINCLUDE/NOLISTINCLUDE
Abbreviation: LC/NOLC
Variable: None
Default value: NOLISTINCLUDE
The LISTINCLUDE directive causes the contents of the header file to appear in the listing file. The QTH simulator recommends that the user use the default value.
2.3.2 SYMBOLS/NOSYMBOLS
Name: SYMBOLS/NOSYMBOLS
Abbreviation: SB/NOSB
Variable: None
Default value: NOSYMBOL
The SYMBOLS, NOSYMBOLS directives generate a table of symbols used by program modules during compilation. For each symbol object, it contains the storage entry, storage type, offset and object size.
Example: C51DEMO.C SB
#pragma sb
2.3.3 PREPRINT/NOPREPRINT
Name: PREPRINT/NOPREPRINT
Abbreviation: PP/NOPP
Variable: optional file name in brackets
Default value: NOPREPRINT
The PREPRINT directive generates a preprocessor listing, macro calls are expanded and comments are deleted. If the PREPRINT directive is not accompanied by an argument, the source file name plus the extension "·I" is used as the listing file name. If this name is not used, a file name must be specified.
例: C51 DEMO.C PP(DEMO.LST)
2.3.4 CODE/NOCODE
Name: CODE/NOCODE
Abbreviation: CD/NOCD
Variable: None
Default value: NOCODE
The CODE directive appends an assembly memory table to the list file, and each function in the source program is represented as assembly code.
2.3.5 PRINT/NOPRINT
Name: PRINT/NOPRINT
Abbreviation: PR/NOPR
Variable: The file name in brackets
Default: PRINT(bname.LST)
The PRINT directive causes the compiler to generate a list file for each compiled program using the path, source file name and extension ".LST". The list file name can be redefined with the PRINT option. When NOPRINT is used, no list file will be generated. QTH simulator recommends that users use the default values.
2.3.6 COND/NOCOND
Name: COND/NOCOND
Abbreviation: CO/NOCO
Variable: None
Default value: COND
The directives COND and NOCOND determine whether the conditional compilation section of the source file appears in the list file. The COND option prohibits the output of skipped lines to the list file. Whenever the preprocessor detects this directive, it will have an effect on the line. The QTH simulator recommends that users use the default value.
2.3.7 PAGELENGTH
Name: PAGELENGTH
Abbreviation: PL
Variable: A decimal number in brackets with a maximum value of 65535
Default value: PAGELENGTH (69)
The PAGELENGTH directive specifies the number of lines per page in the listing file. The default value is 69 pages. This includes header and blank lines.
例: C51 DEMO.C PAGELENGTH(60)
#pragma pl(60)
2.3.8 PAGEWIDTH
Name: PAGEWIDTH
Abbreviation: PW
Variable: A decimal number between 78 and 132 in brackets
Default value: PATHWIDTH (132)
PAGEWIDTH specifies the number of characters per line. If this number is exceeded, the line will be split into two or more lines. QTH simulator recommends that users use the default value.
2.3.9 EJECT
Name: EJECT
Abbreviation: EJ
Variable: None
Default value: None
The EJECT directive causes the listing file to page. This directive can only be used on source files and must be part of a #pragma.
3 C library functions
The library of the C-51 software package contains standard applications. Each function has a prototype declaration in the corresponding header file (.h). If you use a library function, you must define the header file associated with the function (including the prototype declaration of the function) with a precompilation directive in the source program. For example:
#include
#include
If you omit the header file, the compiler expects standard C argument types, and correct execution of the function cannot be guaranteed.
3.1 CTYPE.H: Character Functions
The following library functions are included in the CTYPE.H header file:
Function name: isalpha
Prototype: extern bit isalpha(char)
Function: isalpha checks whether the character passed in is between 'A'-'Z' and 'a'-'z', and returns true if true
The value is 1 otherwise, 0.
Function name: isalnum
Prototype: extern bit isalnum(char)
Function: isalnum checks whether a character is between 'A'-'Z', 'a'-'z' or '0'-'9', and returns true.
The return value is 1 if yes, 0 otherwise.
Function name: iscntrl
Prototype: extern bit iscntrl(char)
Function: iscntrl checks whether the character is between 0x00 and 0x1F or 0x7F. If true, the return value is 1, otherwise it is 0.
Function name: isdigit
Prototype: extern bit isdigit(char)
Function: isdigit checks whether the character is between '0' and '9'. If true, the return value is 1, otherwise it is 0.
Function name: isgraph
Prototype: extern bit isgraph(char)
Function: isgraph checks whether the variable is a printable character. The printable character range is 0x21 to 0x7E.
If printed, the return value is 1, otherwise it is 0.
Function name: isprint
Prototype: extern bit isprint(char)
Function: Same as isgraph, but also accepts space characters (0X20).
Function name: ispunct
Prototype: extern bit ispunct(char)
Function: ispunct checks if a character is a punctuation or space. If the character is a space or 32 punctuation and format
Ispunct returns 1 if the character is one of the following (assuming the 128 standard characters in the ASCII character set), otherwise it returns 0. Ispunct returns 1 for the following characters:
(space)! "$%^&()+,-./:<=>?_['~{
}
Function name: islower
Prototype: extern bit islower(char)
Function: islower checks whether the character variable is between 'a' and 'z'. If true, the return value is 1, otherwise it is 0.
Function name: isupper
原 型: extern bit isupper(char)
Function: isupper checks whether the character variable is between 'A' and 'Z'. If true, the return value is 1, otherwise it is 0.
Function name: isspace
Prototype: extern bit isspace(char)
Function: isspace checks whether a character variable is one of the following: space, tab, carriage return, line feed, vertical tab
The return value is 1 if true, 0 otherwise.
Function name: isxdigit
Prototype: extern bit isxdigit(char)
Function: isxdigit checks whether a character variable is between '0'-'9', 'A'-'F', or 'a'-'f'.
The return value is 1 if true, 0 otherwise.
Function name: toascii
Prototype: toascii(c)((c)&0x7F);
Function: This macro reduces any integer value to the valid ASCII range. It ANDs the variable with 0x7F to remove the low
All digits above 7.
Function name: toint
Prototype: extern char toint(char)
Function: toint converts ASCII characters to hexadecimal and returns values 0 to 9 obtained from ASCII characters '0' to '9'.
10 to 15 are obtained by the ASCII characters 'a'-'f' (not case sensitive).
Function name: tolower
Prototype: extern char tolower(char)
Function: tolower converts characters to lowercase. If the character variable is not between 'A' and 'Z', no conversion is performed.
Replace and return the character.
Function name: _tolower
Prototype: tolower(c);(c-'A'+'a')
Function: This macro performs bit-wise OR of the 0x20 parameter value.
Function name: toupper
Prototype: extern char toupper(char)
Function: toupper converts characters to uppercase. If the character variable is not between 'a' and 'z', no conversion is performed.
Replace and return the character.
Function name: _toupper
Prototype: _toupper(c);((c)-'a'+'A')
Function: The _toupper macro performs a bitwise AND operation on c and 0xDF.
3.2 STDIO.H: General I/O Functions
The C51 compiler contains character I/O functions, which operate through the processor's serial interface. To support other I/O mechanisms, only the getkey() and putchar() functions need to be modified. All other I/O support functions rely on these two modules and do not need to be modified. Before using the 8051 serial port, they must be initialized. The following example initializes the serial port at 2400 baud rate and 12MHz:
SCON=0x52 /*SCON*/
TMOD=0x20 /*TMOD*/
TR1=1 /*Timer 1 run flag*/
TH1=0Xf3 /*TH1*/
Details of other operating modes and baud rates can be obtained from the 8051 user manual.
Function name: _getkey
Prototype: extern char _getkey();
Function: _getkey() reads a character from the 8051 serial port and waits for the character to be input. This function changes the entire
The input port mechanism is the only function that should be modified.
Function name: getchar
Prototype: extern char _getchar();
Function: getchar() uses _getkey to read characters from the serial port, except that the read characters are immediately passed to the putchar function
Same as _getkey, except for response.
Function name: gets
Prototype: extern char *gets(char *s, int n);
Function: This function reads a character from the console device through getchar and sends it to the data group pointed to by 's'.
Taking into account the ANSI standard's recommendation to limit the maximum number of characters that can be read per call, the function provides a character counter 'n' and in all cases discards the input characters when a newline character is detected.
Function name: ungetchar
Prototype: extern char ungetchar(char);
Function: ungetchar pushes the input character back into the input buffer so that it is available next time gets or getchar is called.
ungetchar returns 'char' on success and EOF on failure. It is not possible to process multiple characters with ungetchar.
Function name: _ungetchar
Prototype: extern char _ungetchar(char);
Function: _ungetchar sends the incoming character back to the input buffer and returns its value to the caller, the next time you use getkey
It is not possible to write back multiple characters.
Function name: putchar
Prototype: extern putchar(char);
Function: putchar outputs 'char' through the 8051 serial port. Like the getkey function, putchar changes the entire
The only function that needs to be modified for the output mechanism.
Function name: printf
Prototype: extern int printf(const char*, ...);
Function: printf outputs values and strings in a certain format through the 8051 serial port. The return value is the number of characters actually output.
Parameters can be pointers, characters or values. The first parameter is a format string pointer.
Note: The total number of bytes allowed as printf parameters is limited by the C51 library because of the limited storage space in the 8051 structure. In SMALL and COMPACT modes, a maximum of 15 bytes of parameters (i.e., 5 pointers, or 1 pointer and 3 long bytes) can be passed. In LARGE mode, a maximum of 40 bytes of parameters can be passed. The format control string contains the following fields (fields in square brackets are possible):
%[flags][width][.precision]type
The "width" field defines the number of characters to be displayed by the parameter. It must be a decimal number. If the actual number of characters displayed is less than "width", spaces are added to the left end of the output. If the "width" field starts with 0, 0 is added to the left end.
The "flag" field is used to define the following options:
Falg |
significance |
- |
Output left flush |
+ |
If the output value is a signed value, add a +/- sign |
' '(space) |
If the output value is regular, it will be filled with spaces on the left. |
# |
If it is used with 0, x or X, the characters 0, 0x, 0X are added before the output. When used with value types g, G, f, e, E, '#' causes a decimal point to be generated in the output. |
b,B |
They are used with the format types d, i, o, u, x, X so that the argument type is accepted as '[unsigned]char', such as: %bu, %bd or %bx. |
L,L |
They are used with the format types d, i, o, u, x, X so that the argument type is accepted as '[unsigned]long', such as: %lu, %ld or %lx. |
* |
The next parameter is not output. |
The "type" field defines the following parameter types:
character |
type |
Output Format |
d |
int |
Signed decimal number (16 bits) |
IN |
int |
Unsigned decimal number |
o |
int |
Unsigned octal number |
X,x |
int |
Unsigned hexadecimal number |
f |
float |
[-]Floating point numbers in the form of dddd.dddd |
and and |
float |
[-]d.ddddE[sign] floating point number in dd format |
g, G |
float |
e or f format floating point number, whichever output format is better. |
c |
char |
character |
s |
pointer |
Points to a string with a terminator |
p |
pointer |
Pointer with memory designator and offset. M:aaaa. M:=C(ode),D(ata),I(data),P(data) aaaa: pointer offset value. |
example:
printf(“Int-Val%d,Char-Val%bd,Long-Val%d”,I,c,l);
printf(“String%s,Character%c”,array,character);
printf(“Pointer%p”,&array[10]);
Function name: sprintf
Prototype: extern int sprintf(char *s, const char*, ...);
Function: sprintf is similar to printf, but the output is not displayed on the console, but is sent to the
An addressable buffer.
Note: The total number of bytes of parameters that sprintf allows to output is exactly the same as printf.
Function name: puts
Prototype: extern int puts(const char*, ...);
Function: puts writes the string 's' and a newline character to the console device. It returns EOF if an error occurs, otherwise it returns a non-negative number.
Function name: scanf
Prototype: extern int scanf(const char*, ...);
Function: scanf uses the getcha function to read data from the console under the control of the format string.
scanf returns the number of input items it found and converted. If an error is encountered, it returns EOF. The format string includes:
l Spaces, tabs, etc. These whitespace characters are ignored.
l characters, except for the "%" (format control character) which needs to be matched.
l The conversion character "%" is followed by several optional characters; the assignment suppressor "*" is a number that specifies the maximum field width.
Note: The total number of bytes allowed for scanf parameters is the same as for printf. The format control string can include the following fields (the fields in square brackets are optional):
%[flags][width]type
The format string always starts with a percent sign, and each field contains one or more characters or numbers.
The "width" field defines the number of characters that the parameter can accept. "width" must be a positive decimal number. If the actual number of input characters is less than "width", no padding will be performed.
The 'flag' field is used to define the following options:
Flag |
significance |
* |
Input is ignored |
b,h |
They are used as prefixes for the format types d, i, o, u and x, which define whether the parameter is a character pointer or an unsigned character pointer, such as %bu, %bd, %bx. |
L |
They are used as prefixes for format types d, i, o, u and x, and use this prefix to define whether the parameter is a long pointer or an unsigned word pointer, such as %lu, %ld, %lx. |
The "type" field defines the parameter as follows:
Descriptor |
type |
Input Format |
d |
ptr to int |
Signed decimal number (16 bits) |
i |
ptr to int |
As in C notation, integer values |
in |
ptr to int |
Unsigned decimal number |
O |
ptr to int |
Unsigned octal number |
x |
ptr to int |
Unsigned hexadecimal number |
f,e,g |
ptr to float |
Floating point numbers |
c |
ptr to char |
A character |
s |
ptr to string |
A string |
example:
scanf(“%d%bd%ld”,&i,&c,&l);
scanf(“%f”,&f);
scanf(“%3s,%c”,&string[0],&character);
Function name: sscanf
Prototype: extern int sscanf(const *s,const char*,…);
Function: sscanf is similar to scanf, but the string input is not through the console, but through another null-terminated
Pointer to .
Note: The total number of bytes allowed for sscanf parameters is limited by the C-51 library. This is due to the memory limitations of the 8051 processor architecture. In SMALL and COMPACT modes, a maximum of 15 bytes of parameters (that is, at most 5 pointers, or 2 pointers, 2 long integers, or 1 character) are allowed. In LARGE mode, a maximum of 40 bytes of parameters are allowed.
3.3 STRING.H: String Functions
String functions usually take pointer strings as input values. A string consists of 2 or more characters. The end of a string is represented by a null character. In the functions memcmp, memcpy, memchr, memccpy, memmove, and memset, the string length is explicitly specified by the caller, so that these functions can work in any mode.
Function name: memchr
原 型: extern void *memchr(void *sl, char val,int len);
Function: memchr sequentially searches for len characters in s1 to find the character val, and returns the pointer to val in s1 if successful.
Pointer, or NULL on failure.
Function name: memcmp
原 型: extern char memcmp(void *sl, void *s2,int len);
Function: memcmp compares the first len characters of string s1 and s2 character by character. Returns 0 if they are equal, and returns 0 if string s1 is larger than s2.
If s2 is greater than or less than s2, a positive or negative number is returned accordingly.
Function name: memcpy
原 型: extern void *memcpy(void *dest, void *src,int len);
Function: memcpy copies len characters from the memory pointed to by src to dest, and returns the last character in dest.
If src and dest overlap, the results are unpredictable.
Function name: memccpy
原 型: extern void *memccpy(void *dest, void *src,char val,int len);
Function: memccpy copies len characters from src to dest. If len characters are actually copied, it returns NULL.
The copying process stops after copying the character val, and a pointer to the next element in dest is returned.
Function name: memmove
原 型: extern void *memmove(void *dest, void *src,int len);
Function: memmove works the same way as memcpy, but the copy areas can overlap.
Function name: memset
原 型: extern void *memset(void *s, char val,int len);
Function: memset fills len units in pointer s with the value val.
Function name: strcat
Prototype: extern char *strcat(char *s1, char *s2);
Function: strcat copies string s2 to the end of string s1. It assumes that the address area defined by s1 is large enough to accommodate two strings.
The back pointer points to the first character of the s1 string.
Function name: strncat
原 型: extern char *strncat(char *s1, char *s2,int n);
Function: strncat copies n characters from string s2 to the end of string s1. If s2 is shorter than n, only s2 is copied.
Function name: strcmp
Prototype: extern char strcmp(char *s1, char *s2);
Function: strcmp compares strings s1 and s2, and returns 0 if they are equal.
A positive number.
Function name: strncmp
原 型: extern char strncmp(char *s1, char *s2,int n);
Function: strncmp compares the first n characters in strings s1 and s2. The return value is the same as strncmp.
Function name: strcpy
Prototype: extern char *strcpy(char *s1, char *s2);
Function: strcpy copies string s2 including the terminator to s1 and returns a pointer to the first character of s1.
Function name: strncpy
原 型: extern char *strncpy(char *s1, char *s2,int n);
Function: strncpy is similar to strcpy, but only copies n characters. If the length of s2 is less than n, s1 is replaced with '0'
Pad to length n.
Function name: strlen
Prototype: extern int strlen(char *s1);
Function: strlen returns the number of characters in string s1 (including the end character).
Function name: strchr, strpos
Prototype: extern char *strchr(char *s1, char c);
extern int strpos(char *s1,char c);
Function: strchr searches for the first occurrence of the character 'c' in string s1. If successful, it returns a pointer to the character.
The search also includes the terminator. Searching for a null character returns a pointer to the null character instead of a null pointer.
strpos is similar to strchr, but it returns the position of a character in a string or -1. The first character of string s1 is position 0.
Function name: strrchr, strrpos
Prototype: extern char *strrchr(char *s1, char c);
extern int strrpos(char *s1,char c);
Function: strrchr searches for the last occurrence of the character 'c' in string s1. If successful, it returns a pointer to the character.
A pointer to a character is returned, otherwise NULL is returned. Searching for s1 also returns a pointer to a character instead of a NULL pointer.
strrpos is similar to strrchr, but it returns the position of a character in a string or -1.
Function names: strspn, strcspn, strpbrk, strrpbrk
Prototype: extern int strspn(char *s1, char *set);
extern int strcspn(char *s1,char *set);
extern char *strpbrk(char *s1,char *set);
extern char *strpbrk(char *s1,char *set);
Function: strspn searches for the first character in string s1 that is not included in set, and the return value is the character in s1 that is included in set
The number of characters. If all characters in s1 are contained in set, the length of s1 (including the terminator) is returned. If s1 is an empty string, 0 is returned.
strcspn is similar to strspn, but it searches for the first character in string s1 that is contained in set. strpbrk is very similar to strspn, but it returns a pointer to the character that was searched for, rather than a count, or NULL if it is not found.
strrpbrk is similar to strpbrk, but it returns a pointer in s1 to the last character found in the set character set.
3.4 STDLIB.H: Standard Functions
Function name: atof
Prototype: extern double atof(char *s1);
Function: atof converts the string s1 to a floating point value and returns it. The input string must contain numbers that conform to the floating point value specification.
The C51 compiler treats the data types float and double the same.
Function name: atol
原 型: extern long atol(char *s1);
Function: atol converts the s1 string into a long integer value and returns it. The input string must contain the same
The number of symbols.
Function name: atoi
Prototype: extern int atoi(char *s1);
Function: atoi converts the string s1 to an integer and returns it. The input string must contain numbers that conform to the integer specification.
3.5 MATH.H: Mathematical Functions
Function names: abs, cabs, fabs, labs
Prototype: extern int abs(int va1);
extern char cabs(char val);
extern float fabs(float val);
extern long labs(long val);
Function: abs determines the absolute value of the variable val. If val is positive, it is returned unchanged; if it is negative,
Returns the opposite number. These four functions have the same function except that the variables and return values are different.
Function name: exp, log, log10
Prototype: extern float exp(float x);
extern float log(float x);
extern float log10(float x);
Function: exp returns the power of x with base e, log returns the natural number of x (e=2.718282), log10 returns x raised to 10
The number with base .
Function name: sqrt
Prototype: extern float sqrt(float x);
Function: sqrt returns the square root of x.
Function name: rand, srand
Prototype: extern int rand(void);
extern void srand(int n);
Function: rand returns a pseudo-random number between 0 and 32767. srand is used to initialize the random number generator.
A known (or expected) value such that successive calls to rand will produce the same sequence of random numbers.
Function names: cos, sin, tan
Prototype: extern float cos(float x);
extern float sin(flaot x);
extern flat tan(flaot x);
Function: cos returns the cosine of x. Sin returns the sine of x. Tan returns the tangent of x. All function variables
The range is -π/2 to +π/2, and the variable must be between ±65535, otherwise a NaN error will be generated.
Function names: acos, asin, atan, atan2
Prototype: extern float acos(float x);
extern float asin(float x);
extern float atan(float x);
extern float atan(float y,float x);
Function: acos returns the arccosine of x, asin returns the sine of x, and atan returns the arctangent of x.
The range of atan2 is -π/2 to +π/2. atan2 returns the arc tangent of x/y, and its range is -π to +π.
Function names: cosh, sinh, tanh
Prototype: extern float cosh(float x);
extern float sinh(float x);
extern float tanh(float x);
Function: cosh returns the hyperbolic cosine of x; sinh returns the hyperbolic sine of x; tanh returns the hyperbolic tangent of x
value.
Function name: fpsave, fprestore
Prototype: extern void fpsave(struct FPBUF *p);
extern void fprestore (struct FPBUF *p);
Function: fpsave saves the state of a floating-point subroutine. fprestore restores the state of a floating-point subroutine to its original state.
These two functions are useful when performing floating-point operations using interrupt routines.
3.6 ABSACC.H: Absolute Address Access
Function names: CBYTE, DBYTE, PBYTE, XBYTE
Prototype: #define CBYTE((unsigned char *)0x50000L)
#define DBYTE((unsigned char *)0x40000L)
#define PBYTE((unsigned char *)0x30000L)
#define XBYTE((unsigned char *)0x20000L)
Function: The above macro definition is used to make absolute address access to the 8051 address space, so byte addressing is possible. CBYTE
Addressing CODE area, DBYTE addresses DATA area, PBYTE addresses XDATA area (through MOVX @R0 command), XBYTE addresses XDATA area (through MOVX @DPTR command).
Example: The following instruction accesses address 0x1000 in the external memory area
xval=XBYTE[0x1000];
XBYTE[0X1000]=20;
By using the #define directive, absolute addresses can be defined with symbols, such as the symbol X10 can be equal to the address XBYTE[0x1000]: #define X10 XBYTE[0x1000].
Function Name: CWORD, DWORD, PWORD, XWORD
Prototype: #define CWORD((unsigned int *)0x50000L)
#define DWORD((unsigned int *)0x40000L)
#define PWORD((unsigned int *)0x30000L)
#define XWORD((unsigned int *)0x20000L)
Function: These macros are similar to the above, except that they specify the type as unsigned int. With flexible data types,
All address spaces are accessible.
3.7 INTRINS.H: Intrinsic Functions
Function names: _crol_, _irol_, _lrol_
原 型: unsigned char _crol_(unsigned char val,unsigned char n);
unsigned int _irol_(unsigned int val,unsigned char n);
unsigned int _lrol_(unsigned int val,unsigned char n);
Functions: _crol_, _irol_, _lrol_ shift val left by n bits in bitwise form. This function is similar to the 8051 "RLA" instruction.
Related, the above functions differ in parameter types.
example:
#include
main()
{
unsigned int y;
y=0x00ff;
y=_irol_(y,4); /*y=0x0ff0*/
}
Function names: _cror_, _iror_, _lror_
原 型: unsigned char _cror_(unsigned char val,unsigned char n);
unsigned int _iror_(unsigned int val,unsigned char n);
unsigned int _lror_(unsigned int val,unsigned char n);
Functions: _cror_, _iror_, _lror_ shift val right by n bits in bitwise form. This function is similar to the 8051 "RRA" instruction.
Related, the above functions differ in parameter types.
example:
#include
main()
{
unsigned int y;
y=0x0ff00;
y=_iror_(y,4); /*y=0x0ff0*/
}
Function name: _nop_
Prototype: void _nop_(void);
Function: _nop_ generates a NOP instruction. This function can be used for time comparison in C programs. The C51 compiler generates a NOP instruction in the _nop_ function.
No function call is generated during the operation of the number, that is, the NOP instruction is directly executed in the program.
example:
P()=1;
_nop_();
P()=0;
Function name: _testbit_
Prototype: bit_testbit_(bit x);
Function: _testbit_ generates a JBC instruction that tests a bit and returns 1 if it is set, otherwise it returns 0.
If the bit is set to 1, reset it to 0. The 8051's JBC instruction is used for this purpose. _testbit_ can only be used on directly addressable bits; its use in expressions is not allowed.
STDARG.H: Variable parameter table
The C51 compiler allows reentrant function arguments (symbolized by "..."). The header file STDARG.H allows processing of function parameter lists whose length and data type are unknown at compile time. For this purpose, the following macros are defined.
Macro name: va_list
Function: Pointer to parameter.
宏名: va_stat(va_list pointer,last_argument)
Function: Initialize the pointer to the parameter.
宏 名: type va_arg(va_list pointer,type)
Function: Returns the parameter of type type.
Macro name: va_end(va_list pointer)
Function: Identify the dummy macro at the end of a table.
3.8 SETJMP.H: Jump all the way
The functions in Setjmp.h are used as normal series of number calls and function terminations, which allow direct returns from deep function calls.
Function name: setjmp
Prototype: int setjmp(jmp_buf env);
Function: setjmp stores the status information in env for use by the function longjmp. When setjmp is called directly, the return value is
It is 0 and returns a non-zero value when called by longjmp. setjmp can only be called once in the statement IF or SWITCH.
Function name: long jmp
Prototype: long jmp(jmp_buf env,int val);
Function: longjmp restores the state in env when setjmp is called. The program continues to execute, as if the function setjmp
The value returned by setjmp is the value val passed in the function longjmp, and the values of all automatic variables and variables not defined with volatile in the function called by setjmp are changed.
3.9 REGxxx.H: Accessing SFR and SFR-BIT Addresses
The files REG51.H, REG52.H and REG552.H allow access to the addresses of the SFRs and SFR-bits of the 8051 series. These files contain the #include directive and define all the SFR names required to address the peripheral circuit addresses of the 8051 series. For some other devices in the 8051 series, the user can easily generate a ".h" file with a file editor.
The following example shows access to 8051 PORT0 and PORT1:
#include
main() {
if(p0==0x10) p1=0x50;
}
Previous article:Library function printf in KeilC51
Next article:C51 data types and variable definitions
- Popular Resources
- Popular amplifiers
- Dual Radar: A Dual 4D Radar Multimodal Dataset for Autonomous Driving
- Real-time driver monitoring system via modal and viewpoint analysis
- A review of learning-based camera and lidar simulation methods for autonomous driving systems
- Control strategies for advanced driver assistance systems and automated driving functions
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- 【ufun learning】Part 2: Initial test demo example
- Problems with temperature acquisition based on stm32f446re
- MCU+MOS tube stepping subdivision drive control solution
- Do you know A2B, the automotive audio bus technology?
- Detailed explanation of MSP430F5529 system working mode
- SensorTile.Box becomes bricked after firmware upgrade
- Window Comparator
- [GD32L233C-START Review] Part 2 Compilation, Software Development Environment Review
- Stuck inexplicably
- Realization of Chinese Characters and Graphics Overlay Based on DSP