1. Header file: #include (I am using STC 89C54RD+)
2. Predefined: sbit LED = P1^0 // Define bit 0 of port P1 as LED
Note: The notation “P1^0” is different from A51 (A51 uses P1.0). P1 is a group of ports, with port numbers ranging from 0 to 7.
Note 2: sbit is used to define bit variables of SFR (Special Function Register). In the above example, LED is defined as a “global variable”.
Note 3: The following notation is incorrect:
sbit code table[] = {P1^0, P1^1, P1^2, P1^3}; // Attempting to use table[i] to specify different pins will cause an error.
sbit table[] = {P1^0, P1^1, P1^2, P1^3}; // Considering the above might be a misuse of the code keyword, using standard C array notation, but this is also incorrect.
3. Main function notation: void main(void)
4. Representation of values:
P1 = 1111 1111 // Binary
P1 = 0xff or P1 = 0xFF // Hexadecimal, starting with 0x, and the value is case insensitive.
P1 = 255 // Decimal
5. When defining small values, you can use unsigned char i, which allows i to range from 0 to 255, making it more convenient as a loop variable.
6. Left and right shifts:
P1 <<= 2 is equivalent to P1 = P1 << 2 // Left shift P1 by 2 bits, shifting left by one bit is equivalent to multiplying by 2.
P1 >>= 3 is equivalent to P1 = P1 >> 3 // Right shift P1 by 3 bits, shifting right by one bit is equivalent to dividing by 2.
Note: Left and right shifts default to “logical shifts”, meaning that regardless of left or right shifts, the empty positions are filled with 0.
7. Bitwise AND and OR:
P1 = P1 & 0x01
P1 = P1 | 0x01
8. Defining a ROM table (an array with constant data):
unsigned char code table[] = {0xff, 0xff, 0xff, 0xff};
Usage: P1 = table[i]
Note: table[] is defined as a “global variable”, in the above example, i ranges from 0 to 3.
Note 2: Constants defined with code are stored in the “code area”, i.e., ROM area, which can save RAM space.
9. When programming with a digital tube, if you are using temp[i] to represent a certain display character and suddenly want to display a decimal point, you can use temp[i] | 0x80 to achieve this by using the “OR” operation to add the decimal point…
10. If you are compiling with Keil C51, remember one thing: it is case insensitive!!! Today, while debugging the program, I encountered an error just because an array name and a variable name were exactly the same, differing only in case. I thought standard C allowed this… After checking online, I found out that Keil C51 is case insensitive, to be precise, “it does not distinguish case during linking”. More accurately, “variables with external linkage are case sensitive, while static linkage is case sensitive”… At least in Keil uVision2, I don’t know if other versions are the same, to be verified…
11. There is no syntax for unsigned float x! Float type variables never have the unsigned prefix!
12. In programs compiled with Keil, the main function does not stop after execution; it will repeatedly execute the main function. Why?
Conclusion 1: If there is no while(1) infinite loop in the main program, the program will start executing from the beginning again after reaching the end.
Conclusion 2: If there is a while(1) infinite loop in the main program, the program will continue running in this infinite loop and will not start executing from the beginning again.
This should be considered a bug of the Keil compiler. Some users have experimented and reported that the assembly code generated by Keil at the end contains a line LJMP main, which means jumping to the main function to execute repeatedly… Another theory is that the PC pointer overflows, and the overflowed address points to the beginning, causing the effect of continued execution… (The author believes this is still a problem with Keil; if the Keil compiler did not generate such a statement as LJMP main, there would be no looping effect…)
In any case, adding while(1) at the end of the program can solve the bug of repeatedly executing the main function…