C / 嵌入式软件开发 / 哦!这就是嵌入式软件开发

写在前面的话

2013年6月份,两年,所谓的嵌入式软件工程师,其实是9527型程序员。老程序员可能会告诉我们,“你可以在这个行业有梦想,但它不应该是生活的全部”。我同意,不过那是30岁后的事了,如果20多岁的年轻人梦想不是你的全部,请问你拿什么跟别人拼,干爹?这两年,像很多diors一样,工作上显得碌碌无为,执行一些繁杂而又缺乏技术含量的任务。OK,打住,再多抱怨无用,多编程多总结才是可行的,这两天一直在想一个问题:嵌入式软件开发和其它像服务器编程、移动开发、Web编程相比,包括开发环境在内都有哪些不同呢?话说这个问题本该是初学时就要先了解的,随便了,总结而已。

在网上看到一份pdf档《C语言嵌入式系统编程修炼》,很好的总结了在嵌入式系统开发的知识,有兴趣的可在网上搜一下。

以下是我写的一点读书笔记,与大家分享,里面的东西不知道大家是不是真的掌握了,反正我好多都没掌握。


 

硬件架构

软件架构

内存操作
屏幕、键盘操作
性能优化



软件架构:

#开发环境

就像没有人在手机或者平板上写代码一样,嵌入式软件开发大都也是在PC在编程,编程环境的话,各不相同,基本上都是在PC上用各类编辑软件写好代码后,用本地交叉编译环境Cygwin或者服务器上的编译环境去自动编译整包代码,完后把可执行档案想办法读到平台RAM里面去,最后用PC串口与平台通信,用打印信息或其它上位机软件来调试。整个开发或者Debug过程大多都是这样,当然其它还有什么的话,我就不知道了... ...和服务器编程、移动开发、Web编程不同的是,这些都有强大的技术支持,而嵌入式软件开发一般不会有模拟器让普通开发者使用,不会有Firebug或开发者工具之类的东西使用,因为大多是定制的原因,走的路线很多时候往往和标准不太一样,这一切都让嵌入式软件开发比其它开发环境艰难。


#按照功能进行模块划分(p.s.:在OOP中这种设计是错误的)

1. 模块即是一个(堆).c档和一个.h档的结合,.h档是开给别人用的编程接口;

2. .c档里不想被别人使用的东西定义为static保护起来;

3. 如果模块的.c档里既没有用static来保护函数或数据,又没有在.h档里面开出相应的接口,别人就可以用extern来使用你的函数或数据;

4. 不要在.h档中出现这样的东西:

 

int a = 10;

因为这个.h档如果被很多人include 的话,那内存中就会有很多份的a变量;如果你想把你.c档里的变量作为全局变量开给外面的人来用,你可以在.h档中用

extern int a;

的方式,这样,你完全可以把.c编译成一个.dll档或.a或.so等等提供出去。

 


#单任务,多任务

单任务,典型的是以前没有操作系统的功能手机,一直while(1)或for(;;)在那里,然后不断的polling各个模块。主流程像这样:

0. CPU到指定地址执行去跑汇编

1. 跳到main函数所在的地址,开始跑C代码,做init hw, init sw

2. 

 

for(;;)

{

    A();

    B();

    C();

}

多任务,现在的嵌入式系统几乎都带操作系统,按不同的方案需求选用不同的系统,如果没有非常实时的要求,嵌入式Linux是个不错的选择,现在很多的嵌入式设备都是基于嵌入式Linux系统来开发。既然有支持多任务的操作系统存在,那上面的死循环就不是简单的轮询了,任务调度,消息处理也让嵌入式系统的可开发的功能变得更多,更强大,现在,和开发PC上的程序就几乎无异了。

 


#ISR

硬件中断

软件中断,ANSI C不支持中断,需要编译器添加对C的中断的支持。中断的编写要求:

1. 不能传参,不能有返回值

2. 功能mini一点

3. 不能有printf


#让C也面向对象

OOP的三大特征:封装、继承、多态;

1. 封装:

C没有C++中的类,但可以在structure里面数据集合的基础上写一些函数指针来模拟;

2. 继承:

从GObject的思想我们可以知道,在structure定义的开始位置如果是另一个structure的变量,那么我们就模拟继承了一个“类”。

3. 多态:

在成功继承之后,我们便可以通过强制类型转换的手法(GObject中把它封装成了宏)来模拟多态的特性。


可参考GObject对象系统:http://www.ibm.com/developerworks/cn/linux/l-gobject/ 来实现C的面向对象。


内存操作:

#之所以在嵌入式系统中使用C语言进行程序开发,主要因为它具备强大的内存操作能力。
#数据指针

CPU以Byte为单位来编址,而C语言指针以指向的数据类型长度作++/--

#函数指针

1. C语言的函数名直接对应于函数生成的指令代码在内存中的地址;

2. 调用函数实际上等同于“跳转指令 + 参数传递处理 + 回归位置入栈”,本质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的PC寄存器;

#数组vs动态申请(谁申请谁释放)
#const

const int a;
int const a;
const int* a;
int* const a;
int const* a const;
const int SIZE = 10; /* 不能改变的"变量" */
char a[SIZE]; /* 非法;因为编译阶段不能用到变量 */
#volatile

1. 防止编译器的误优化;

2. 主要用在处在共享状态的变量身上。

 


性能优化:

#使用宏
减少函数调用和函数返回的开销
 #define MIN(A,B) (A<=B?A:B) /* Wrong */
 #define MIN(A,B) ((A)<=(B)?(A):(B)) /* OK,宏定义需要括上所有参数*/
#使用寄存器变量

register i=0; /* 只有局部自动变量和形参才可以定义为寄存器变量,因为寄存器变量属于动态存储方式,且register只是一个“建议型”关键字 */


# 使用内嵌汇编

int result;

void add(long a, long b)

{

_asm

{

MOV AX, a

MOV BX, b

ADD AX, [BX]

MOV result, AX

}

}


#利用硬件特性:CPU对各种存储器的访问速度
1. CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM, 对于程序代码,最好在系统启动后将FLASH/ROM中的目标代码拷入RAM中后再执行以提高取指令速度 
2. 使用DMA读取方式在读取存储信息较大时效率较高,以块来传输
#使用位操作

<<

>>

&
|

~


以上,只是C语言在嵌入式软件编程当中的一些常识性的知识,而在自己实际的工作当中却很少注意到这些知识点,这些最基本的东西让你知道,嵌入式软件编程是这样。

 

你可能感兴趣的:(软件开发)