news 2026/9/22 11:59:09

单片机工程师眼中每个bit都很贵~

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单片机工程师眼中每个bit都很贵~


正文


大家好,我是bug菌~

如今嵌入式软件按照平台来分主要是两大派系,玩单片机和玩嵌入式Linux,相对而言单片机这块的资源更是不够用,当然现在很多单片机的主频贼高,内存贼大,资源贼丰富,那我还要考虑资源受限的问题吗?

需要的,在成本面前没有最低,只有更低,当技术壁垒一旦被打破,拼的就是成本,多少公司的产品可以做得跟主流厂家一模一样,但就是成本压不下来,导致报价偏高,常常丢标。

那么在单片机开发中,内存是极其宝贵的资源,一些8位单片机可能只有几KB的RAM,当然有时候flash也比较少,但绝大多数情况都没有RAM那么稀缺,如何高效利用每一个bit都是工程师们必须面对的挑战。

那么今天bug菌就介绍下位数组小技巧,从而更加紧凑地存储和操作布尔值,管理大量布尔状态、标志位或设备状态的场景还是比较好用的。

1

bit数组

简单点就是定义一个数组,通过制作一些接口可以便捷的操作所定义数组中每个bit,很多朋友在项目中也是这么用的,但可能没有封装,整理一下或许以后更加方便。

1. 数据结构定义

#ifndef BIT_ARRAY_H #define BIT_ARRAY_H #include <stdint.h> #include <stdbool.h> // 位数组结构体 typedefstruct { uint8_t *data; // 存储数据的字节数组 uint32_t bit_count; // 总位数 uint32_t byte_size; // 需要的字节数 } BitArray; // 错误码 typedefenum { BITARRAY_OK = 0, BITARRAY_ERROR_INVALID_INDEX, BITARRAY_ERROR_NULL_POINTER, BITARRAY_ERROR_INVALID_SIZE } BitArrayError; #endif

这里的*data就是指针指向一篇连续的内存,通常是用后面初始化函数传入的buffer数组,bit_count和byte_size都是标识*data所指向的内存有多大。bitArrayError是一些防御性编程的枚举数值。

2. 基础操作宏

// 计算存储指定位数所需的字节数 #define BITARRAY_BYTES_NEEDED(bits) (((bits) + 7) / 8) // 获取位索引所在的字节位置 #define BITARRAY_BYTE_INDEX(bit_index) ((bit_index) >> 3) // 获取位在字节内的位置(0-7) #define BITARRAY_BIT_POS(bit_index) ((bit_index) & 0x07) // 创建位掩码 #define BITARRAY_BIT_MASK(bit_index) (1U << BITARRAY_BIT_POS(bit_index))

这里是一些基础的宏,为了后面封装函数,不至于晦涩难懂。其实都是一个常规的操作,也比较经典,如果觉得看起来有点吃力,那还得多敲敲代码了,记得都是按照1个byte对应8bit来处理的。

3. 实现

下面是相对比较完整的实现,大家也可以根据自己的项目进行调整和要优化,比如注意在具体平台的大小端问题,线程安全问题等等。

// bitarray.c #include "bitarray.h" /** * @brief 初始化位数组 * @param array 位数组指针 * @param buffer 存储缓冲区 * @param buffer_size 缓冲区大小(字节) * @param bit_count 需要的总位数 * @return 初始化结果 */ BitArrayError bitarray_init(BitArray *array, uint8_t *buffer, uint32_t buffer_size, uint32_t bit_count) { if (!array || !buffer) { return BITARRAY_ERROR_NULL_POINTER; } uint32_t required_bytes = BITARRAY_BYTES_NEEDED(bit_count); if (buffer_size < required_bytes) { return BITARRAY_ERROR_INVALID_SIZE; } if (bit_count == 0) { return BITARRAY_ERROR_INVALID_SIZE; } array->data = buffer; array->bit_count = bit_count; array->byte_size = required_bytes; // 清零所有位 bitarray_clear_all(array); return BITARRAY_OK; } /** * @brief 设置指定位为1 * @param array 位数组指针 * @param bit_index 位索引(0 ~ bit_count-1) * @return 操作结果 */ BitArrayError bitarray_set(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] |= bit_mask; return BITARRAY_OK; } /** * @brief 清除指定位(设为0) * @param array 位数组指针 * @param bit_index 位索引 * @return 操作结果 */ BitArrayError bitarray_clear(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] &= ~bit_mask; return BITARRAY_OK; } /** * @brief 获取指定位的值 * @param array 位数组指针 * @param bit_index 位索引 * @param value 存储位值的指针 * @return 操作结果 */ BitArrayError bitarray_get(const BitArray *array, uint32_t bit_index, bool *value) { if (!array || !value) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); *value = (array->data[byte_idx] & bit_mask) != 0; return BITARRAY_OK; } /** * @brief 切换指定位(0变1,1变0) * @param array 位数组指针 * @param bit_index 位索引 * @return 操作结果 */ BitArrayError bitarray_toggle(BitArray *array, uint32_t bit_index) { if (!array) return BITARRAY_ERROR_NULL_POINTER; if (bit_index >= array->bit_count) return BITARRAY_ERROR_INVALID_INDEX; uint32_t byte_idx = BITARRAY_BYTE_INDEX(bit_index); uint8_t bit_mask = BITARRAY_BIT_MASK(bit_index); array->data[byte_idx] ^= bit_mask; return BITARRAY_OK; } /** * @brief 设置所有位为1 * @param array 位数组指针 * @return 操作结果 */ BitArrayError bitarray_set_all(BitArray *array) { if (!array) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { array->data[i] = 0xFF; } // 清除多余的位(如果总位数不是8的倍数) uint32_t extra_bits = array->bit_count & 0x07; if (extra_bits > 0) { uint8_t mask = (1U << extra_bits) - 1; array->data[array->byte_size - 1] &= mask; } return BITARRAY_OK; } /** * @brief 清除所有位为0 * @param array 位数组指针 * @return 操作结果 */ BitArrayError bitarray_clear_all(BitArray *array) { if (!array) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { array->data[i] = 0x00; } return BITARRAY_OK; } /** * @brief 检查所有位是否都为0 * @param array 位数组指针 * @param is_empty 存储结果的指针 * @return 操作结果 */ BitArrayError bitarray_is_empty(const BitArray *array, bool *is_empty) { if (!array || !is_empty) return BITARRAY_ERROR_NULL_POINTER; for (uint32_t i = 0; i < array->byte_size; i++) { if (array->data[i] != 0) { *is_empty = false; return BITARRAY_OK; } } *is_empty = true; return BITARRAY_OK; }

最后

好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个~

唯一、永久、免费分享嵌入式技术知识平台~

推荐专辑 点击蓝色字体即可跳转

MCU进阶专辑

嵌入式C语言进阶专辑

“bug说”专辑

专辑|Linux应用程序编程大全

专辑|学点网络知识

专辑|手撕C语言

专辑|手撕C++语言

专辑|经验分享

专辑|电能控制技术

专辑 | 从单片机到Linux

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 0:38:34

Granite-4.0-H-350m与Claude对比:轻量化模型性能评测

Granite-4.0-H-350m与Claude对比&#xff1a;轻量化模型性能评测 1. 为什么轻量化模型正在改变游戏规则 最近在调试一个边缘设备上的智能助手时&#xff0c;我遇到了一个典型问题&#xff1a;原本在服务器上运行流畅的模型&#xff0c;在树莓派上直接卡死。内存占用太高&…

作者头像 李华
网站建设 2026/9/20 12:27:58

Claude Code安装指南:与DeepSeek-OCR-2构建智能编程助手

Claude Code安装指南&#xff1a;与DeepSeek-OCR-2构建智能编程助手 1. 为什么需要这个组合 最近在调试一个文档处理项目时&#xff0c;我遇到了一个典型问题&#xff1a;代码截图里的错误信息需要快速识别和修复&#xff0c;但每次都要手动输入文字&#xff0c;效率很低。直…

作者头像 李华
网站建设 2026/9/20 22:03:12

UI/UX设计优化DeepSeek-OCR-2交互体验:用户研究实践

UI/UX设计优化DeepSeek-OCR-2交互体验&#xff1a;用户研究实践 1. 当OCR工具遇上真实工作流&#xff1a;为什么交互设计比模型精度更重要 上周我帮一家法律事务所部署DeepSeek-OCR-2时&#xff0c;遇到个有意思的现象&#xff1a;技术团队花了三天时间调通模型&#xff0c;准…

作者头像 李华
网站建设 2026/9/17 6:42:52

Python正则表达式提取比特币地址

在处理文本数据时,尤其是在提取特定的信息如电子邮件地址、URL或在本文中提到的比特币地址时,正则表达式(Regular Expressions)是不可或缺的工具。今天我们将讨论如何使用Python中的re模块来提取比特币地址。 问题描述 假设我们有以下一段文本,包含了各种类型的比特币地…

作者头像 李华
网站建设 2026/9/11 8:32:30

Chord视频分析工具行业落地:自动驾驶路测视频异常行为自动标注

Chord视频分析工具行业落地&#xff1a;自动驾驶路测视频异常行为自动标注 1. 为什么自动驾驶路测视频需要“看得懂”的本地分析工具 你有没有想过&#xff0c;一辆自动驾驶测试车每天跑上几十公里&#xff0c;摄像头会录下多少视频&#xff1f;不是几段&#xff0c;而是成百…

作者头像 李华