From participating in the electronic design competition during university to now, I've spent several years exploring the world of microcontrollers. Throughout this journey, I've gathered a lot of experience and insights that I'd like to share. When learning about microcontrollers, it's common to get stuck on the application of various module functions—like serial port communication (232, 485), controlling different ICs, motor control using PWM, interrupt handling, timer usage, human-machine interface implementation, and even CAN bus protocols. These are essential stages in the learning process and form the foundation of MCU skills. Fortunately, my pre-competition training in the Electronic Design Competition gave me solid control over MCU basics. After that, I found that working with different MCUs was quite similar, each having its own strengths. It became easier to learn any new MCU, including more complex processors. The programming approach around MCUs also evolved into a higher-level understanding—managing peripherals and communication between them, such as IIC, SPI, Intel 8080, and M6800. At first, programming around an MCU seems simple, but there's more to it than meets the eye. This is just one part of embedded development. As I worked with various MCUs and faced more complex design requirements, I eventually returned to bare-metal development. This made me think more deeply about the overall architecture of the program. A good program structure is a clear boundary between experienced engineers and beginners. Below is my summary of understanding the microcontroller program framework and some common development practices: Any time-critical tasks can be challenging. If needed, we can increase hardware costs to eliminate these issues. For example, if you want to display eight digital tubes, you must use dynamic scanning without dedicated hardware support, which can hinder the MCU from handling other tasks. When the MCU is heavily loaded, I would choose to use a peripheral like MAX8279 to solve this problem. On the other hand, many tasks are not time-sensitive. For instance, keyboard scanning: the rate at which people press keys is limited, so we don't need to scan the keyboard in real-time or even every few tens of milliseconds. During this time, the MCU can perform other tasks efficiently. Although the MCU runs on bare metal, sometimes the actual needs require us to implement a multitasking program. For example, a typical situation might involve four tasks: keyboard scanning, LED digital tube display, receiving and processing serial data, and sending serial data. In the past, I placed the keyboard scanning in the main loop, used interrupts for serial reception, and processed the received data in the interrupt service function, using flag bits to handle it in the main loop. However, this approach could lead to poor real-time performance if the tasks were too long or too many. To build a better general programming model, we need to eliminate time-consuming parts of each task and break them down. Let’s look at specific measures for each task: 1. **Keyboard Scanning** Keyboard scanning is a common function in microcontrollers. Software debouncing is standard, but using software delays (e.g., 20ms) is a big no-no for real-time systems. Another issue is waiting for key release using infinite loops, which can freeze the system. Instead, we can use timers for debouncing and manage state transitions effectively. 2. **Digital Tube Display** Dynamic scanning is commonly used for 8-digit displays. The human eye can’t detect flickering above 50Hz, so we have ample time for scanning. Using a timer to trigger the display at 4ms intervals ensures smooth operation. 3. **Serial Port Data Reception** In interrupt mode, it's best to store incoming data in a buffer rather than completing the entire frame in the interrupt service routine. Frame composition and verification should be handled in the main loop, ensuring flexibility and real-time performance. 4. **System Timing Events** A timer-driven event system allows for structured execution of tasks at specific intervals. For example, feeding the watchdog, updating the display, scanning the keyboard, and flashing LEDs can all be managed through a central `TimeEvent()` function. By structuring the system this way, we ensure that each task is executed efficiently without blocking others. The code remains clean, modular, and easy to maintain, making it suitable for most MCUs, especially those with limited resources. Overall, this approach has proven effective, and the template can be adapted to different MCUs by adjusting the timer and adding custom event functions. It's flexible, efficient, and easy to use.

1D Handheld Barcode Scanner

Guangzhou Winson Information Technology Co., Ltd. , https://www.barcodescanner-2d.com