第十一章 PIC 单片机的 C 语言编程.pdf
《第十一章 PIC 单片机的 C 语言编程.pdf》由会员分享,可在线阅读,更多相关《第十一章 PIC 单片机的 C 语言编程.pdf(26页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 张明峰 2004-4-7 于上海 1 of 26 第十一章第十一章 PIC 单片机的单片机的 C 语言编程语言编程 11.1 PIC 单片机单片机 C 语言编程简介语言编程简介 用 C 语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、代码的重复利用率高、便于跨平台的代码移植等等,因此 C 语言编程在单片机系统设计中已得到越来越广泛的运用。针对 PIC 单片机的软件开发,同样可以用 C 语言实现。但在单片机上用 C 语言写程序和在 PC 机上写程序绝对不能简单等同。现在的 PC 机资源十分丰富,运算能力强大,因此程序员在写 PC 机的应用程序时几乎不用关心编译后
2、的可执行代码在运行过程中需要占用多少系统资源,也基本不用担心运行效率有多高。写单片机的 C 程序最关键的一点是单片机内的资源非常有限,控制的实时性要求又很高,因此,如果没有对单片机体系结构和硬件资源作详尽的了解,以笔者的愚见认为是无法写出高质量实用的 C 语言程序。这就是为什么前面所有章节中的的示范代码全部用基础的汇编指令实现的原因,希望籍此能使读者对 PIC 单片机的指令体系和硬件资源有深入了解,在这基础之上再来讨论 C 语言编程,就有水到渠成的感觉。本书围绕中档系列PIC单片机来展开讨论,Microchip公司自己没有针对中低档系列PIC单片机的 C 语言编译器,但很多专业的第三方公司有众
3、多支持 PIC 单片机的 C 语言编译器提供,常见的有 Hitech、CCS、IAR、Bytecraft 等公司。其中笔者最常用的是 Hitech 公司的PICC 编译器,它稳定可靠,编译生成的代码效率高,在用 PIC 单片机进行系统设计和开发的工程师群体中得到广泛认可。其正式完全版软件需要购置,但在其网站上有限时的试用版供用户评估。另外,Hitech 公司针对广大 PIC 的业余爱好者和初学者还提供了完全免费的学习版 PICC-Lite 编译器套件,它的使用方式和完全版相同,只是支持的 PIC 单片机型号限制在 PIC16F84、PIC16F877 和 PIC16F628 等几款。这几款 F
4、lash 型的单片机因其所具备的丰富的片上资源而最适用于单片机学习入门,因此笔者建议感兴趣的读者可从 PICC-Lite 入手掌握 PIC 单片机的 C 语言编程。在此列出几个主要的针对 PIC 单片机的 C 编译器相关连接网址,供读者参考:Hitech-PICC: IAR: CCS: ByteCraft: 本章将介绍 Hitech-PICC 编译器的一些基本概念,由于篇幅所限将不涉及 C 语言的标准语法和基础知识介绍,因为在这些方面都有大量的书籍可以参考。重点突出针对 PIC 单片机的特点而所需要特别注意的地方。11.2 Hitech-PICC 编译器编译器 PICC 基本上符合 ANSI
5、标准,除了一点:它不支持函数的递归调用。其主要原因是因为 PIC 单片机特殊的堆栈结构。在前面介绍 PIC 单片机架构时已经详细说明了 PIC 单片机 张明峰 2004-4-7 于上海 2 of 26 中的堆栈是硬件实现的,其深度已随芯片而固定,无法实现需要大量堆栈操作的递归算法;另外在 PIC 单片机中实现软件堆栈的效率也不是很高,为此,PICC 编译器采用一种叫做“静态覆盖”的技术以实现对 C 语言函数中的局部变量分配固定的地址空间。经这样处理后产生出的机器代码效率很高,按笔者实际使用的体会,当代码量超过 4K 字后,C 语言编译出的代码长度和全部用汇编代码实现时的差别已经不是很大(10%
6、),当然前提是在整个 C代码编写过程中须时时处处注意所编写语句的效率,而如果没有对 PIC 单片机的内核结构、各功能模块及其汇编指令深入了解,要做到这点是很难的。11.3 MPLAB-IDE 内挂接内挂接 PICC PICC 编译器可以直接挂接在 MPLAB-IDE 集成开发平台下,实现一体化的编译连接和原代码调试。使用 MPLAB-IDE 内的调试工具 ICE2000、ICD2 和软件模拟器都可以实现原代码级的程序调试,非常方便。首先必须在你的计算机中安装 PICC 编译器,无论是完全版还是学习版都可以和MPLAB-IDE 挂接。安装成功后可以进入 IDE,选择菜单项 Project?Set
7、 Language Tool Locations,打开语言工具挂接设置对话框,如图 11-1 所示:在对话框中选择“HI-TECH PICC Toolsuite”栏,展开可执行文件组“Executable”后,列出了将被 MPLAB-IDE 后台调用的编译器所用到的所有可执行文件,其中有汇编编译器“PICC Assembler”、C 原程序编译器“PICC Compiler”和连接定位程序“PICC Linker”。同时在此列表中还显示了对应的可执行程序名,请注意在这里都是“PICC.EXE”。用鼠标分别点击选中这三项可执行文件,观察对话框下面“Location”一栏中显示的文件路径,用“Br
8、owse”按纽,从计算机中已经安装的 PICC 编译器文件夹中选择 PICC.EXE 文件。实际上 PICC.EXE 只是一个调度管理程序,它会按照所输入的文件扩展名自动调用对应的编译器和连接器,用户要注意的是 C 语言原程序扩展名用“.c”,汇编原程序用“.as”即可。工具挂接完成后,在建立项目时可以选择语言工具为“HI-TECH PICC”,具体步骤可以参阅第三章 3.1.3 节,此处不再重复。项目建立完成后可以加入 C 或汇编原程序,也可以加入已有的库文件或已经编译的目标文件。最常见的是只加入 C 原程序。用 C 语言编程的好 图 11-1 MPLAB-IDE 语言工具设置对话框 张明峰
9、 2004-4-7 于上海 3 of 26 处是可以实现模块化编程。程序编写者应尽量把相互独立的控制任务用多个独立的 C 原程序文件实现,如果程序量较大,一般不要把所有的代码写在一个文件内。图 11-2 列出的是笔者建立的一个项目中所有 C 原程序模块,其中主控、数值计算、I2C 总线操作、命令按键处理和液晶显示驱动等不同的功能分别在不同的独立的原程序模块中实现。11.4 PIC 单片机的单片机的 C 语言原程序基本框架语言原程序基本框架 基于 PICC 编译环境编写 PIC 单片机程序的基本方式和标准 C 程序类似,程序一般由以下几个主要部分组成:?在程序的最前面用#include 预处理指
10、令引用包含头文件,其中必须包含一个编译器提供的“pic.h”文件,实现单片机内特殊寄存器和其它特殊符号的声明;?用“_CONFIG”预处理指令定义芯片的配置位;?声明本模块内被调用的所有函数的类型,PICC 将对所调用的函数进行严格的类型匹配检查;?定义全局变量或符号替换;?实现函数(子程序),特别注意 main 函数必须是一个没有返回的死循环。下面的例 11-1 为一个 C 原程序的范例,供大家参考。#include /包含单片机内部资源预定义#include“pc68.h”/包含自定义头文件 /定义芯片工作时的配置位 _CONFIG(HS&PROTECT&PWRTEN&BOREN&WDTD
11、IS);/声明本模块中所调用的函数类型 void SetSFR(void);void Clock(void);void KeyScan(void);void Measure(void);void LCD_Test(void);void LCD_Disp(unsigned char);/定义变量 unsigned char second,minute,hour;bit flag1,flag2;/函数和子程序 图 11-2 C 语言多模块编程 张明峰 2004-4-7 于上海 4 of 26 void main(void)SetSFR();PORTC=0 x00;TMR1H+=TMR1H_CONS
12、T;LED1=LED_OFF;LCD_Test();/程序工作主循环 while(1)asm(“clrwdt”);/清看门狗 Clock();/更新时钟 KeyScan();/扫描键盘 Measure();/数据测量 SetSFR();/刷新特殊功能寄存器 例 11-1 C 语言原程序框架举例 11.5 PICC 中的变量定义中的变量定义 11.5.1 PICC 中的基本变量类型 PICC 支持的基本变量类型见表 11-1:类型 长度(位数)数学表达 bit 1 布尔型位变量,0 或 1 两种取值 char 8 有符号或无符号字符变量,PICC 缺省认定 char 型变量为无符号数,但可以通过
13、编译选项改为有符号字节变量 unsigned char 8 无符号字符变量 short 16 有符号整型数 unsigned short 16 无符号整型数 int 16 有符号整型数 unsigned int 16 无符号整型数 long 32 有符号长整型数 unsigned long 32 无符号长整型数 float 24 浮点数 double 24 或 32 浮点数,PICC 缺省认定 double 型变量为 24 位长,但可以改变编译选项改成 32 位 表 11-1 PICC 的基本变量类型 PICC 遵循 Little-endian 标准,多字节变量的低字节放在存储空间的低地址,高
14、字节放在高地址。张明峰 2004-4-7 于上海 5 of 26 11.5.2 PICC 中的高级变量 基于表 11-1 的基本变量,除了 bit 型位变量外,PICC 完全支持数组、结构和联合等复合型高级变量,这和标准的 C 语言所支持的高级变量类型没有什么区别。例如:数组:unsigned int data10;结构:struct commInData unsigned char inBuff8;unsigned char getPtr,putPtr;联合:union int_Byte unsigned char c2;unsigned int i;例 11-2 C 语言高级变量举例 11
15、.5.3 PICC 对数据寄存器 bank 的管理 为了使编译器产生最高效的机器码,PICC 把单片机中数据寄存器的 bank 问题交由编程员自己管理,因此在定义用户变量时你必须自己决定这些变量具体放在哪一个 bank 中。如果没有特别指明,所定义的变量将被定位在 bank0,例如下面所定义的这些变量:unsigned char buffer32;bit flag1,flag2;float val8;除了 bank0 内的变量声明时不需特殊处理外,定义在其它 bank 内的变量前面必须加上相应的 bank 序号,例如:bank1 unsigned char buffer32;/变量定位在 ba
16、nk1 中 bank2 bit flag1,flag2;/变量定位在 bank2 中 bank3 float val8;/变量定位在 bank3 中 中档系列 PIC 单片机数据寄存器的一个 bank 大小为 128 字节,刨去前面若干字节的特殊功能寄存器区域,在 C 语言中某一 bank 内定义的变量字节总数不能超过可用 RAM 字节数。如果超过 bank 容量,在最后连接时会报错,大致信息如下:Error000 :Cant find 0 x12C words for psect rbss_1 in segment BANK1 连接器告诉你总共有 0 x12C(300)个字节准备放到 ban
17、k1 中但 bank1 容量不够。显然,只有把一部分原本定位在 bank1 中的变量改放到其它 bank 中才能解决此问题。虽然变量所在的 bank 定位必须由编程员自己决定,但在编写原程序时进行变量存取操作前无需再特意编写设定 bank 的指令。C 编译器会根据所操作的对象自动生成对应 bank 设定的汇编指令。为避免频繁的 bank 切换以提高代码效率,尽量把实现同一任务的变量定位在同一个 bank 内;对不同 bank 内的变量进行读写操作时也尽量把位于相同 bank 内的变量归并在一起进行连续操作。张明峰 2004-4-7 于上海 6 of 26 11.5.4 PICC 中的局部变量
18、PICC 把所有函数内部定义的 auto 型局部变量放在 bank0。为节约宝贵的存储空间,它采用了一种被叫做“静态覆盖”的技术来实现局部变量的地址分配。其大致的原理是在编译器编译原代码时扫描整个程序中函数调用的嵌套关系和层次,算出每个函数中的局部变量字节数,然后为每个局部变量分配一个固定的地址,且按调用嵌套的层次关系各变量的地址可以相互重叠。利用这一技术后所有的动态局部变量都可以按已知的固定地址地进行直接寻址,用 PIC 汇编指令实现的效率最高,但这时不能出现函数递归调用。PICC 在编译时会严格检查递归调用的问题并认为这是一个严重错误而立即终止编译过程。既然所有的局部变量将占用 bank0
19、 的存储空间,因此用户自己定位在 bank0 内的变量字节数将受到一定的限制,在实际使用时需注意。11.5.5 PICC 中的位变量 bit 型位变量只能是全局的或静态的。PICC 将把定位在同一 bank 内的 8 个位变量合并成一个字节存放于一个固定地址。因此所有针对位变量的操作将直接使用 PIC 单片机的位操作汇编指令高效实现。基于此,位变量不能是局部自动型变量,也无法将其组合成复合型高级变量。PICC 对整个数据存储空间实行位编址,0 x000 单元的第 0 位是位地址 0 x0000,以此后推,每个字节有 8 个位地址。编制位地址的意义纯粹是为了编译器最后产生汇编级位操作指令而用,对
20、编程人员来说基本可以不管。但若能了解位变量的位地址编址方式就可以在最后程序调试时方便地查找自己所定义的位变量,如果一个位变量 flag1 被编址为 0 x123,那么实际的存储空间位于:字节地址0 x123/8=0 x24 位偏移 0 x123%8=3 即 flag1 位变量位于地址为 0 x24 字节的第 3 位。在程序调试时如果要观察 flag1 的变化,必须观察地址为 0 x24 的字节而不是 0 x123。PIC 单片机的位操作指令是非常高效的。因此,PICC 在编译原代码时只要有可能,对普通变量的操作也将以最简单的位操作指令来实现。假设一个字节变量 tmp 最后被定位在地址 0 x2
21、0,那么 tmp|=0 x80 =bsf 0 x20,7 tmp&=0 xf7 =bcf 0 x20,3 if(tmp&0 xfe)=btfsc 0 x20,0 即所有只对变量中某一位操作的 C 语句代码将被直接编译成汇编的位操作指令。虽然编程时可以不用太关心,但如果能了解编译器是如何工作的,那将有助于引导我们写出高效简介的 C 语言原程序。在有些应用中需要将一组位变量放在同一个字节中以便需要时一次性地进行读写,这一功能可以通过定义一个位域结构和一个字节变量的联合来实现,例如:张明峰 2004-4-7 于上海 7 of 26 union struct unsigned b0:1;unsigne
22、d b1:1;unsigned b2:1;unsigned b3:1;unsigned b4:1;unsigned b5:1;unsigned :2;/最高两位保留 oneBit;unsigned char allBits;myFlag;例 11-3 定义位变量于同一字节 需要存取其中某一位时可以 myFlag.oneBit.b3=1;/b3 位置 1 一次性将全部位清零时可以 myFlag.allBits=0;/全部位变量清 0 当程序中把非位变量进行强制类型转换成位变量时,要注意编译器只对普通变量的最低位做判别:如果最低位是 0,则转换成位变量 0;如果最低位是 1,则转换成位变量 1。而
23、标准的 ANSI-C 做法是判整个变量值是否为 0。另外,函数可以返回一个位变量,实际上此返回的位变量将存放于单片机的进位位中带出返回。11.5.6 PICC 中的浮点数 PICC 中描述浮点数是以 IEEE-754 标准格式实现的。此标准下定义的浮点数为 32 位长,在单片机中要用 4 个字节存储。为了节约单片机的数据空间和程序空间,PICC 专门提供了一种长度为 24 位的截短型浮点数,它损失了浮点数的一点精度,但浮点运算的效率得以提高。在程序中定义的 float 型标准浮点数的长度固定为 24 位,双精度 double 型浮点数一般也是 24 位长,但可以在程序编译选项中选择 doubl
24、e 型浮点数为 32 位,以提高计算的精度。一般控制系统中关心的是单片机的运行效率,因此在精度能够满足的前提下尽量选择24 位的浮点数运算。11.5.7 PICC 中变量的绝对定位 首先必须强调,在用 C 语言写程序时变量一般由编译器和连接器最后定位,在写程序之时无需知道所定义的变量具体被放在哪个地址(除了 bank 必须声明)。真正需要绝对定位的只是单片机中的那些特殊功能寄存器,而这些寄存器的地址定位在PICC 编译环境所提供的头文件中已经实现,无需用户操心。编程员所要了解的也就是 PICC是如何定义这些特殊功能寄存器和其中的相关控制位的名称。好在 PICC 的定义标准基本上按照芯片的数据手
25、册中的名称描述进行,这样就秉承了变量命名的一贯性。一个变量绝对定位的例子如下:张明峰 2004-4-7 于上海 8 of 26 unsigned char tmpData 0 x20;/tmpData 定位在地址 0 x20 千万注意,PICC 对绝对定位的变量不保留地址空间。换句话说,上面变量 tmpData 的地址是 0 x20,但最后 0 x20 处完全有可能又被分配给了其它变量使用,这样就发生了地址冲突。因此针对变量的绝对定位要特别小心。从笔者的应用经验看,在一般的程序设计中用户自定义的变量实在是没有绝对定位的必要。如果需要,位变量也可以绝对定位。但必须遵循上面介绍的位变量编址的方式。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第十一章 PIC 单片机的 语言编程 第十一 单片机 语言 编程
限制150内