嵌入式软件设计之提高代码可移植性

前面一篇博文嵌入式软件架构设计之分层设计給大家分享了程序分层设计的一些个人观点。里面有提到接口统一规范的问题,下面这篇博文详细阐述一下关于代码可移植性的问题。代码可移植性非常重要!在这里有的人很纳闷,有人会问:除了汇编语言的移植性很差以外,c语言,c++,java等其他高级语言的移植性不是都很棒的么。毋庸置疑,c语言的移植性是非常好。但本文不是在探讨一段编程语言的移植性问题,要探讨的是:在不同的嵌入式平台上,如何提高开发嵌入式产品的效率问题。换一种表达方式:如何提高嵌入式软件平台之间的可移植性。

在探讨之前先抛出一个问题:如何才能使开发的应用程序运行在不同的硬件平台上?这里所指的应用程序不是指pc端的应用也不是指的android,ios等平台的应用。而是指的是其他嵌入式平台的应用,他们更多的是c语言实现。我们都知道windows平台也好还是ios,android平台也罢,他们的应用是不同的编程语言实现的,但是他们有一个共同的特点:給应用开发人员提供标准的sdk接口。正是这些标准的接口使得应用开发和硬件以及底层相分离。大大提高了应用程序的可移植性。

目前来看,嵌入式产品若不是android系统,是没有统一的接口规范的。公司在开发设计某款嵌入式产品时,涉及到如下内容:硬件平台选型,软件平台选型,底层软件开发,应用软件开发。底层软件和硬件是紧密联系在一起的,而应用软件可以做到与硬件平台无关。要做到无关就得定义统一的接口规范。让应用程序调用接口规范规定的接口,底层软件根据不同的平台封装不同的程序来实现其接口功能。如此大大提高应用程序不同硬件平台的可移植性。这样做也规范了编程,增加了程序的可读性。

下面以文件操作为例

1.本模块相关宏定义

//本模块相关宏定义以及结构定义如下:
//  错误码定义
#define     FILE_EXIST          1
#define     FILE_NOEXIST        2
#define     MEM_OVERFLOW        3
#define     TOO_MANY_FILES      4
#define     INVALID_HANDLE      5
#define     INVALID_MODE        6
#define     FILE_NOT_OPENED     8
#define     FILE_OPENED         9
#define     END_OVERFLOW        10
#define     TOP_OVERFLOW        11
#define     NO_PERMISSION       12
#define     FS_CORRUPT          13
//以上错误码与标准linux的错误码errno有差异,对于Linux系统的机型,错误码保留linux标准的errno定义。
//  文件打开模式,可使用"或"组合
#ifndef O_RDONLY
#define O_RDONLY     00
#endif
#ifndef O_WRONLY
#define O_WRONLY     01
#endif
#ifndef O_RDWR
#define O_RDWR     02
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK  04000
#endif
#ifndef O_CREAT
#define O_CREAT   0100
#endif
//  文件定位起点
#ifndef SEEK_SET
#define     SEEK_SET            0
#endif
#ifndef SEEK_CUR
#define     SEEK_CUR            1
#endif
#ifndef SEEK_END
#define     SEEK_END            2
#endif
//  文件信息
typedef struct
{
    char     fid;
    char     attr;
    char     type;
    char     name[17];
    int      length;
} FILE_INFO;

2.接口函数规范说明

2.1 dev_FileOpen


原型:


int dev_FileOpen(const char *FileName, int Mode);


功能:


打开本应用所属的文件


参数:


FileName(输入)


1-16Bytes


文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


Mode(输入)


O_CREAT


0100


文件打开方式,O_CREATE表示创建一个新的文件


O_RDWR


02


文件打开方式,O_RDWR表示打开文件用于读/写,


返回:


[0,255]


成功,返回句柄号


-1


失败,错误码放在errno中


注释:


如果以O_CREATE | O_RDWR的方式打开文件,若文件已存在,则以O_RDWR的方式打开,否则创建该文件。已打开的文件可以重复打开,每次打开后,文件指针移到文件开头。

错误码介绍:

INVALID_MODE       mode不为O_RDWR/O_CREATE

FILE_NOEXIST 文件不存在

FILE_EXIST         当文件存在时以O_CREATE的方式打开

MEM_OVERFLOW空间不足

TOO_MANY_FILES    文件句柄太多,超过255,无法创建新文件

FILE_OPENED        文件已打开


示例:


打开文件”Demo.bin”, 如果不存在该文件,则创建该文件。

int Ret = 0;

Ret = fileOpen(“Demo.bin”,O_RDWR); // 以读写方式打开该文件

if(Ret < 0) // 该文件不存在,则重新创建

{

Ret = fileOpen(“Demo.bin”, O_CREAT);

if(Ret < 0)

{

return Ret; // 创建失败,则返回错误码

}

}

…………………  // 对这个文件进行其他的读写操作等

2.2 dev_FileSeek


原型:


int dev_FileSeek(int FileID, int Offset, int Whence);


功能:


对打开的文件指针进行定位


参数:


FileID(输入)


[0,255]


文件句柄号,从打开文件获得的返回句柄


Offset(输入)


从Whence指定的位置到要移到的位置的字节数(有符号值)


Whence(输入)


SEEK_SET


0


表示从文件头开始


SEEK_CUR


1


从当前文件指针开始


SEEK_END


2


从文件尾开始。


返回:


>=0


成功, 返回的数值是文件当前指针相对文件头的位置


-1


失败,参数错误或偏移目标超出文件范围,错误码放在errno中。


注释:


错误码介绍:

INVALID_FILEID无效的文件句柄

FILE_NOT_OPENED   文件未打开

END_OVERFLOW      后移时超出文件长度的偏移

TOP_OVERFLOW    前移时出错


示例:


调用该函数前,必须先确认指定文件已经被正确打开了:

fd = fileOpen(“filename”, O_RDWR);

1、定位到文件的第2个字节位置:

Ret = fileSeek(fd, 2, SEEK_SET);

2、定位到文件的倒数第2个字节位置:

Ret = fileSeek(fd, -2, SEEK_END);

3、定位当前位置的后面第2个字节处:

Ret = fileSeek(fd, 2, SEEK_CUR);

2.3 dev_FileRead


原型:


int dev_FileRead(int FileID, void *DataBuf, int Len);


功能:


从文件的当前定位位置开始读取文件数据


参数:


FileID(输入)


[0,255]


文件句柄号,从打开文件获得的返回句柄


DataBuf(输出)


应用指定的用来存放读取数据的缓冲区


Len(输入)


期望读取的数据字节数。


返回:


>=0


读取成功,返回实际读到的字节数。


-1


失败,错误码放在errno中


注释:


读取后文件指针位置将移动到读取后的位置

错误码介绍:

FILE_NOT_OPENED文件未打开

INVALID_FILEID无效的文件句柄


示例:


调用该函数之前,先调用fileOpen打开指定的文件:

fd = fileOpen(“Filename”, O_CREAT|O_RDWR);

1、从文件起始处读取16字节

Ret = fileSeek(fd, 0, SEEK_SET);

Ret = fileRead(fd, Buff, 16);

2、从当前光标位置处开始读取16字节:

Ret = fileSeek(fd, 0, SEEK_CUR);

Ret = fileRead(fd, Buff, 16);

3、读取文件的最后16个字节

Ret = fileSeek(fd, -16, SEEK_END);

Ret = fileRead(fd, Buff, 16);

2.4 dev_FileWrite


原型:


int dev_FileWrite(int FileID, const void *DataBuf, int Len);


功能:


从文件的当前定位位置开始写入数据


参数:


FileID(输入)


[0,255]


文件句柄号,从打开文件获得的返回句柄


DataBuf(输入)


应用指定的存放写入数据的缓冲区


Len(输入)


需要写入数据的字节数。


返回:


>=0


写入成功,返回实际写入的字节数。


-1


失败,错误码放在errno中


注释:


写入后,文件指针位置将移动到写入后的位置

错误码介绍:

INVALID_FILEID     无效的文件句柄

FILE_NOT_OPENED  文件未打开

MEM_OVERFLOW 空间不足或文件句柄太多


示例:


调用该函数之前,必须先调用fileOpen打开指定的文件:

fd = fileOpen(“filename”, O_RDWR|O_CREAT);

1、修改文件的头16个字节:

Ret = fileSeek(fd, 0, SEEK_SET);

Ret = fileWrite(fd, Buff, 16);

2、从当前光标处开始写入16字节:

Ret = fileSeek(fd, 0, SEEK_CUR);

Ret = fileWrite(fd, Buff, 16);

3、从文件结束处再写入16字节:

Ret = fileSeek(fd, 0, SEEK_END);

Ret = fileWrite(fd, Buff, 16);

2.5 dev_FileTruncate


原型:


int dev_FileTruncate(int FileID, int Len);


功能:


截短文件


参数:


FileID(输入)


[0,255]


文件句柄号,从打开文件获得的返回句柄


Len(输入)


从文件头保留的文件数据长度。


返回:


0


成功截断。


-1


失败,错误码放在errno中。


注释:


该函数将文件截断为Len长度,原文件中从Len到结尾的内容全被截去。文件指针移至截短后的文件的最后。

错误码介绍:

NO_FILESYS文件系统未建立

INVALID_FILEID    无效的文件句柄

FILE_NOT_OPENED      文件未打开

TOP_OVERFLOW          长度小于0

END_OVERFLOW        长度超出文件长度


示例:


只保留指定文件的前256字节内容:

fd = fileOpen(“filename”, O_RDWR);

Ret = fileTruncate(fd, 256);

2.6 dev_FileClose


原型:


int dev_FileClose(int FileID);


功能:


关闭已打开的文件


参数:


FileID(输入)


[0,255]


文件句柄号,从打开文件获得的返回句柄


返回:


0


成功关闭文件


-1


失败,错误码放在errno中。


注释:


错误码介绍:

INVALID_FILEID无效的文件句柄


示例:


先打开文件:

fd = fileOpen(“filename”, O_RDWR | O_CREAT);

…………………  // 文件相关处理

关闭文件:

Ret = fileClose(fd);

2.7 dev_FileRemove


原型:


int dev_FileRemove(const char *FileName);


功能:


删除文件


参数:


FileName(输入)


1-16Bytes


文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


返回:


0


成功


-1


失败,错误码放在errno中。


注释:


错误码介绍:

FILE_OPENED 文件已打开

FILE_NOEXIST 文件不存在


示例:


删除指定文件:

Ret = fileRemove(“filename”);

2.8 dev_FileSize


原型:


int dev_FileSize(const char *FileName);


参数:


FileName(输入)


1-16Bytes


文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


返回:


>=0


文件的大小


-1


失败,错误码放在errno中。


注释:


错误码介绍:

FILE_NOEXIST 文件不存在


示例:


fileLen = fileSize(“filename”); // 查询文件大小

2.9 dev_FileExist


原型:


int dev_FileExist(const char *FileName);


功能:


判断文件是否存在


参数:


FileName(输入)


1-16Bytes


文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


返回:


[0,255]


文件序号。


-1


在当前应用中没有指定的文件


注释:



示例:


判断某个文件是否存在,如存在,则获取其大小:

Ret = fileExist(“filename”);

if(Ret >= 0)

{

fileLen = fileSize(“filename”);

}

2.10 dev_FileRename


原型:


int dev_FileRename(const char *OldFileName, const char *NewFileName);


功能:


修改属于本应用的数据文件文件名


参数:


OldFileName(输入)


1-16Bytes


原文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


NewFileName(输入)


1-16Bytes


新文件名,最多可以是16个字符,以‘\x00’结尾,超过16个字符的只取前16个。


返回:


0


成功


-1


失败,错误码放在errno中。


注释:


错误码介绍:

FILE_OPENED 文件已打开

FILE_NOEXIST 文件不存在

FILE_EXIST    新文件已经存在


示例:

2.11 dev_FileFreeSpace


原型:


int dev_FileFreeSpace(void);


功能:


返回文件系统剩余可写的字节数


参数:



返回:


返回文件系统总共剩余的空间大小(字节数)


注释:



示例:


判断文件系统还有多少剩余空间:

FreeLen = fileFreeSpace();

2.12 dev_MntSDCard


原型:


int dev_MntSDCard(const char *TargetDir, int Mode);


功能:


挂载SD卡。


参数:


TargetDir(输入)


指定的挂载SD卡的目录,默认为"/mnt/sdcard/"。若为NULL则SD卡自动挂载到"/mnt/sdcard/"目录。


Mode(输入)


TRUE


挂载SD卡


FALSE


卸载SD卡


返回:


0


挂载成功


-1


挂载失败


注释:


应用层不需要关心挂载的设备名和filesystem类型。

挂载SD卡命令:mount -t vfat /dev/sdd1 /mnt/sdcard

2.13. dev_MntUSBDisk


原型:


int dev_MntUSBDisk(const char *TargetDir, int Mode);


功能:


挂载U盘。


参数:


TargetDir(输入)


指定的挂载U盘的目录,默认为"/mnt/usb/"。若为NULL则U盘自动挂载到"/mnt/usb/"目录。


Mode(输入)


TRUE


挂载U盘


FALSE


卸载U盘


返回:


0


挂载成功


-1


挂载失败


注释:


应用层不需要关心挂载的设备名和filesystem类型。

挂载U盘命令:mount -t vfat /dev/sda1 /mnt/usb

统一接口后,凡是对文件的操作,应用程序或者SDK层都只能调用这些接口,这样不管是linux平台还是其他嵌入式操作系统或非操作系统平台,应用程序对文件的操作的接口函数都是一样的了,这样就做到了应用程序不同平台的兼容性。

时间: 2024-08-16 18:36:45

嵌入式软件设计之提高代码可移植性的相关文章

Verilog代码可移植性设计(转自特权同学博客http://bbs.ednchina.com/BLOG_ARTICLE_1983188.HTM)

最近开始学习FPGA,之前项目中仅用过parameter,在CrazyBingo的<FPGA设计技巧与案例开发例程详解>中看到使用localparam,以及在366页中简单介绍了下‘define,parameter和localparam的区别.查找特权同学博客发现其曾经讲诉过.文中红色阴影处为文中错误. Verilog代码可移植性设计 1.       参数定义 localparam,实例代码如下: module tm1( clk,rst_n, pout ); input clk; input

嵌入式软件设计第11次实验报告-140201235-陈宇

嵌入式软件设计第11次实验报告 学号:140201235             姓名:陈宇 组别:第3组                实验地点:D19 一.实验目的: 1.了解短信AT指令的使用方法. 2.掌握使用短信AT指令驱动SIM900A发送和接收短信的方法. 二.实验内容: 1.使用AT命令进行模块测试,发送和接收短信. 2.编写程序利用触摸屏完成固定号码短信的发送和接收.(需要加上AT测试命令模块.手机SIM卡检测模块.手机信号质量检测模块等等.) 三.实验过程描述及结果展示: 短

嵌入式软件设计第12次实验报告-140201235-陈宇

嵌入式软件设计第12次实验报告 学号:140201235             姓名:陈宇 组别:第3组                实验地点:D19 一.实验目的: 1.掌握通过GSM短信远程与嵌入式设备进行交互的方法. 二.实验内容: 1.编写程序把嵌入式开发板采集到的温度信息通过GSM短信传送给指定号码.(每10秒发送1次) 2.编写程序,使手机可以通过短信指令的方式控制嵌入式开发板的蜂鸣器和LED灯.(比如手机编辑"BEEP_ON"和"BEEP_OFF"

嵌入式软件设计第11次实验报告-140201133-李宇昕

嵌入式软件设计第11次实验报告 学号:140201133            姓名:李宇昕 组别:第3组                实验地点:D19 一.实验目的: 1.了解短信AT指令的使用方法. 2.掌握使用短信AT指令驱动SIM900A发送和接收短信的方法. 二.实验内容: 1.使用AT命令进行模块测试,发送和接收短信. 2.编写程序利用触摸屏完成固定号码短信的发送和接收.(需要加上AT测试命令模块.手机SIM卡检测模块.手机信号质量检测模块等等.) 三.实验过程描述及结果展示: 短

浅谈嵌入式软件设计

浅谈嵌入式软件设计 本文在21IC的公众号文章<多年嵌入式编程工程师经验分享:换个角度来编程>基础上结合自己理解而写,部分图片以及文字说明均来自互联网. 前后台模型 模型介绍 当开发过程中不使用OS时,几乎所有的嵌入式程序归根结底都是一个由无法停止的循环为结构构成的,即常见的while(1)或for(;;),用流程图表示就是这样: graph TD stop[结束] start[查询IO或外设状态] --> section1[执行相关业务逻辑] section1 --> condi

SoC嵌入式软件架构设计之三:代码分块(Bank)设计原则

上一节讲述了在没有MMU的CPU(如80251.MIPS M控制器系列.ARM cortex m系列)上实现虚拟内存管理的集成硬件设计方法,新设计的内存管理管理单元要实现虚拟内存管理还需要操作系统.代码分块(Bank)的支持,详见SoC嵌入式软件架构设计之二:没有MMU的CPU实现虚拟内存管理的设计方法.这里要阐述Bank设计的一些原则. Bank设计是为了实现不同时刻运行的Bank(代码块)运行在同一块内存上,所以在运行之前操作系统需要将已存在内存的代码/数据进行缓存处理,并加载将要运行的Ba

嵌入式软件设计第8次试验

嵌入式软件设计第8次实验报告 学号:140201126                   姓名:杨鹏飞 组别:第二组                实验地点:D19 一.实验目的: 1.熟悉WWW技术中的CGI(公共网关接口)技术. 2.学会使用CGI技术编写C语言代码驱动嵌入式开发板的LED灯 和蜂鸣器. 二.实验内容: 1.编写代码完成Web服务器端蜂鸣器的驱动. 2.编写代码完成Web服务器端LED灯的驱动.三.实验过程描述及结果展示: 1.实验原理 CGI技术简介:公共网关接口CGI(

如何提高代码质量

一.代码质量 软件是交付给用户,并由用户体验的产品:代码则是对软件正确且详细的描述,所以代码质量关系到软件产品的质量.虽然软件质量不等于代码质量,但是代码上的缺陷会严重的影响到软件产品的质量.因此,为提高代码质量的投入是值得的. 二.软件产品质量通常可以从以下六个方面去衡量 功能性,即软件是否满足了客户业务要求: 可用性,即衡量用户使用软件需要付出多大的努力: 可靠性,即软件是否能够一直处在一个稳定的状态上满足可用性: 高效性,即衡量软件正常运行需要耗费多少物理资源: 可维护性,即衡量对已经完成

嵌入式软件设计第8次实验报告-140201236-沈樟伟

嵌入式软件设计第8次实验报告 学号:140201236                   姓名:沈樟伟 组别:第二组                实验地点:D19 一.实验目的: 1.熟悉WWW技术中的CGI(公共网关接口)技术. 2.学会使用CGI技术编写C语言代码驱动嵌入式开发板的LED灯和蜂鸣器. 二.实验内容: 1.编写代码完成Web服务器端蜂鸣器的驱动. 2.编写代码完成Web服务器端LED灯的驱动.三.实验过程描述及结果展示: 1.实验原理 CGI技术简介:公共网关接口CGI(C