摘要:介绍PIC系列单片机C言语的开展;以HI-TECH Software公司的HI-TECH PICC为例,介绍PICC编译器的特色和用其开发PIC系列单片机时应留意的一些问题。 关键词:PIC PICC编译器 C言语/汇编言语 Hi-Tech 导言 现在,在市场上运用最广泛的应该归于8位单片机,Microchip Technoloogy公司推出的8位PIC系列单片机,现在在国内市场上深受用户欢迎,现已逐步成为单片机运用的新潮流;但惋惜的是,现在国内介绍它的 C言语开发工具的书本和文章却比较少,并且用的人也不多,广阔的程序员在用其开发的过程中都在渐渐探索,或许会走一些弯路。笔者最近在用PIC的C言语时就遇到了好些问题,在这里想和最近一段时间用PIC的C言语的一些经历和广阔的底层软件程序员做一下沟通和介绍期望本文对用PICC开发PIC系列单片机的人有所协助。 现在,在国内用得比较多的是Hi-Tech的Hi-Tech PICC编译器,并且现在市场上一些国内的PIC单片机仿真器也开端支撑Hi-Tech PICC编译格局;因而,本文主要以Hi-Tech的PICC为根底,介绍一下PIC的C言语的底子特色。 1 Hi-Tech PICC的C言语开发工具的言语特色 PICC的C言语按ANSI C来界说,并进行了C言语的扩展。PICC和ANSI C有一个底子的差异便是,PICC不支撑函数的递归调用。这是因为PIC单片机的仓库巨细是由硬件决议的,资源有限,所以不支撑递归调用。它的数据也遵照规范C的数据结构,PICC的数据结构是以数据类型的方式呈现的。PICC编译器支撑的数据类型有位类型(bit)、无符号字符(unsigned char)、有符号字符(signed char)、无符号整型(unsigned int)、有符号整形(signed int)、无符号长整型(unsigned long)、有符号长整型(signed long)、浮点(float)和指针类型等。需求留意的是,PICC支撑的多字节数据都选用低字节在前,高字节在后的准则。即一个多字节数,比方int 型,在内存单元中存储次序为低位字节存储在地址低的存储单元。高位字节存储在地址高的存储单元中,程序员在用union界说变量时必定要留意这一特色。 PIC的C言语变量分为局部变量和大局变量,一切变量在运用前有必要先界说后运用。大局变量是在任何函数之外阐明的、可被恣意模块运用的、在整个程序履行期间都坚持有用的变量。局部变量在函数内部阐明。局部变量有两种:主动变量和静态变量。缺省类型为主动变量,除非清晰将其声明为静态变量。并且,一切的主动变量都被分配在寄存器页0,所以bank限定词不能用于主动变量,便能够用于静态的局部变量。当程序退出时,主动变量占用的空间开释,主动变量也就失掉含义。静态变量是一种局部变量,只在声明它的函数内部有用;但它占用固定的存储单元,而这个存储单元不会被其他函数运用,因而其它函数能够经过指针拜访或修正静态变量的值。静态变量在程序开端只初始化一次,因而若只在某函数内部运用一变量,而又期望其值在2次函数调用期间坚持不变,为完成程序模块化,则可将其声明为静态变量。例如以下声明中,有些为合法,有些为不合法: void max(void) unsigned char var1; //合法声明 unsigned char bank1 var2; //不合法声明 static unsigned char bank1 ver3; //合法声明 unsigned char var4=0x02; //合法声明,每次调用都初始化 static unsigned char bank1 var5=0x02; //合法声明,但只初始化一次 ………… } PICC编译器对局部变量及传递参数运用RAM掩盖技能。编译时,连接器会主动把一些不或许被一起调用的函数的主动变量区堆叠在一起,以到达内存的高效运用,因而其内部RAM的运用功率十分高。 2 函数调用时参数的传递 PICC函数参数的传递是依据被传参数的长度,用W、被调函数的主动变量区域或被调函数的参数区域传递,传递代码比较高效。传递给函数的参数能够经过一个由问号“?”、下划线“_”及函数名加一个偏移量构成的标号获取。下面为一调用求和子程序的源泉代码: Unsigned char add_function(unsigned char augend,unsigned char addend); Void main(void) { unsigned char temp1,temp2,temp3; tem3=add_function(temp1,temp2); } unsigned char add_function(unsigned char augend,unsigned char addend) { return(augend + addend); } 编译后生成的汇编程序为: _main ; _temp2 assigned to?a_main+0 ;_temp3 assigned to ?a_main+1 ; _temp1 assigned to ?a_main+2 bcf status,5 bcf status,6 movf (((?a_main+0))),w movwf(((?_add_function))) movf (((?a_main+2))),w fcall (_add_function) movwf(((?a_main+1))) _add_function ; _augend assigned to ?a_add_function+0 ; _augend stored from w bcf status,5 bcf status,6 movwf(((?a_add_function+0))) movf (((?a_add_function+0))),w addwf (((?_add_function+0))),w return 3 PICC言语和汇编言语的混合编程 一般情况下,主程序都是用C言语编写的。C言语与汇编言语最大的差异在于,汇编程序履行功率较高,因为,C言语首要要用C编译器生成汇编代码,在不少情况下,C编译器生成的汇编代码不如用手艺生成的汇编代码功率高。在PICC中,能够用两种方法在C程序中调用汇编程序。一种方法是运用#asm,#endasm及asm()在C言语中直接嵌入汇编代码,#asm和#endasm指令别离用于标明嵌入汇编程序块的最初和结属;asm()用于将单条汇编指令嵌入到编译器生成的代码中,如下所示: void func1(void){ asm(NOP); #asm nop rlf_var,f #endasm asm(rlf_var,f); } 需求留意的是,嵌入汇编不是完好含义上的汇编,是一种伪汇编指令,运用时有必要留意它们与编译器生成代码之间的彼此影响。 另一种方法是将汇编作为一个独立的模块,用汇编编译器(ASPIC)生成方针文件,然后用链接器和C言语生成的其它模块的方针文件链接在一起。假如变量要公用时,则在另一个模块中阐明为外部类型,并答应运用方式参数和回来值。 例如,假如在C模块中运用汇编模块中的函数,那么在C中可知下声明: extern char rotate_left(char); 本声明阐明晰要调用的这个外部函数有一个char型方式参数,并回来一个char型的值。而rotate_left()函数的真实函数体在外部能够被 ASPIC编译的汇编模块(文件名后缀.as)中,具体代码能够如下编写: processor16C84 PSECT text0,class=CODE,local,delta=2 GLOBAL _rotate_left SIGNAT _rotate_4201 _rotate_left movwf?a_rotate_left rlf?a_rotate_left,w return FNSIZE _rotate_left,1,0 GLOBAL?a_rotate_left END 需求留意的是,以C模块中声明的函数称号,在汇编模块中是以下划线最初的。GLOBAL界说了一个大局变量,也等同于C模块中的 extern,SIGNAL强制链接器在链接各个方针文件模块时进行类型匹配查看,FNSIZE界说局部变量和方式参数的内存分配。 这种方法比较费事,假如对某一模块的履行功率要求较高时,能够采纳这种方法;可是,为了确保汇编程序能正常运转,有必要严格遵守函数参数传递和回来规矩。当然,为防止这些规矩带来的费事,一般情况下,能够先用C言语大致编写一个相似功用的函数,预先界说好各种变量,选用PICC-S选项对程序进行编译,然后手艺优化编译器发生的汇编代码后将其作为独立的模块就能够了。 4 留意事项 运用PICC时,为了更有用地运用资源,应留意以下几点: ①尽量运用无符号数和字节变量。 ②在寄存器资源答应的情况下,对某些履行功率要求较高的平级元彼此调用函数中用到的内部变量,可将其界说为大局暂时变量,编程时掩盖运用,这样可削减许多编译代码。而关于中止函数内部用到的变量,可用大局变量。 ③关于有必定汇编经历的人在开端运用PICC时,应多留意观看编译后发生的汇编源代码,并常常观看经正确编译链接后发生的映像文件(.MAP文件)。在该文件中,具体列出了分配给变量和代码的地址和生成代码的巨细等信息。运用者可了解代码是否优化,变量分配是否合理,仓库是否溢出等,然后写出高效简练的C 源代码。 ④在许多情况下,PICC不支撑类型强制转化。即在类型不匹配时须查验编译后的汇编代码,看是否正确,尤其是对指针操作的时分必定要留意。 ⑤对某位变量自操作时,比方求反,不能够直接简写,例如:!flag;编译后不能正确发生代码,而须写成:“flag=!flag;” ⑥尽量挑选大局优化编译选项。为确保寄存器页(包含程序存储期页面和RAM寄存器页)的正确转化,PICC的编译代码中有很多的改换寄存器页的代码,挑选大局优化PICC会优化去很多有关RP0、RP1、PCLAPH所添加的改换代码,然后加速程序履行速度,并节约很多的程序空间。 ⑦若有某一代码很短的函数被多个函数常常调用,最好将其界说为宏。因为若函数代码很短时,因为被调函数和调用函数不在同一代码页所发生的附加代码或许都会超越函数代码自身的长度。 5 定论 PICC编译器发生的代码在有些时分尽管比较繁琐,但结构和逻辑性很强,开发功率大大提高,调试与保护都很便利。不论是从程序的开发速度、软件质量仍是从程序的可保护性和可移植性上讲,PICC的长处绝非汇编言语所能比较的。