嵌入式开发利器: 9个高效C语言代码片段分享
在嵌入式系统开发过程中,开发者经常会面对资源受限、性能敏感的场景。为了提升开发效率、保证代码质量、避免重复造轮子,复用成熟的“工具级”代码片段成为一种高效的工程实践。
本文精选了9个在嵌入式开发中实用且常见的 C 语言技巧型代码片段(工具函数),并附带简要说明,助你构建更稳定、可维护的底层系统。
1. 循环队列(Circular Buffer)
循环队列是一种高效的数据结构,适用于串口通信、传感器数据缓冲等场景。
✅ 使用场景:
-
串口接收缓冲
-
音视频数据缓存
-
生产者-消费者模型
2. 断言机制(Assertion)
断言机制有助于在开发阶段快速定位逻辑错误,提升调试效率。
✅ 使用场景:
-
检查函数参数合法性
-
保证状态机状态转移合法
-
开发阶段防御性编程
3. 位反转操作(Bit Reversal)
位反转常用于数据编码、FFT预处理等底层算法中。
4. 固定点运算(Fixed-Point Arithmetic)
在无硬件FPU的系统上,使用固定点数可以有效模拟浮点计算。
✅ 使用场景:
-
控制算法(如PID)
-
数字滤波器
-
图像处理(色彩运算等)
5. 字节序转换(Endianness Conversion)
在进行网络通信或外设协议交互时,字节序转换尤为重要。
6. 位掩码(Bit Masks)
构造位掩码,用于寄存器或位标志操作,是嵌入式中非常常见的技巧。
7. 硬件定时器读取(Timer Counter)
用于时间测量或精确的周期性操作。
- ⚠️ 注意:该示例基于 AVR 平台,其他 MCU 需要参考对应的寄存器手册。
8. 二进制查找(Binary Search)
一个经典且高效的查找算法,适用于已排序数据。
9. 位集合(Bitset)
管理多个标志位时,使用位集合是一种高效且结构清晰的做法。
10. 嵌入式工具函数模块
✅ embedded_utils.h
#ifndef EMBEDDED_UTILS_H
#define EMBEDDED_UTILS_H
#include <stdint.h>
#include <stddef.h>
/* ========== 1. Circular Buffer ========== */
#define CBUF_SIZE 128
typedef struct {
int buffer[CBUF_SIZE];
int head;
int tail;
int count;
} CircularBuffer;
void cbuf_push(CircularBuffer *cb, int data);
int cbuf_pop(CircularBuffer *cb);
/* ========== 2. Assertion ========== */
void eu_assert_failed(const char *file, int line);
#ifndef NDEBUG
#define eu_assert(expr) ((expr) ? (void)0 : eu_assert_failed(__FILE__, __LINE__))
#else
#define eu_assert(expr) ((void)0)
#endif
/* ========== 3. Bit Reversal ========== */
uint32_t reverse_bits(uint32_t num);
/* ========== 4. Fixed-Point Arithmetic ========== */
typedef int16_t fixed_t;
#define FIXED_SHIFT 8
#define float_to_fixed(f) ((fixed_t)((f) * (1 << FIXED_SHIFT)))
#define fixed_to_float(f) ((float)(f) / (1 << FIXED_SHIFT))
fixed_t fixed_multiply(fixed_t a, fixed_t b);
/* ========== 5. Endianness Conversion ========== */
uint16_t swap_bytes16(uint16_t value);
/* ========== 6. Bit Mask ========== */
#define BIT_MASK(bit) (1U << (bit))
/* ========== 7. Timer Counting (AVR example) ========== */
#ifdef __AVR__
#include <avr/io.h>
void timer_setup(void);
uint16_t timer_read(void);
#endif
/* ========== 8. Binary Search ========== */
int binary_search(const int *arr, size_t size, int target);
/* ========== 9. Bitset ========== */
typedef struct {
uint32_t bits;
} Bitset;
void bitset_set(Bitset *bitset, int bit);
int bitset_get(const Bitset *bitset, int bit);
#endif // EMBEDDED_UTILS_H
✅ embedded_utils.c
#include "embedded_utils.h"
#include <stdio.h>
/* ========== 1. Circular Buffer ========== */
void cbuf_push(CircularBuffer *cb, int data) {
if (cb->count < CBUF_SIZE) {
cb->buffer[cb->head] = data;
cb->head = (cb->head + 1) % CBUF_SIZE;
cb->count++;
}
}
int cbuf_pop(CircularBuffer *cb) {
if (cb->count > 0) {
int data = cb->buffer[cb->tail];
cb->tail = (cb->tail + 1) % CBUF_SIZE;
cb->count--;
return data;
}
return -1;
}
/* ========== 2. Assertion ========== */
void eu_assert_failed(const char *file, int line) {
printf("Assertion failed at %s:%d\n", file, line);
}
/* ========== 3. Bit Reversal ========== */
uint32_t reverse_bits(uint32_t num) {
uint32_t num_bits = sizeof(num) * 8;
uint32_t result = 0;
for (uint32_t i = 0; i < num_bits; ++i) {
if (num & (1U << i)) {
result |= (1U << (num_bits - 1 - i));
}
}
return result;
}
/* ========== 4. Fixed-Point Arithmetic ========== */
fixed_t fixed_multiply(fixed_t a, fixed_t b) {
return (fixed_t)(((int32_t)a * (int32_t)b) >> FIXED_SHIFT);
}
/* ========== 5. Endianness Conversion ========== */
uint16_t swap_bytes16(uint16_t value) {
return (value >> 8) | (value << 8);
}
/* ========== 7. Timer Counting (AVR Only) ========== */
#ifdef __AVR__
void timer_setup(void) {
// Configure timer (user-defined)
}
uint16_t timer_read(void) {
return TCNT1;
}
#endif
/* ========== 8. Binary Search ========== */
int binary_search(const int *arr, size_t size, int target) {
int left = 0;
int right = (int)size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target)
return mid;
else if (arr[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1;
}
/* ========== 9. Bitset ========== */
void bitset_set(Bitset *bitset, int bit) {
if (bit < 0 || bit >= 32) return; // 避免越界
bitset->bits |= (1U << bit);
}
int bitset_get(const Bitset *bitset, int bit) {
if (bit < 0 || bit >= 32) return 0;
return (bitset->bits >> bit) & 1U;
}
✅ 示例用法 main.c
#include "embedded_utils.h"
#include <stdio.h>
int main() {
CircularBuffer cb = {0};
cbuf_push(&cb, 42);
printf("Pop: %d\n", cbuf_pop(&cb));
eu_assert(1 == 1);
printf("Reversed bits: 0x%X\n", reverse_bits(0x00000001));
fixed_t a = float_to_fixed(1.5f);
fixed_t b = float_to_fixed(2.0f);
printf("Fixed multiply: %.2f\n", fixed_to_float(fixed_multiply(a, b)));
printf("Swap 0x1234: 0x%X\n", swap_bytes16(0x1234));
Bitset bset = {0};
bitset_set(&bset, 3);
printf("Bit 3: %d\n", bitset_get(&bset, 3));
int arr[] = {1, 3, 5, 7, 9};
printf("Search 7: %d\n", binary_search(arr, 5, 7));
return 0;
}
✅ Makefile
# === Project Configuration ===
TARGET := embedded_demo
SRCS := main.c embedded_utils.c
OBJS := $(SRCS:.c=.o)
INCLUDES := -I.
CFLAGS := -Wall -Wextra -O2 $(INCLUDES)
LDFLAGS :=
# === Cross Compile Support ===
# For native build, leave this empty.
# For ARM, you might use: arm-none-eabi-
CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)gcc
# === Rules ===
all: $(TARGET)
$(TARGET): $(OBJS)
$(LD) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
✅ 交叉编译
- Linaro 提供的 AArch64 工具链:
下载地址:🔗 https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
mkdir ~/toolchains
cd ~/toolchains
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
export TOOLCHAIN_DIR=~/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu
export PATH=$TOOLCHAIN_DIR/bin:$PATH
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
$ ls $TOOLCHAIN_DIR/bin/
aarch64-linux-gnu-gcc
aarch64-linux-gnu-g++
aarch64-linux-gnu-ld
aarch64-linux-gnu-strip
...
make CROSS_COMPILE=arm-none-eabi-
总结
这些工具级代码片段虽小,却极具威力,在嵌入式开发过程中扮演着“利剑”般的角色。掌握并善用这些技巧,不仅能提升开发效率,还能帮助你编写出更鲁棒、更易维护的底层系统。