论文部分内容阅读
【摘要】ARM是一种高性能、低功耗的32位RISC嵌入式处理器系列。目前在各种嵌入式系统中ARM获得了广泛的应用。无操作系统支持的嵌入式软件包括系统引导(BOOT)、外围驱动程序、存储管理、系统I/O、通信、应用程序等方面,需要结合采用汇编语青(约占10%)和C语言(约占90%)。本文详细介绍嵌入式系统平台的C编程方法。从概念介绍入手,介绍了系统引导与main函数、数局部变量的个数、存储管理与LCD终端(系统I/O)及驱动程序与应用程序的设计等内容,为ARM嵌入式系统C语言编程提供了可靠的依据。
【关键词】ARM嵌入式系统;C语言编程;探析
中图分类号:G623.58 文献标识码:A 文章编号:
一、前言
随着计算机技术尤其是计算机信息控制技术的深入发展,嵌入式技术得以出现,并已在众多消费类电子产品中得到成熟应用,如汽车电子设备、视频电子产品、智能家电等, 目前正在向装备制造业领域、工业自动化控制、航天产品、网络等高端领域蔓延。ARM嵌入式系统C语言编程也是其中应用的重要的一方面,本文对这一方面进行了探索,具有很大的价值。
二、嵌入式系统及ARM概念介绍
嵌入式系统也即嵌入式计算机系统,主要用于对机器装置乃至大型厂房等进行控制或监视,其特点可与普通的Pc机系统对比来体现:
1、PC机系统面向大众和大部分行业领域,而嵌入式计算机系统一般只针对特定应用;
2、PC机系统的软件一般存储于磁盘或硬盘当中,而嵌入式系统软件则基本上固化在存储器芯片或单片机上;
3、嵌入式系统要依赖一套专门的开发工具或编程环境来实现间接开发。嵌入式系统也同PC机一样由操作软件和应用软件组成,总的来看,其架构包含了嵌入式处理器、嵌入式外围设备、嵌入式操作系统和嵌入式应用软件,而这其中嵌入式处理器如同PC机的CPU,是整个嵌入式系统的核心部件。ARM系列微处理器便是嵌入式处理器中的佼佼者,其因处理速度快、功耗低且价格低廉而拥有着良好的应用前景, 目前基ARM微处理器已广泛应用于电子产品、通信网络系统和军事系统等领域。
三、系统引导与main函数
通常c语言是从main函數开始的。main函数的原型是:Int main(int argc,char ***argv),其中argv是参数的个数,argv是指向各参数的指针的数组。main函数由操作系统内核启动,操作系统内核完成函数所需的变量初始化工作,并在调用结束后检查main函数的返回值,若返回值为0,表明程序运行正常,否则表明程序运行出错。在嵌入式系统中,由于没有操作系统内核存在,对main函数的初始化工作只能由系统引导(BOOT)模块完成。系统引导(BOOT)部分完成系统初始化工作,用汇编语言实现。它的工作包括硬件初始化、栈寄存器的设置、全局变量的初始化或清0、RAM中运行的模块的加载、堆参数的初始化等。完成这些工作后,再把控制权交给C的“main函数。显然,对嵌入式系统的main而言,argc和argv这两个参数及返回值都是没有意义的(如果返回,表明系统出现严重错误)。另外,为了避免产生混淆,我们还必须给main函数另外取一个名字。否则,编译器将会给main函数生成一大堆初始化代码,导致c程序的主人口与系统引导模块的接口错误。
四、函数局部变量的个数
为了加快程序的执行速度,函数编译时应尽可能将局部变量都分配在寄存器中。当局部变量多于可用的寄存器时,编译器会将多余的变量压入堆栈(即存入存储器中),因此必须控制局部变量的个数。ARM处理器采用RISC结构,带有丰富的内部寄存器。在编译器使用一apcs开关选项,即支持ATPCS(ARM—Thumb Procedure Call Standard)标准时,理论上有14个寄存器(R0~R12,R14)可以用来存放局部变量。但是实际上有些寄存器有自身特殊的用途,例如R9在与读写位置无关(RWPI)的编译情况下作为静态基址寄存器使用,R12作为子程序内部调用的临时过渡寄存器使用。因此,应尽量限制局部变量的数目:
(1)对于函数的参数个数应控制在4个以内,只有R0~R3可用来保存参数,当参数多于4个时将被压人堆栈。如果由于实际应用的需要,参数多于4个,也可以采用结构体来组织参数,传递结构体指针来实现。
(2)函数内部局部变量的个数应控制在12个以内(R0~R11),R12~R15都有特定用途。
五、存储管理与LCD终端(系统I/O)
1、存储管理
存储管理是一个复杂的课题。从广义的角度来说,磁盘文件系统、内存、片内高速Cache等都属于这个范畴。嵌入式系统中,较有意义的是内存的动态分配与释放及Flash存储器管理两方面。本文要介绍的是我们在嵌人式系统中实现的动态内存管理。
C语言中动态内存分配与释放主要由malloc和free两个标准库函数实现。malloc从系统空闲内存中分配合适的内存块,free函数完成内存块的回收。这两个函数一般需要操作系统内棱的支持,在ARM裸平台上,不能直接调用。为此,我们编写了m—alloc和m一free两个函数,实现动态存储管理的功能。
2、LCD终端(系统I/O)
LCD终端软件是系统(系统I/O)范畴的重要内容,主要包括LCD字符显示(英文8×16点阵,汉字6×16点阵),LCD绘图(点、线、圆、面、位图、图形旋转等)。320×240象素的LCD显示器,能显示15行×40列英文字符,或5行×20列汉字字符,并基本实现有较好分辨率的图形/图像的显示。
六、驱动程序与应用程序的设计
1、驱动程序的设计
驱动程序包括最底层的中断处理程序设计和建立在其上的驱动程序设计两个部分,其实现与具体的外围设备有关,复杂性较大。这里只介绍用c语言设计驱动程序时需要注意的一些方面。外围硬件设备一般通过中断与CPU进行通信。中断是一种外部异步事件。在处理与中断相关的变量时,需要小心。C语言的编写风格也要为效率考虑。例如对数组元素的操作“Array[idx/4]=&~1;”就不如改为“Array[idx>>2]=&~1;”这里。“>>”是移位运算,有相应的机器指令,而“/”是除法运算,算法要夏杂得多。当然,先进的编译器一般能优化这类的语句,但不能保证所有编译器都有此功能。
2、用程序设计
嵌入式裸平台上的应用程序设计也有与PC机上的应用程序设计不同的地方,需要格外注意。
(一)、凡是由需操作系统支持的标准库函数均不能使用,除非自己编写(如m _alloc和m_free)。
(二)、由于内存资源有限,栈容量有限且不能自动扩展,使用时要格外小心。常常能见到这样的局部变量的应用:Int buf[2048],其目的是要申请一个2048word(8192Byte)的缓冲区,对于嵌入式系统来说.开销过于庞大。同时,栈空间巾用于嵌套调用的升销是不可见的,在嵌套层数较多时尤其如此。
(三)、同样的道理,坚决避免使用递归函数。
(四)、使用m如函数时要注意两点:
(1)要检查返回值是否为0;
(2)要适时调用m一丘钟函数释放内存。前者可以避免系统陷人不必要的崩溃,后者可以防止出现内存泄漏。
(五)、对于编译器给出的警告信息不耍忽略。有良好的编程习惯的程序员是不会放过任何一个警告的。实际上,警告常常隐含着严重的逻辑错误。即使是无关痛痒的警告,比如变量声明了却没有使用的警告,也要予以重视,因为这类警告多了之后,会把一些有意义的警告掩盖掉,最终导致错误出现。
(六)、对一些速度要求较高的关键模块,采用汇编语言实现。
七、结束语
目前,嵌入式应用日渐普及,嵌人式软件越来越受到关注。本文在此只介绍了几种具有代表性的ARM 嵌入式系统与C语言编程的结合点,除此还有诸如应用程序设计中,嵌入式平台上的应用程序设计常常面临着标准库函数无法直接借用和内存资源有限带来的栈容量无法自动扩展的设计难题,而借助C语言编程很好地解决了这一问题。相信随着嵌入式软件的不断增多和成熟,ARM 嵌入式系统将得到越来越多的应用。
参考文献
[1]严蔚敏,吴伟民.数据结椅(第二版)[M].清华大学出版社,1992.
[2]田泽.嵌入式系统开发与应用教程[M].北京航空航天大学出版社,2004:273—285.
[3]周立功.ARM嵌入式系统基础教程[M].北京航空航天大学出版社,2005:159—186.
[4]孙曼曼,姬龙涛.浅谈基于ARM 的嵌入式系统[J].福建电脑,2010,3.
[5]姜换新.ARM嵌入式系统C语言编程[J].北京航空航天大学出版社,2010.
【关键词】ARM嵌入式系统;C语言编程;探析
中图分类号:G623.58 文献标识码:A 文章编号:
一、前言
随着计算机技术尤其是计算机信息控制技术的深入发展,嵌入式技术得以出现,并已在众多消费类电子产品中得到成熟应用,如汽车电子设备、视频电子产品、智能家电等, 目前正在向装备制造业领域、工业自动化控制、航天产品、网络等高端领域蔓延。ARM嵌入式系统C语言编程也是其中应用的重要的一方面,本文对这一方面进行了探索,具有很大的价值。
二、嵌入式系统及ARM概念介绍
嵌入式系统也即嵌入式计算机系统,主要用于对机器装置乃至大型厂房等进行控制或监视,其特点可与普通的Pc机系统对比来体现:
1、PC机系统面向大众和大部分行业领域,而嵌入式计算机系统一般只针对特定应用;
2、PC机系统的软件一般存储于磁盘或硬盘当中,而嵌入式系统软件则基本上固化在存储器芯片或单片机上;
3、嵌入式系统要依赖一套专门的开发工具或编程环境来实现间接开发。嵌入式系统也同PC机一样由操作软件和应用软件组成,总的来看,其架构包含了嵌入式处理器、嵌入式外围设备、嵌入式操作系统和嵌入式应用软件,而这其中嵌入式处理器如同PC机的CPU,是整个嵌入式系统的核心部件。ARM系列微处理器便是嵌入式处理器中的佼佼者,其因处理速度快、功耗低且价格低廉而拥有着良好的应用前景, 目前基ARM微处理器已广泛应用于电子产品、通信网络系统和军事系统等领域。
三、系统引导与main函数
通常c语言是从main函數开始的。main函数的原型是:Int main(int argc,char ***argv),其中argv是参数的个数,argv是指向各参数的指针的数组。main函数由操作系统内核启动,操作系统内核完成函数所需的变量初始化工作,并在调用结束后检查main函数的返回值,若返回值为0,表明程序运行正常,否则表明程序运行出错。在嵌入式系统中,由于没有操作系统内核存在,对main函数的初始化工作只能由系统引导(BOOT)模块完成。系统引导(BOOT)部分完成系统初始化工作,用汇编语言实现。它的工作包括硬件初始化、栈寄存器的设置、全局变量的初始化或清0、RAM中运行的模块的加载、堆参数的初始化等。完成这些工作后,再把控制权交给C的“main函数。显然,对嵌入式系统的main而言,argc和argv这两个参数及返回值都是没有意义的(如果返回,表明系统出现严重错误)。另外,为了避免产生混淆,我们还必须给main函数另外取一个名字。否则,编译器将会给main函数生成一大堆初始化代码,导致c程序的主人口与系统引导模块的接口错误。
四、函数局部变量的个数
为了加快程序的执行速度,函数编译时应尽可能将局部变量都分配在寄存器中。当局部变量多于可用的寄存器时,编译器会将多余的变量压入堆栈(即存入存储器中),因此必须控制局部变量的个数。ARM处理器采用RISC结构,带有丰富的内部寄存器。在编译器使用一apcs开关选项,即支持ATPCS(ARM—Thumb Procedure Call Standard)标准时,理论上有14个寄存器(R0~R12,R14)可以用来存放局部变量。但是实际上有些寄存器有自身特殊的用途,例如R9在与读写位置无关(RWPI)的编译情况下作为静态基址寄存器使用,R12作为子程序内部调用的临时过渡寄存器使用。因此,应尽量限制局部变量的数目:
(1)对于函数的参数个数应控制在4个以内,只有R0~R3可用来保存参数,当参数多于4个时将被压人堆栈。如果由于实际应用的需要,参数多于4个,也可以采用结构体来组织参数,传递结构体指针来实现。
(2)函数内部局部变量的个数应控制在12个以内(R0~R11),R12~R15都有特定用途。
五、存储管理与LCD终端(系统I/O)
1、存储管理
存储管理是一个复杂的课题。从广义的角度来说,磁盘文件系统、内存、片内高速Cache等都属于这个范畴。嵌入式系统中,较有意义的是内存的动态分配与释放及Flash存储器管理两方面。本文要介绍的是我们在嵌人式系统中实现的动态内存管理。
C语言中动态内存分配与释放主要由malloc和free两个标准库函数实现。malloc从系统空闲内存中分配合适的内存块,free函数完成内存块的回收。这两个函数一般需要操作系统内棱的支持,在ARM裸平台上,不能直接调用。为此,我们编写了m—alloc和m一free两个函数,实现动态存储管理的功能。
2、LCD终端(系统I/O)
LCD终端软件是系统(系统I/O)范畴的重要内容,主要包括LCD字符显示(英文8×16点阵,汉字6×16点阵),LCD绘图(点、线、圆、面、位图、图形旋转等)。320×240象素的LCD显示器,能显示15行×40列英文字符,或5行×20列汉字字符,并基本实现有较好分辨率的图形/图像的显示。
六、驱动程序与应用程序的设计
1、驱动程序的设计
驱动程序包括最底层的中断处理程序设计和建立在其上的驱动程序设计两个部分,其实现与具体的外围设备有关,复杂性较大。这里只介绍用c语言设计驱动程序时需要注意的一些方面。外围硬件设备一般通过中断与CPU进行通信。中断是一种外部异步事件。在处理与中断相关的变量时,需要小心。C语言的编写风格也要为效率考虑。例如对数组元素的操作“Array[idx/4]=&~1;”就不如改为“Array[idx>>2]=&~1;”这里。“>>”是移位运算,有相应的机器指令,而“/”是除法运算,算法要夏杂得多。当然,先进的编译器一般能优化这类的语句,但不能保证所有编译器都有此功能。
2、用程序设计
嵌入式裸平台上的应用程序设计也有与PC机上的应用程序设计不同的地方,需要格外注意。
(一)、凡是由需操作系统支持的标准库函数均不能使用,除非自己编写(如m _alloc和m_free)。
(二)、由于内存资源有限,栈容量有限且不能自动扩展,使用时要格外小心。常常能见到这样的局部变量的应用:Int buf[2048],其目的是要申请一个2048word(8192Byte)的缓冲区,对于嵌入式系统来说.开销过于庞大。同时,栈空间巾用于嵌套调用的升销是不可见的,在嵌套层数较多时尤其如此。
(三)、同样的道理,坚决避免使用递归函数。
(四)、使用m如函数时要注意两点:
(1)要检查返回值是否为0;
(2)要适时调用m一丘钟函数释放内存。前者可以避免系统陷人不必要的崩溃,后者可以防止出现内存泄漏。
(五)、对于编译器给出的警告信息不耍忽略。有良好的编程习惯的程序员是不会放过任何一个警告的。实际上,警告常常隐含着严重的逻辑错误。即使是无关痛痒的警告,比如变量声明了却没有使用的警告,也要予以重视,因为这类警告多了之后,会把一些有意义的警告掩盖掉,最终导致错误出现。
(六)、对一些速度要求较高的关键模块,采用汇编语言实现。
七、结束语
目前,嵌入式应用日渐普及,嵌人式软件越来越受到关注。本文在此只介绍了几种具有代表性的ARM 嵌入式系统与C语言编程的结合点,除此还有诸如应用程序设计中,嵌入式平台上的应用程序设计常常面临着标准库函数无法直接借用和内存资源有限带来的栈容量无法自动扩展的设计难题,而借助C语言编程很好地解决了这一问题。相信随着嵌入式软件的不断增多和成熟,ARM 嵌入式系统将得到越来越多的应用。
参考文献
[1]严蔚敏,吴伟民.数据结椅(第二版)[M].清华大学出版社,1992.
[2]田泽.嵌入式系统开发与应用教程[M].北京航空航天大学出版社,2004:273—285.
[3]周立功.ARM嵌入式系统基础教程[M].北京航空航天大学出版社,2005:159—186.
[4]孙曼曼,姬龙涛.浅谈基于ARM 的嵌入式系统[J].福建电脑,2010,3.
[5]姜换新.ARM嵌入式系统C语言编程[J].北京航空航天大学出版社,2010.