Hello everyone! Today, I want to share not just dry coding rules, but 6 practical skills that can help your microcontroller projects succeed and double your code efficiency. These experiences come from my years of lessons learned from mistakes, specifically addressing the “program runs but is not user-friendly” issues!
1. Project Planning: Draw the Map Before Setting Off
Case 1: Smart Lamp Requirement Breakdown
/* Traditional beginner's approach */
void main() {
while(1) {
// Piling up all functionalities here
}
}
/* Expert's approach */
// Functional module division
#define LIGHT_MODE 0
#define SENSOR_MODE 1
#define SETTING_MODE 2
uint8_t current_mode = LIGHT_MODE;
Skill Analysis:
- Use comments to outline the functional module map
- Manage program flow with state variables
- Build the framework before filling in the details
2. Modular Programming: Write Code Like Building with LEGO
Case 2: Reusable LED Driver Module
// LED.h
#ifndef _LED_H_
#define _LED_H_
typedef enum {OFF, ON, BLINK} LedState;
void LED_Init(void);
void LED_SetState(LedState state, uint16_t interval);
#endif
// LED.c
static uint16_t blink_interval = 500;
void LED_SetState(LedState state, uint16_t interval) {
switch(state) {
case BLINK:
blink_interval = interval;
// Start timer interrupt
break;
// Other state handling...
}
}
Why Modularize:
- Directly “move in” when porting projects
- Team collaboration without interference
- Quickly locate problem areas during debugging
3. State Machine Design: Say Goodbye to Spaghetti Code
Case 3: Smart Lock State Transition
typedef enum {
LOCKED,
UNLOCKING,
UNLOCKED,
ALARM
} LockState;
void Lock_Handler(void) {
static LockState state = LOCKED;
switch(state) {
case LOCKED:
if(ValidRFID()) state = UNLOCKING;
break;
case UNLOCKING:
Motor_Run(90); // Servo turns to 90 degrees
if(DoorOpened()) state = UNLOCKED;
else if(Timeout()) state = ALARM;
break;
// Other state handling...
}
}
Advantages of State Machines:
- Visualizes complex logic
- Avoids excessive flag variables
- Supports non-blocking program structures
4. Debugging Techniques: Quickly Locate Issues
Technique 1: LED Heartbeat Monitoring
// Add at the end of the main loop
LED_Toggle(DEBUG_LED);
delay(200); // LED blinks regularly during normal operation
Function: Determine if the program is running correctly by the LED blinking frequency
Technique 2: Serial Print Colorful Logs
#define LOG_ERROR(format, ...) printf("\033[31m[ERROR] " format "\033[0m\n", ##__VA_ARGS__)
#define LOG_DEBUG(format, ...) printf("\033[36m[DEBUG] " format "\033[0m\n", ##__VA_ARGS__)
void ADC_Read() {
if(ADC_VALUE > 4095) {
LOG_ERROR("ADC overflow! Current value:%d", ADC_VALUE);
}
}
Effect: Different log levels display in different colors
Technique 3: Use an Oscilloscope to Capture Waveforms
Practical Scenario: Measure PWM duty cycle, serial timing, interrupt response time
5. Memory Optimization: Small Size, Big Wisdom
Case 4: Clever Use of the Code Keyword
// Traditional approach (occupies RAM)
char menuText[] = "Welcome";
// Optimized approach (stored directly in Flash)
code char menuText[] = "Welcome";
Memory Optimization Checklist:
- Use
code
keyword to store constants - Use
bit
instead ofbool
to save space - Use
unsigned char
for local variables as much as possible - Structure byte alignment (
#pragma pack(1)
) - Use unions to share memory space
6. Interrupt Safety: Lightning Protection Guide
Case 5: Atomic Operations in Timer Interrupts
volatile uint32_t sysTick = 0; // Must use volatile!
void Timer0_ISR() interrupt 1 {
sysTick++; // Modify global variable in interrupt
}
uint32_t GetTick() {
uint32_t temp;
EA = 0; // Disable interrupts
temp = sysTick;
EA = 1; // Enable interrupts
return temp;
}
Interrupt Safety Rules:
- Shared variables must be marked as
volatile
- Critical operations should be atomic
- Keep interrupt service routines as short as possible
- Avoid calling complex functions in interrupts
7. Advanced Tips: Expert’s Secret Tool Library
-
Bit-band Magic:
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
Achieve bit-level atomic operations
-
Lookup Table Optimization:
code uint8_t sinTable[64] = {0,12,24,...,255,245}; PWM = sinTable[angle%64]; // Quickly obtain sine wave
-
Macro Definition Black Magic:
#define SET_BIT(reg, bit) ((reg) |= (1<<(bit))) #define CLR_BIT(reg, bit) ((reg) &= ~(1<<(bit)))
Conclusion: Programming is Like Practicing Martial Arts, Techniques are in the Heart and in Action
Three growth suggestions for beginners:
- Keep an “experimental version” and a “stable version” for each project
- Build your own code library (e.g., LED driver library, key processing library)
- Regularly review code written three months ago
Thought Question: How to implement a microwave heating control program using a state machine? Feel free to share your design ideas in the comments!