In the process of microcontroller programming, if a designer can master multiple programming languages simultaneously, then that designer is undoubtedly a very talented individual. However, mastering assembly, C, and C++ at the same time is quite challenging, and many beginners struggle significantly while learning just one of these languages. This article specifically compiles opinions from engineers with many years of experience in the embedded programming field, summarizing them into a set of considerations that can guide embedded programming practices. Interested readers are encouraged to take a look.In microcontroller embedded programming, the two most challenging aspects are interrupts and memory management. The reason some people find them not difficult is that in most cases, chip manufacturers have already provided the necessary configurations. However, if the designer works for the chip manufacturer, they must be able to write the configuration files themselves.These two aspects are considered difficult because they require writing in assembly or C-like languages, which are relatively low-level. Interrupts can be categorized into external and internal interrupts. External interrupts have two implementation modes: hardware interrupt mode and software interrupt mode, which are relatively simple and belong to the application layer. In contrast, internal interrupts are much more complex, primarily arising from situations such as restarts, bus errors, overflows, and checksum errors. Many software developers do not write corresponding interrupt service routines (ISRs) because they are too difficult and generally not needed. However, when they do occur, they can lead to catastrophic errors. Therefore, from the perspective of overall system robustness, it is essential to have corresponding ISRs, as recommended by experts from Freescale. Below, we will discuss the considerations that should be taken into account in embedded programming.DelaysEmbedded programming often involves hardware operations, such as ADCs, turning on or off a current source, all of which require time. Therefore, when issuing these commands, immediately reading the register values will not yield the desired results, and the reasons may not be apparent. Sometimes, the required delay can be quite long, reaching the millisecond level, while in general, microsecond-level delays are sufficient, depending on the clock frequency of each chip, not just the bus clock frequency of the MCU.VariablesGenerally, if the scope and lifetime of a variable are very clear, it should be defined with the appropriate specifiers, such as const or static. This approach minimizes errors. It is not advisable to define all variables as global variables, as this complicates management and can lead to significant issues if the program encounters errors. The same applies to functions; global variables and generic functions must be declared to avoid errors during calls. Some compilers do not report errors for undeclared functions, but they may issue warnings about implicit type conversions during calls. This point should be approached with particular caution.Macro DefinitionsDuring program development, specific numbers should ideally be defined using macros. This practice has the advantage of being intuitive and facilitating future maintenance. Otherwise, after a long time, one may forget what a particular number represents. Macro definitions do not impose any burden on the program, as they are fully replaced during compilation, so they can be widely used. It is worth mentioning that macro definitions are not limited to constants; they can also define functions. Since they are directly replaced, they avoid stack operations, improving program execution efficiency, although they increase code size. Therefore, they are generally used for simpler functions. One drawback is that the replacement process does not check whether the parameter types are correct, which increases security risks. A solution to this issue is to use inline functions, which inherit the advantages of macro definitions while compensating for their drawbacks. However, this falls within the C++ domain and has a certain level of difficulty; interested readers can refer to relevant materials.Floating Point OperationsMost low-end microcontrollers do not support floating-point operations, and therefore, they are rarely used in practice. To reduce costs, floating-point operation modules are generally omitted, leading to a problem: what if floating-point operations are needed? Observant readers may notice that even microcontrollers without floating-point operations can still use float or double data types during simulation and debugging, yielding accurate results. This is because the compiler automatically calls library functions to implement this, typically through iterative methods, which results in very slow execution efficiency. This method is not recommended. Instead, the “fixed-point” method is commonly used to address this issue. For example, a 32-bit data value can be assumed to have its lowest 8 bits as the decimal part, allowing for bit-shifting calculations similar to integer operations. This method is complex but can achieve high precision. Another approach is to directly scale the value by 10 raised to the power of N for integer calculations to obtain an approximate value. Therefore, to avoid unnecessary complications, floating-point operations should always be avoided whenever possible.WatchdogTaking a triple watchdog as an example, watchdog 1 checks the clock frequency, watchdog 2 monitors a small segment of code that must be fed within a relatively short time, generally required to be fed every 250 to 650 microseconds, while watchdog 3 monitors a larger segment of code that must be fed within a longer time frame, generally within 100 milliseconds. All three conditions must be met simultaneously, which requires a clear understanding of the code execution process; otherwise, it may lead to watchdog errors and restarts.It is important to emphasize that in microcontroller embedded programming, the quality of the program is often determined by the details. The level of detail and flexibility in writing a program is proportional to the accumulation of knowledge and practical experience over time. Although programming can be a very tedious and even monotonous process, the joy of success can make one believe that the effort is worthwhile.