亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial Internet of Things >> 嵌入式

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

学习如何使用外部文本文件初始化 C 语言数组

本指南讲解如何在 C 程序中使用存储在独立文本文件中的数据填充数组。这些值不嵌入源代码,而是在编译时加载。内容涵盖一维和多维数组,展示如何控制数组驻留在 RAM 还是非易失性存储器,并演示如何在多个数据文件中选择初始化源。

示例针对 32 位 ARM 微控制器,使用 GCC 编译。所有代码片段采用标准 C,兼容该编译器。

数组初始化基础

在 C 语言中声明数组时,可在花括号内提供初始值列表(称为初始化项)。例如:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

若省略方括号内的大小,编译器会根据初始化项数量推断。如果声明的数组大于初始化列表,剩余元素默认为零。提供的初始化项超过声明大小会触发编译错误。

空白字符处理

初始化项间用逗号分隔,可自由添加空格、制表符、换行符、回车符、垂直制表符或换页符。C 语言允许语句跨多行,这对可能占据数页源代码的大型数组特别有用。

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

从文件初始化数组

C 预处理器可使用 #include 指令包含任意文本文件。此功能不限于头文件或源文件;任何纯文本文件均可。包含数字、逗号和空白字符的简单文件可用于初始化数组:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

被包含文件必须是纯文本——无富文本格式、标题或其他附加内容。用 Windows 记事本创建的示例如下:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

编译后,数组在内存中如调试器截图所示。此例中数组驻留在 RAM,“Location”列的高地址表明这一点。

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

将数组存储在非易失性存储器并选择数据文件

上例中数组为无显式放置的全局变量。编译器假设其运行时可修改,故置于 RAM。初始值驻留在非易失性存储器(通常为 Flash),启动例程将其复制到 RAM。若数组真为常量,声明 const 告知编译器仅保留在 Flash,节省宝贵 RAM。下图显示效果:数组“Location”指向低 Flash 地址。

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

可用 #define 和 #if 指令在编译时切换 RAM/Flash 存储,或选择不同数据文件初始化。以下代码演示编译时选择存储位置:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

#if 构造是条件包含的经典示例,根据编译时标志决定是否应用 const 限定符。

同样可条件选择提供初始数据的文件:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

大型数组测试验证

为验证技术,使用存储在 CSV 文件中的 10,000 采样噪声波形。下图展示波形,声明演示数据如何融入程序:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

原始 CSV 文件每个值后无逗号。使用正则表达式查找/替换(搜索 \R 替换为 ,\R)单次操作给所有 10,000 项添加逗号。

生成的数组在调试器中清晰可见,按每行 100 元素分组。

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

多维数组

处理二维或三维数据时,记住 C 语言按行优先顺序存储数组。例如 uint16_t test[2][3] 在内存布局为:

[0,0] [0,1] [0,2] [1,0] [1,1] [1,2]

沿最右下标访问连续元素更快,因数据连续。若需两个 1,000 采样向量,声明 test[2][1000] 最大化缓存友好性。

二维数组初始化通常用嵌套花括号分组:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

但可省略外层花括号;编译器按左到右填充。会发出警告:initializer 缺少花括号。只要值总数匹配数组大小,即可编译通过。

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

跨多文件分布数据时,只需按序包含各文件,用一对花括号包裹整个列表:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

联合体中初始化数组

union 允许不同类型共享同一内存。例如包含一维向量和二维矩阵的联合体占用同一地址空间:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

初始化时,编译器优先填充第一个成员。若顺序反转,可能因初始化列表未完全加括号而警告。在 #include 外层加双层花括号确保正确分组:

数据文件内容如下:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

内存中 vector 和 matrix 起始位置相同,调试器截图验证:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

你知道其他从单一数值文件初始化多维数组的方法吗?欢迎评论区分享。

额外技巧:字符串初始化

从外部文件初始化字符串要求引号在文件内部。直接在字符串字面量中 #include 会导致编译器报错。应将引号放入文件,按如下方式包含:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践

生成的字符串驻留 RAM,截图所示:

嵌入式固件开发:使用外部文件数据和信号波形初始化 C 数组的最佳实践


这些示例为理论性质,适用于任何标准 C 编译器。若遇编译器特定怪癖,请评论区告知。

来源提供。

嵌入式

  1. 规避数据分析项目常见陷阱:实战指南
  2. Nexus Integra对比主流物联网与大数据平台:核心差异化优势
  3. STMicroelectronics 发布 STM32Cube.AI:赋能边缘设备嵌入式神经网络
  4. DATA MODUL推出超高亮21.5/31.5寸开放式显示器 EasyTouch适配户外室内
  5. Microchip推出24位与16位Delta-Sigma ADC 153.6kSPS数据率
  6. Contrinex 2020:云就绪传感器与蓝牙光幕,赋能安全应用
  7. 云革命:云计算如何重塑IT、安全与职业生涯
  8. IBM与Tech Data共绘物联网蓝图——第二部分
  9. 落地物联网:Tech Data与IBM洞见——第一部分
  10. C++ 数组完全指南:声明、初始化、多维数组与指针技巧
  11. C++ 动态数组分配实战指南:new/delete、初始化、扩容与内存管理
  12. Java BufferedReader 读取文件:实战指南与示例