news 2026/4/18 12:27:00

单片机工程师眼中每个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/4/18 8:20:04

AnimateDiff开发环境搭建:Ubuntu系统配置全攻略

AnimateDiff开发环境搭建&#xff1a;Ubuntu系统配置全攻略 1. 为什么选择Ubuntu来跑AnimateDiff 在实际部署AnimateDiff的过程中&#xff0c;Ubuntu系统几乎是大多数开发者的首选。不是因为某个厂商的推广&#xff0c;而是它在AI开发场景中确实表现得足够稳当。我用过CentOS…

作者头像 李华
网站建设 2026/4/18 4:01:07

WAN2.2文生视频镜像免配置优势:预装ComfyUI+依赖库+工作流开箱即用

WAN2.2文生视频镜像免配置优势&#xff1a;预装ComfyUI依赖库工作流开箱即用 1. 为什么“免配置”才是真正的新手友好&#xff1f; 你有没有试过部署一个文生视频模型&#xff1f;下载几十个依赖、手动编译CUDA扩展、反复调试Python环境、折腾半天连界面都打不开……这些不是…

作者头像 李华
网站建设 2026/4/18 4:03:10

GLM-4-9B-Chat-1M模型蒸馏实践:在移动端部署轻量级版本

GLM-4-9B-Chat-1M模型蒸馏实践&#xff1a;在移动端部署轻量级版本 1. 为什么需要对GLM-4-9B-Chat-1M做模型蒸馏 GLM-4-9B-Chat-1M确实是个让人眼前一亮的模型&#xff0c;它支持100万tokens上下文长度&#xff0c;能处理约200万中文字符&#xff0c;相当于两本《红楼梦》的体…

作者头像 李华
网站建设 2026/4/18 4:04:58

GTE-Pro企业应用案例:从关键词到意图理解的进化

GTE-Pro企业应用案例&#xff1a;从关键词到意图理解的进化 你有没有遇到过这样的场景&#xff1a;在企业知识库中搜索“服务器崩了”&#xff0c;结果返回一堆无关的运维手册目录&#xff1b;输入“新来的程序员是谁”&#xff0c;系统却只匹配到包含“程序员”和“新”两个字…

作者头像 李华
网站建设 2026/4/18 4:01:08

YOLO12部署全攻略:从本地到云端的完整解决方案

YOLO12部署全攻略&#xff1a;从本地到云端的完整解决方案 1. 为什么YOLO12值得你立刻上手 你是否还在为检测精度和推理速度难以兼顾而纠结&#xff1f;是否试过多个目标检测模型&#xff0c;却总在“快但不准”和“准但慢”之间反复横跳&#xff1f;YOLO12不是又一个迭代版本…

作者头像 李华
网站建设 2026/4/18 4:04:56

二次元角色设计神器:漫画脸描述生成实战教程

二次元角色设计神器&#xff1a;漫画脸描述生成实战教程 1. 为什么你需要这个工具——从手绘草稿到AI角色设计的跨越 你是不是也经历过这样的场景&#xff1a;脑子里有个绝妙的角色形象&#xff0c;头发是什么颜色、眼睛有多大、穿什么风格的衣服都清清楚楚&#xff0c;可一拿…

作者头像 李华