用PICC编译器语言开发PIC系列单片机的代码
PIC编程说明
PIC编程说明在编程过程中由于一个端口可能有多个功能,所以在初始化时应该详细设置所以的端口的功能,当使用一种功能时应该将其他功能关闭,否则端口的功能将不能正常工作。
汇编:C语言:-------picc1、在用C语言编程之前,得确定用户用的是哪个辅助C编译器(因为MPLAB IDE 不提供C编译器,不过在8.33版本有捆绑了PICC的C编译器用户可以直接选用)。
注意设置连接编译器的路径。
2 在程序的最前面用#include 预处理指令引用包含头文件,其中必须包含一个编译器提供的“pic.h”文件(在picc18里为:pic18.h),实现单片机内特殊寄存器和其它特殊符号的声明;3 用“__CONFIG”预处理指令定义芯片的配置位;4 声明本模块内被调用的所有函数的类型,PICC 将对所调用的函数进行严格的类型匹配检查;5 定义全局变量或符号替换;6 实现函数(子程序),特别注意main 函数必须是一个没有返回的死循环。
现提供个C 原程序的范例:#include <pic.h> //包含单片机内部资源预定义#include “pc68.h” //包含自定义头文件//定义芯片工作时的配置位__CONFIG (HS & PROTECT & PWRTEN & BOREN & WDTDIS);//声明本模块中所调用的函数类型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;//函数和子程序void main(void){SetSFR();PORTC = 0x00;TMR1H += TMR1H_CONST;LED1 = LED_OFF;LCD_Test();//程序工作主循环while(1) {asm(“clrwdt”); //清看门狗Clock(); //更新时钟KeyScan(); //扫描键盘Measure(); //数据测量SetSFR(); //刷新特殊功能寄存器}}为了使编译器产生最高效的机器码,PICC 把单片机中数据寄存器的bank 问题交由编程员自己管理,因此在定义用户变量时你必须自己决定这些变量具体放在哪一个bank 中。
PIC C语言编程
下例中,是将整数0X80的低2位置为1。
|)
10000000 00000011 —————— 10000011
(5)按位异或
01111111 ^) 01111000 —————— 00000111
7 条件运算符
条件运算符(?:)能用来代替某些if—then— else形式的语句。 一般形式为: EXP1 ? EXP2 : EXP3
9 增1和减 运算符 和减1运算符 和减
(前缀)++操作数 或 --操作数 (后缀)操作数++ 或 操作数—
x=++n; //n先加1,再赋给x。 结果是n=6,x=6 x=n++; //先把n值赋给x,n值在加1。 结果是n=6,x=5;
10 取地址运算符 取地址运算符“&”和取内容运算符 和取内容运算符“*” 和取内容运算符 “&”运算符用于取出操作数的地址,“*”运算符 是通过指针间接的访问一个值,在指针类型中 应用很多。
PIC单片机C语言编程
2011.3
内容
C语言编译器 C语言编程
C语言编译软件
PICC Microchip公司的第三方公司HITECH公司 编写的C语言编译器。 MAPLAB C18 Microchip公司编写的C语言编译器。
MAPLAB C18
1 建立项目
选择Project>New 来创建一个新项目。然后在所显示的对话框 中输入项目名及其路径,再点击OK。
下图所示的“General”选项卡中输入MPLAB C18 安装目录中 头文件和函数库子目录的路径。可以直接输入路径或点击 Browse 指定路径。MPLAB C18 会在指定的头文件目录下搜 索包含的.h 文件。MPLINK 链接器会在函数库目录下搜索目 标文件和库文件,其中包括在链接描述文件中指定的文件。
PIC单片机的C语言
第3步:在项目名文本框中输入项目名 led,在项目路径文 本框中输入项目路径 D:\led ,也可以通过单击 Browse 按钮 选择项目名的保存路径。
第4步:单击新项目对话框的OK按钮,出现如下所示的项 目树窗口,说明项目已经建立。
⒉选择器件 在开始其他工作之前,应先选择开发过程中所需器件, 其操作过程如下所示。 首先在MPLAB集成开发环境中打开Configure菜单,然 后单击Select Device菜单项,弹出如下所示的器件选择对 话框。此处可以选择PICl6F877A作为开发芯片。
第4步:设置完包含文件路径和库文件路径后,在设置语 言组件的对话框中,单击OK按钮,设置语言组件完成。 至此PICC的项目设置完毕,可以对项目进行编译、调 试和运行了。
三、PICC 基本编程
㈠PICC 中的基本变量类型 PICC 支持的基本变量类型见下表:
㈡PICC 中的高级变量 基于上表的基本变量,除了bit 型位变量外,PICC 完 全支持数组、结构和联合等复合型高级变量,这和标准的 C 语言所支持的高级变量类型没有什么区别。例如: 数组:unsigned int data[10]; 结构体:struct commInData { unsigned char inBuff[8]; unsigned char getPtr, putPtr; }; 联合体:union int_Byte { unsigned char c[2]; unsigned int i; };
PICCV8.05PL1编译器在安装完成后应在激活后使用, 如果不激活只能作为DEMO版使用,DEMO版使用有时间 限制。PICCV8.05PL1编译器的激活方法是:单击PICC编 译器开始菜单中的Compiler Activation项,可出现如下所示 的编译器激活窗口。
PIC单片机的C语言使用(一)
PIC单片机的C语言使用(一)在MPLAB-IDE 中使用HitechC 编译器一、装入编译器:1、启动MPLAB-IDE,如下图所示选择Project-》Install Language Toolscreen.width-300)this.width=screen.width-300” border=0>2、在弹出的安装语言工具对话框里“Language Suite”选项现在显示的是Microchip,点击后面的箭头来选择语言。
screen.width-300) this.width=screen.width-300” border=0>我使用的工具是HI-TECH PICCME,所以选择为“HI-TECH PICC”。
3、接下来在“Tool Name”里选择编译器组件的调用路径,这里有“PICC Compiler”(C 编译器)、“PICC Assembler”(汇编器)和“PICC Linker”(链接器)3 项都需要设置。
screen.width-300)this.width=screen.width-300” border=0>用“Browse”来选择调用路径,把上述3 项组件的调用文件都设为PICC.EXE。
点“OK”后完成设置。
screen.width-300)this.width=screen.width-300” border=0>二、选用编译器:1、新建一个项目,编辑项目对话框的“Language Tool Suite”栏目默认是“Microchip”,将它改为“HI-TECH PICC”。
screen.width-300)this.width=screen.width-300” border=0>2、在项目文件框里点“flasha[.hex]”,这时“Node Properties”(节点属性)按钮将会亮起来。
点击进入。
screen.width-300)this.width=screen.width-300”border=0>3、设置节点属性。
PIC单片机C语言教程
PIC单片机C语言教程PIC单片机(Peripheral Interface Controller)是德州仪器(Texas Instruments)公司生产的一款微控制器芯片。
它具有高性能、低功耗、易编程等特点,因此被广泛应用于各种电子设备中。
PIC单片机的编程语言主要是C语言。
C语言是一种广泛使用的高级程序设计语言,它结构简洁、表达能力强、可移植性好。
通过使用C语言,我们可以轻松地编写控制PIC单片机的程序,并且可以充分发挥PIC单片机的特性和功能。
在PIC单片机的C语言教程中,首先需要了解C语言的基础知识,包括变量、数据类型、运算符、控制语句等。
接下来,我们需要学习如何使用C语言编写PIC单片机的程序。
1.引脚配置:在PIC单片机的程序中,我们需要配置引脚的状态,包括输入输出模式、电平状态等。
通过使用C语言,我们可以方便地配置引脚,实现与外部器件的连接和通信。
2.中断编程:中断是PIC单片机的重要特性之一,可以使控制器在特定条件下停止当前任务执行,转而执行中断服务程序。
通过使用C语言,我们可以编写中断服务程序,实现特定条件下的任务切换和响应。
3.定时器编程:定时器是PIC单片机的另一个重要功能,可以实现一定时间间隔内的定时操作。
通过使用C语言,我们可以编程设置定时器的参数,以实现特定的定时操作。
4.串口通信:PIC单片机具有串口通信功能,可以与其他设备进行数据交换。
通过使用C语言,我们可以编写串口通信的程序,实现与其他设备的数据传输和交互。
5.外设控制:PIC单片机可以连接各种外设,如LCD显示屏、键盘、驱动器等。
通过使用C语言,我们可以编写控制程序,实现与外设的连接和控制。
以上只是PIC单片机C语言教程的一部分内容。
除了上述内容,我们还可以学习其他更高级的主题,如编码技巧、优化技术等。
通过系统学习和实践,我们可以掌握PIC单片机的C语言编程技巧,实现各种功能和应用。
总的来说,PIC单片机的C语言教程是一个庞大而丰富的话题,需要通过实践和深入学习来掌握。
PIC单片机之汇编语言
PIC指令介绍2006-12-24 03:03:05来源:嵌入式技术网关键字: PIC指令系统<a target='_blank' href='/www/delivery/ck.php?n=826cd67'><img border='0' alt='' src='/www/delivery/avw.php?zoneid=212&n=826cd67' /></a>工作以来一直使用ST的单片机,其他的单片机虽大致了解但从未认真看过,近几日恰好无事,决定熟悉一下PIC的单片机,于是想将自己从网上或这书本上的东西转下来,予以同一样的初学者共同参考。
PIC的指令系统PIC 8位单片机共有三个级别,有相对应的指令集。
基本级PIC 系列芯片共有指令33条,每条指令是12位字长;中级PIC系列芯片共有指令35条,每条指令是14位字长;高级PIC系列芯片共有指令58条,每条指令是16位字长。
其指令向下兼容。
一、PIC汇编语言指令格式PIC系列微控制器汇编语言指令与MCS-51系列单片机汇编语言一样,每条汇编语言指令由4个部分组成,其书写格式如下:标号操作码助记符操作数1,操作数2;注释指令格式说明如下:指令的4个部分之间由空格作隔离符,空格可以是1格或多格,以保证交叉汇编时,PC机能识别指令。
1 标号与MCS-51系列单片机功能相同,标号代表指令的符号地址。
在程序汇编时,已赋以指令存储器地址的具体数值。
汇编语言中采用符号地址(即标号)是便于查看、修改,尤其是便于指令转移地址的表示。
标号是指令格式中的可选项,只有在被其它语句引用时才需派上标号。
在无标号的情况下,指令助记符前面必须保留一个或一个以上的空格再写指令助记符。
指令助记符不能占用标号的位置,否则该助记符会被汇编程序作标号误处理。
书写标号时,规定第一字符必须是字母或半角下划线“—”,它后面可以跟英文和数字字符、冒号(:)制符表等,并可任意组合。
PIC单片机的C语言
㈣ volatile 修饰词 PICC 中还有一个特殊的变量修饰词“volatile”,用来 说明一个变量的值是会随机变化的,即使程序没有刻意对 它进行任何赋值操作。 在单片机中,作为输入的IO 端口其内容将是随意变 化的;很多特殊功能寄存器的值也将随着指令的运行而动 态改变。所有这种类型的变量必须将它们明确定义成 “volatile”类型,例如: volatile unsigned char STATUS @ 0x03; volatile bit commFlag;
Hitech-PICC 编译器基本上符合ANSI C标准,但是不 支持函数的递归调用。其主要原因是因为PIC 单片机特殊 的堆栈结构。PIC 单片机的堆栈是硬件实现的,其深度已 随芯片固定,无法实现需要大量堆栈操作的递归算法。
二、PICC C编译器的安装 PICC C编译器可以运行在Windows操作系统上,可 以在MPLAB IDE集成开发环境下进行项目开发。 下面介绍在MPLAB IDE 7.00集成环境下安装和设置 PICCV8.05 PL1 PICC编译器,以及在此环境下编译和调 试源程序的基本方法。
第3步:单击对话框中的Browse按钮,弹出如下图所示的 打开文件对话框。在缺省PICC V8.05PL1编译器安装目录 C:\HT-PIC\bin\下,选择plcc.exe作为编译程序。然后单击 “打开”按钮,可以发现PICC Compiler项已选择picc.exe 作为编译程序。
同样,PICC Assembler和PICC Linker都选择picc.exe 作为汇编和链接程序,如下图所示。
㈤标准库函数 PICC 提供了较完整的C 标准库函数支持,其中包括 数学运算函数和字符串操作函数。在程序中使用这些现成 的库函数时需要注意的是入口参数必须在bank0 中。 如果需要用到数学函数,则用 “#include <math.h>” 包含头文件;如果要使用字符串操作函数,就需要包含 “#include <string.h>”头文件。在这些头文件中提供了函 数类型的声明。直接查看这些头文件就可以知道PICC 提 供了哪些标准库函数。 C 语言中的格式化输出函数“printf/sprintf”用在单片 机的程序中时要特别谨慎。printf/sprintf 是一个非常大的 函数,一旦使用,你的程序代码长度就会增加很多。
PICC使用说明(包括编程实例)
PIC的C语言使用(一)在MPLAB-IDE中使用HitechC编译器一、装入编译器:1、启动MPLAB-IDE,如下图所示选择Project-》Install LanguageTool2、在弹出的安装语言工具对话框里“Language Suite”选项现在显示的是Microchip,点击后面的箭头来选择语言。
我使用的工具是HI-TECH PICCME,所以选择为“HI-TECH PICC”。
3、接下来在“Tool Name”里选择编译器组件的调用路径,这里有“PICC Compiler”(C编译器)、“PICC Assembler”(汇编器)和“PICC Linker”(链接器)3项都需要设置。
用“Browse”来选择调用路径,把上述3项组件的调用文件都设为PICC.EXE。
点“OK”后完成设置。
二、选用编译器:1、新建一个项目,编辑项目对话框的“Language Tool Suite”栏目默认是“Microchip”,它改为“HI-TECH PICC”。
2、在项目文件框里点“flasha[.hex]”,这时“Node Properties”(节点属性)按钮将会亮起来。
点击进入。
3、设置节点属性。
由于FLASHA.C还有其他相关连的源程序需要加进来,所以在“Language Tool”栏里应该择“PICC Linker”(链接器)。
通常我们可以选择:1)Generate debug info:显示debug信息;2)Create map file:选择该项后我们将看到ROM、RAM的使用情况;3)Error file:显示错误信息;4)Compile for MPLAB ICD:如果不使用ICD,就不必选择这个项目了。
4、设置完成之后点“Add Node”来添加节点。
这个项目有两个节点:fla.c和flasha.c,选择节点后点击“Node Properties”或直接双节点来进入节点属性设置。
PIC单片机的C语言使用(一)——在MPLAB-IDE中使用HitechC编译器
一、装入编译器:1、启动MPLAB-IDE,如下图所示选择Project-》Install Language2、在弹出的安装语言工具对话框里“Language Suite”选项现在显示的是Microchip,点击后面的箭头来选择语言。
我使用的工具是HI-TECH PICCME,所以选择为“HI-TECH PICC”。
3、接下来在“Tool Name”里选择编译器组件的调用路径,这里有“PICC Compiler”(C编译器)、“PICC Assemble Linker”(链接器)3项都需要设置。
用“Browse”来选择调用路径,把上述3项组件的调用文件都设为PICC.EXE。
点“OK”后完成设置。
二、选用编译器:1、新建一个项目,编辑项目对话框的“Language Tool Suite”栏目默认是“Microchip”,将它改为“HI-TECHPICC”。
2、在项目文件框里点“flasha[.hex]”,这时“Node Properties”(节点属性)按钮将会亮起来。
点击进入。
3、设置节点属性。
由于FLASHA.C还有其他相关连的源程序需要加进来,所以在“Language Tool”栏里应该选择“PICC Linker”(链接器)。
通常我们可以选择:1)Generate debug info:显示debug信息;2)Create map file:选择该项后我们将看到ROM、RAM的使用情况;3)Error file:显示错误信息;4)Compile for MPLAB ICD:如果不使用ICD,就不必选择这个项目了。
4、设置完成之后点“Add Node”来添加节点。
这个项目有两个节点:fla.c和flasha.c,选择节点后点击“Node Properties”或直接双击节点来进入节点属性设置。
5、节点文件的工具这时应该选择为“PICC Compiler”(C编译器),蓝色圈子里的4项依次是:1)显示debug 信息;2)局部优化;3)全局优化;4)ICD编译配件。
单片机编程之汇编语言基础-PIC单片机汇编指令
单片机编程之汇编语言基础-PIC单片机汇编指令1、程序的基本格式先介绍二条伪指令:EQU 标号赋值伪指令ORG 地址定义伪指令PIC16C5X在RESET后指令计算器PC被置为全1,所以PIC16C5X几种型号芯片的复位地址为:PIC16C54/55:1FFHPIC16C56:3FFHPIC16C57/58:7FFH一般来说,PIC的源程序并没有要求统一的格式,大家可以根据自己的风格来编写。
但这里我们推荐一种清晰明了的格式供参考。
TITLE This is ;程序标题;--------------------------------------;名称定义和变量定义;--------------------------------------F0 EQU 0RTCC EQU 1PC EQU 2STATUS EQU 3FSR EQU 4RA EQU 5RB EQU 6RC EQU 7┋PIC16C54 EQU 1FFH ;芯片复位地址PIC16C56 EQU 3FFHPIC16C57 EQU 7FFH;-----------------------------------------ORG PIC16C54 GOTO MAIN ;在复位地址处转入主程序ORG 0 ;在0000H开始存放程序;-----------------------------------------;子程序区;-----------------------------------------DELAY MOVLW 255┋RETLW 0;------------------------------------------;主程序区;------------------------------------------MAINMOVLW B00000000TRIS RB ;RB已由伪指令定义为6,即B口┋LOOPBSF RB,7 CALL DELAYBCF RB,7 CALL DELAY┋GOTO LOOP;-------------------------------------------END ;程序结束注:MAIN标号一定要处在0页面内。
Hi-Tech PIC-C语言编程
11.3
MPLAB-IDE 内挂接 PICC
PICC 编译器可以直接挂接在 MPLAB-IDE 集成开发平台下,实现一体化的编译连接和 原代码调试。使用 MPLAB-IDE 内的调试工具 ICE2000、ICD2 和软件模拟器都可以实现原 代码级的程序调试,非常方便。
首先必须在你的计算机中安装 PICC 编译器,无论是完全版还是学习版都可以和 MPLAB-IDE 挂接。安装成功后可以进入 IDE,选择菜单项 Project Æ Set Language Tool Locations…,打开语言工具挂接设置对话框,如图 11-1 所示:
但在单片机上用 C 语言写程序和在 PC 机上写程序绝对不能简单等同。现在的 PC 机资 源十分丰富,运算能力强大,因此程序员在写 PC 机的应用程序时几乎不用关心编译后的可 执行代码在运行过程中需要占用多少系统资源,也基本不用担心运行效率有多高。写单片机 的 C 程序最关键的一点是单片机内的资源非常有限,控制的实时性要求又很高,因此,如 果没有对单片机体系结构和硬件资源作详尽的了解,以笔者的愚见认为是无法写出高质量实 用的 C 语言程序。这就是为什么前面所有章节中的的示范代码全部用基础的汇编指令实现 的原因,希望籍此能使读者对 PIC 单片机的指令体系和硬件资源有深入了解,在这基础之 上再来讨论 C 语言编程,就有水到渠成的感觉。
中的堆栈是硬件实现的,其深度已随芯片而固定,无法实现需要大量堆栈操作的递归算法; 另外在 PIC 单片机中实现软件堆栈的效率也不是很高,为此,PICC 编译器采用一种叫做“静 态覆盖”的技术以实现对 C 语言函数中的局部变量分配固定的地址空间。经这样处理后产 生出的机器代码效率很高,按笔者实际使用的体会,当代码量超过 4K 字后,C 语言编译出 的代码长度和全部用汇编代码实现时的差别已经不是很大(<10%),当然前提是在整个 C 代码编写过程中须时时处处注意所编写语句的效率,而如果没有对 PIC 单片机的内核结构、 各功能模块及其汇编指令深入了解,要做到这点是很难的。
PIC单片机C语言编程教程
PIC单片机C语言编程简介用 C 语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、代码的重复利用率高、便于跨平台的代码移植等等,因此 C 语言编程在单片机系统设计中已得到越来越广泛的运用。
针对PIC 单片机的软件开发,同样可以用C 语言实现。
但在单片机上用C 语言写程序和在PC 机上写程序绝对不能简单等同。
现在的PC 机资源十分丰富,运算能力强大,因此程序员在写PC 机的应用程序时几乎不用关心编译后的可执行代码在运行过程中需要占用多少系统资源,也基本不用担心运行效率有多高。
写单片机的 C 程序最关键的一点是单片机内的资源非常有限,控制的实时性要求又很高,因此,如果没有对单片机体系结构和硬件资源作详尽的了解,以笔者的愚见认为是无法写出高质量实用的C 语言程序。
这就是为什么前面所有章节中的的示范代码全部用基础的汇编指令实现的原因,希望籍此能使读者对PIC 单片机的指令体系和硬件资源有深入了解,在这基础之上再来讨论C 语言编程,就有水到渠成的感觉。
本书围绕中档系列PIC 单片机来展开讨论,Microchip 公司自己没有针对中低档系列PIC单片机的C 语言编译器,但很多专业的第三方公司有众多支持PIC 单片机的 C 语言编译器提供,常见的有Hitech、CCS、IAR、Bytecraft 等公司。
其中笔者最常用的是Hitech 公司的PICC 编译器,它稳定可靠,编译生成的代码效率高,在用PIC 单片机进行系统设计和开发的工程师群体中得到广泛认可。
其正式完全版软件需要购置,但在其网站上有限时的试用版供用户评估。
另外,Hitech 公司针对广大PIC 的业余爱好者和初学者还提供了完全免费的学习版PICC-Lite 编译器套件,它的使用方式和完全版相同,只是支持的PIC 单片机型号限制在PIC16F84、PIC16F877 和PIC16F628 等几款。
这几款Flash 型的单片机因其所具备的丰富的片上资源而最适用于单片机学习入门,因此笔者建议感兴趣的读者可从PICC-Lite 入手掌握PIC 单片机的 C 语言编程。
PIC系列C语言编程实例
option #endasm } void csxsdata(unsigned int dat,unsigned char deg) //74H595操作/dat数据 /degree输出位数 { for(;deg>0;deg--) { asm("clrwdt"); //看门狗 sck = 0; //输入数据时钟 lck = 0; //移位时钟 asm("nop"); dat = dat >> 1; sdi = CARRY; asm("nop"); asm("nop"); asm("nop"); asm("nop"); lck = 1; //输入数据时钟 asm("nop"); asm("nop"); asm("nop"); asm("nop"); lck = 0; //输入数据时钟 asm("nop"); asm("nop"); asm("nop"); asm("nop"); sck = 1; //移位时钟 asm("nop"); asm("nop"); asm("nop"); asm("nop"); sck = 0; //移位时钟 } } //延时子函数(delaytime为秒数据变量)//主频455K. void mdelay(unsigned char ysdata) { unsigned char j; for(;ysdata>0;ysdata--) { for(j=0;j<10;j++) //2ms { asm("clrwdt"); //看门狗 //CLRWDT(); //看门狗 } } } void tmrsz() //定时器 { if(TMR0>160) //176=0.4s {
page 4
led1=1; led2=1; led3=0; crpaxs(); //出入平安显示 mdelay(150); //15*20ms=0.3s } //3 // intdat=0xfefe; for(degree=1;degree<17;degree++) { asm("clrwdt"); //看门狗 crpaxs(); //出入平安显示 led1=1; //消影 led2=1; led3=1; csxsdata(0xffff,16); csxsdata(0xfefe,degree); //显示 led1=0; led2=0; led3=0; mdelay(150); //15*20ms=0.3s } //4 intdat=0x0000; for(degree=1;degree<17;degree++) { asm("clrwdt"); //看门狗 cled3=1; csxsdata(0xffff,16); csxsdata(intdat,degree); //显示 led1=0; led2=0; led3=0; mdelay(150); //15*20ms=0.3s intdat=intdat >> 1; } for(degree=15;degree>0;degree--) { asm("clrwdt"); //看门狗 crpaxs(); //出入平安显示 CARRY=1; intdat=intdat << 1; led1=1; //消影 led2=1; led3=1; csxsdata(0xffff,16); csxsdata(intdat,degree); //显示 led1=0; led2=0;
《PIC系列单片机C程序设计方案...
《PIC系列单片机C程序设计方案...学习之6---看门狗定时器(WDT)//PIC.H中定义了宏#define CLRWDT() asm("clrwdt")因此在PICC的c语言中可以直接使用CLRWDT()对WDT清0//若单片机WDT使能,在适当位置加入CLRWDT(),程序进入正常运行时,每隔一定时间均会执行CLRWDT()语句对WDT清0,芯片不会复位//如果程序陷入死循环,不会执行到CLRWDT()语句,则超出所设定的时间后,WDT溢出使芯片复位,从头(000H)开始执行,单片机恢复正常运行//PIC16F单片机,看门狗定时器的启用只能在芯片的烧写时确定,即无法用软件来开启或关闭WDT,但在PIC16f88X中可以。
//PIC16单片机的WDT基本溢出时间为18MS,由RC充放电时间确定,在-40~85度之间变化时,WDT基本溢出时间在7-33ms变化#include__CONFIG(0X3F3D)。
//开启WTDvoid DELAY(unsigned int)。
#define LED1 RB1main(void){TRISB=0B11111101。
OPTION=0B11111011。
//WDT的分频比为1:8,最大复位时间为18*8=144ms if(TO==0)// 若写成T0,则编译出错。
{LED1=1。
//看门狗定时器溢出,仿真时溢出TO不会清零 }elseLED1=0。
while(1){DELAY(100)。
//模拟一个运行100ms的子程序CLRWDT()。
DELAY(200)。
//模拟一个运行200ms的子程序,此时会产生溢出(200ms>144ms)CLRWDT()。
}。
}void DELAY(unsigned int n) {unsigned int j。
char k。
for(j=0。
j0。
k--) NOP()。
}学习之7--EEPROM的读写EEPROM特点:掉电时保持不变,F877A的EEPROM参数是保证1 000 000次擦除,数据保存>40年PICC中定义了读/写EEPROM的宏EERPOM_WRITE(addr,value)。
基于PICC 编译环境编写PIC单片机程序
基于PICC 编译环境编写PIC 单片机程序目前,Microchip 公司生产的PIC 系列单片机以其低成本、低功耗、高性能、开发速度快且一次性用户可编程等优点迅速占领了国内市场,成为国内销售量最大的单片机,但国内介绍他的C 语言开发工具的书籍和文章却比较少,而且用的人也不多,在用其开发的过程中给广大程序员带来了许多困难和不便。
Microchip 公司自己没有针对中低档系列PIC 单片机的C 语言编译器,但很多专业的第三方公司有众多支持PIC 单片机的C 语言编译器提供,常见的有Hitech,CCS,IAR,Bytecraft 等公司。
Hitech 公司的PICC 编译器稳定可靠,编译生成的代码效率高,在用PIC 单片机进行系统设计和开发的工程师群体中得到广泛认可。
因此,本文主要以Hi-Tech PICC 为基础,介绍PIC 的C 语言的基本特点。
1HiTech PICC 和ANSI C 的异同及HiTech PICC 语言的特点除了PICC 不支持函数的递归调用外,PICC 基本上符合ANSI 标准,其主要原因是因为PIC 单片机特殊的堆栈结构。
PIC 单片机中的堆栈是硬件实现的,其深度已随芯片而固定,无法实现需要大量堆栈操作的递归算法;另外在PIC 单片机中实现软件堆栈的效率也不是很高,为此,PICC 编译器采用一种“静态覆盖”技术以实现对C 语言函数中的局部变量分配固定的地址空间。
经这样处理后产生出的机器代码效率很高,当代码量超过4 kB 后,C 语言编译出的代码长度和全部用汇编代码实现时的差别已经不是很大(2PICC 中的变量PICC 中的变量类型和标准C 一样,这里不再重复。
为了使编译器产生最高效的机器码,PICC 把单片机中数据寄存器的bank 问题交由编程员自己管理,因此在定义用户变量时必须自己决定这些变量具体放在哪一个bank 中。
如果。
用PICC编译器开发PIC系列单片机的代码
SIGNAT _rotate_left,4201
_ rotate_left
movwf ?a_rotate_left
rlf? a_rotate_left,w
return
FNSIZE _rotate_left,1,0
GLOBAL ?a_rotate_left
END
需要注意的是,在 C 模块中声明的函数名称,在汇
数之外说明的、 可被任意模块使用的、 在整个程序执行
期间都保持有效的变量。 局部变量在函数内部说明。 局
部变量有两种:自动变量和静态变量。 缺省类型为自动
变量, 除非明确将其声明为静态变量。 而且, 所有的自
动变量都被分配在寄存器页 0 ,所以 b a n k 限定词不能用
于自动变量,但可以用于静态的局部变量。当程序退出
形式参数,并返回一个char 型的值。而rotate_left()函数
的真正函数体在外部可以被 A S P I C 编译的汇编模块( 文
件名后缀. a s ) 中,具体代码可以如下编写:
processor16C84
PSECT text0,class=CODE,local,delta=2
GLOBAL _rotate_left
时,自动变量占用的空间释放, 自动变量也就失去意
义。 静态变量是一种局部变量, 只在声明它的函数内部
有效;但它占用固定的存储单元, 而这个存储单元不会
被别的函数使用, 因此其它函数可以通过指针访问或修
改静态变量的值。静态变量在程序开始只初始化一次,
因此若只在某函数内部使用一变量,而又希望其值在 2
次函数调用期间保持不变, 为实现程序模块化, 则可将
5 结 论
P I C C 编译器产生的代码在有些时候虽然比较繁琐,
PIC16F1938单片机编程样例
PIC 单片机编程样例MCU:PIC16F1938;开发语言:C 语言 开发工具:编译环境:MPLAB IEDC 编译器:HI-TECH PICC C compiler 编辑软件:source in sight 烧录工具:MPLAB ICD2 仿真软件:Protues说明:程序已经通过编译并在仿真软件和硬件平台上成功跑起来;目的:对用到PIC16F 系列单片机开发软件的群众提供样例支持,希望有帮助。
Protues 仿真图:片 H4I --C2 i UF: - ."IO S O I TI CKI 2临丽 r^rrckiNi ADZ 占芒湖FC :£|]兀讯口 EF UM OTTO® 铐3由厲气I ||啊21 bF 讥 BA 启凶« 耳匚I OUL'CP a&nU 匸-T LG 耳111匚匚肥戈EM ve 甸+•殳 uu r/vi 1.4*-hi. iH 仝心 ^LJ !I=wn3sari: LKOL TIVUF 0;IIYUIT 町T £rCF 丈「L DlK bi4IT4ri*%JKI FJBI^I 皿 口1 陆1庐StRI PSiJP liiULLW RB?rfWT[lilN2 XF iKLPaTO^UCCB=:B+l/UF Mi'F 1 DJCXC N 脅阳il tfli'FS IGXO.I■^asic^CLtncrcij -jGa-4 |RIT<1 C IFDHiN E IDfllKH^IF ■ rnw SUM 匸 Vii inc孔 l/TIQWI 宙 MRL±i*C .九* .叭玉)• RW5Cl.rsCJ¥Trqr5ESll F cfli^nycicrc [:沖』刊 举EBB 材Ml 注“乱肘也=3UNLI•-C F ■-£仙CCi^PIM TE吐1>迥I '1、一些定义typedef void typedef bit VOID; BIT;typedef un sig ned char UINT8; typedef int INT16;typedef un sig ned int UINT16; typedef long INT32;typedef un sig ned long UINT32;VOID delay( VOID ){int i = 100;while( i--);}2、EEPRO读写/******************************************************************************功能:从EEPRO中读取一个字节的数据原型: UINT8 EEPROM_read( UINT8 addr )参数说明:输入参数:addr输入地址输出参数:无返回:读取的字节注意:******************************************************************************/UINT8 EEPROM_read( UINT8 addr ){UINT8 EE_data;EEADRL = addr;EEPGD = 0;CFGS = 0;GIE = 0; // 禁止所有中断RD = 1;asm( "n op");EE_data = EEDATL;RD = 0;GIE = 1; // 恢复所有中断return EE_data;},**************************************************************************** 功能:向EEPRO中写入一个字节的数据原型:VOID EEPROM_write( UINT8 addr, UINT8 ee_data ) 参数说明:输入参数:addr输入地址,ee_data需要写入的数据输出参数:无返回:无注意:****************************************************************************VOID EEPROM_write( UINT8 addr, UINT8 ee_data ){EEADRL = addr;EEDATL = ee_data;EEPGD = 0;CFGS = 0 JGIE = 0; // 禁止所有中断WREN = 1 ; // 运行执行编程/擦除操作EECON2: =0x55; // 必须按这样的时序EECON2: =0xAA;WR = 1;while( WR==1 ); // 等待写操作完成GIE = 1;WREN = C );// 禁止执行编程/擦除操作3、ADC模块/** ADC模块的初始化*/static VOID ADC_init( VOID ){ADCON0 = 0b00110001; // 选择AN12 通道、ADC使能位ADCON1 = 0b11100000; //AD 转换结果右对齐,64分频作为转换时钟,选择VSS VDD乍为参考电压ADIF = 0; // 清楚AD转换标志}static UINT16 throttle = 0;static VOID AD_Fu nctio n( VOID ){UINT8 i;UINT16 AD_result;UINT16 AD_max = 0;UINT16 AD_min = 2000;throttle = 0;for( i=0; i<AD_NUM; i++ ) {ADIF = 0;ADRESH = 0;ADRESL = 0;delay();ADCON0 |= 0x02;while( 0 == ADIF ); //等待转换完成ADIF = 0;AD_result = ADRESH;AD_result = AD_result << 8;AD_result = AD_result | ADRESL;throttle += AD_result;AD_max = AD_max > AD_result ? AD_max : AD_result;AD_min = AD_min < AD_result ? AD_min : AD_result;去掉最大值和最小throttle = (throttle - AD_max - AD_mi n) / (AD_NUM - 2); //值,均值滤波}4、定时器0/**定时器0初始化*/static VOID Timer0_i nit(VOID){OPTION_REG = 0b10000100; //禁止所有弱上拉、部指令周期时钟32分频TMR0 = TIMER0_1MS; // 定时器0的中断间隔为1msTMR0IE = 1; // 定时器0开中断//总的中断开关记得在所有模块初始化完成后打开 static UINT8 timecou nt = 0;static BIT timelOmsflg; static BIT timelmsflg;VOID interrupt ISR(VOID) {uart_ha ndler(); ///**定时器0的处理*/ if( 1 == TMR0IF ) TMR0 = TIMER0_1MS; // 重新赋值timeco un t++; if( timeco unt >= 10 ) {timeco unt = 0; time10msflg = 1;} timelmsflg = 1;//根据实际情况添加自己的代码 }5、IO 初始化/** IO 初始化*/static VOID IO_i nit(VOID) {/** PORT A */ ANSELA = 0x00; // TRISA = 0x00; // PORTA = 0x00;///** PORT B */ ANSELB = 0x03; 〃RB0和RB1都绑定为同一模拟 AD 输入串口通讯接收{TMR0IF = 0; // 清零标志位所有IO 为数字IO 所有IO 为output初始化所有IO 输出电平为低电平CCP1CON &= 0b11001111;} /******************************************************************************功 能:PWM 占空比设置原型:VOID PWM_WidthSet( UINT8 width )参数说明:输入参数:width 占空比的百分比分子,设置值从 0至100,例如width = 50 时,设置的占空比为50%输出参数:无 返 回:无 注意:******************************************************************************/ static VOID PWM_WidthSet( UINT8 width ) {UINT16 PWM_width; UINT16 tmp;TRISB = 0X03; 〃RB0 PORTB = 0x00;和RB1为输入,其他端口为输出/** POTR C */ PORTC =0xff; LATC = 0xff; TRISC =0xC4;//TX和RX 引脚都要设置为1,禁止CCP1引脚输出驱动器6、PWM 模块/** PWM 模块的初始化*/ static VOID PWMCCP 」nit(VOID) {CCP1CON = 0b00001100; // 单输出,PWM 模式CCPTMRS0 &= 0b11111100; //CCP1 选择 Timer2 作为定时器PR2 = 249; //PWM周期计算:(PR2 + 1)*0.0625*4(16Mhz 晶振四分频,即指令周期广预分频值, 当 PR2为249时,PWM 频率为16KT2CON = 0x00; //预分频为1:1 ; TMR2ON = 1; //使能定时器Timer2TRISC2 = 0; //打开CCP1引脚输出驱动器CCPR1L = 0x00; //PWM 占空比为0100PWM_width = width * 10;if( 100 == width ) {//经过Protues 仿真,100时至少比1000大于4才可以达到完全的 PWM_width += 4;}/** 高八位赋值*/ CCPR1L = PWM_width >> 2 ;/**低两位赋值*/ tmp = PWM_width & 0x0003; tmp = tmp << 4; CCP1CON &= 0b11001111; CCP1CON |= tmp;}7、串口通讯模块void uart_ in it(void) {UINT8 ii;for(ii=0;ii<_SUB_NUM_;ii++)get_uart_sub[ii]=0xff;RCSTA = 0xb0; TXSTA = 0x20;//TXSTA = 0x20; BAUDCONbits.BRG16=0;SPBRG = _FOSC_/64/_BAUD_-1;//23;TXIE = 0; // 发送不需要中断处理 RCIE = 1; PEIE = 1; //没有开全局中断//发送数据static VOID UART_se nt( UINT8 byte ) {SPBRGH = 0; //8 位定时器 Baud Rate Generator//add by lihf for test〃while( 0 == TXIF )//con ti nue;TXREG = byte;while( 0 == TRMT ){asm( "n op");}}//接收在中断里面调用uart_handler() 函数#defi ne _SUB_NUM_ 50UINT8 get_uart_sub[_SUB_NUM_];void uart_ha ndler(void){UINT8 i;if( 1 == RCIF ){RCIF = 0;for(i=0;i<_SUB_NUM_-1;i++)get_uart_sub[i]=get_uart_sub[i+1];get_uart_sub[_SUB_NUM_-1] = RCREG;}}Protues中如何仿真串口通讯,网上很多资料,找一份参考一下。
电气自动化技术专业《基于PICC编译环境编写PIC单片机程序》
基于2008-01-27a"clrwdt";这是在C原程序中直接嵌入汇编指令的最直接最容易的方法。
2 如果需要编写一段连续的汇编指令,〞开始汇编指令段,用“#endasm〞结束。
例如:汇编指令寻址C语言定义的全局变量所有C中定义的符号在编译后将自动在前面添加一下划线符“_〞,因此,假设要在汇编指令中寻址 C 语言定义的各类变量,一定要在变量前加上“_〞符号,例如上例中的count是在C中定义的无符号全局变量,在汇编语言中只需在其前面加上“_〞符号就可对他进行访问了。
另外,对于C中定义的多字节全局变量,例如在C中有如下定义:那么在汇编里访问他时就得分字节访问,例如:汇编指令寻址C函数的局部变量前面已经提到,PICC 对自动型局部变量〔包括函数调用时的入口参数〕采用一种“静态覆盖〞技术对每一个变量确定一个固定地址〔位于ban0〕,因此嵌入的汇编指令对其寻址时只需采用数据存放器的直接寻址方式即可, 所以关键是要知道这些局部变量的寻址符号。
建议读者先编写一小段C代码,其中有最简单的局部变量操作指令,把此C源代码编译成对应的PICC 汇编指令;查看C编译器生成的汇编指令是如何寻址这些局部变量的,自己编写的行内汇编指令就采用同样的寻址方式。
相比于汇编语言,用C语言编程的优势是毋庸置疑的:开发效率大大提高、人性化的语句指令加上模块化的程序易于日常管理和维护、程序在不同平台间的移植方便。
所以既然用了C语言编程,就尽量防止使用嵌入汇编指令或整个地编写汇编指令模块文件。
例如:变量的循环右移操作用C语言实现非常不方便,PIC 单片机已有对应的移位操作汇编指令,因此用嵌入汇编的形式实现效率最高。
同时对移位次数的控制,实质上说变量count1 的递减判零也可以直接用汇编指令实现,这样可节约代码,但用标准的C语言描述更直观,更易于维护。
6 考前须知1〕既然所有的局部变量将占用ban0 的存储空间,因此用户自己定位在ban0 内的变量字节数将受到一定的限制,在实际使用时需注意。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用PICC编译器语言开发PIC系列单片机的代码介绍了PIC系列单片机C语言的发展,并以HI-TECH Software公司的HI-TECH PICC 为例。
介绍了PICC编译器的特点和用其开发PIC系列单片机时的应注意的一些问题。
一.前言目前在市场上应用最广泛的应该属于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语言的基本特点。
二.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 var3; //合法声明unsigned char var4 = 0x02; //合法声明,每次调用都初始化static unsigned char bank1 var5 = 0x02; //合法声明,但只初始化一次…………}PICC编译器对局部变量及传递参数使用RAM覆盖技术,编译时,连接器会自动把一些不可能被同时调用的函数的自动变量区重叠在一起,以达到内存的高效利用,因此其内部RAM的利用效率非常高。
1、位变量的使用需要说明的是:虽然PICC允许利用bit定义位变量,比如:static bit init_flag;但位变量不能定义为自变量,也能不能作为函数参数,但可以作为函数的返回值。
而且位变量也不能被静态初始化。
比如若只想在某一个函数中使用位变量flag,用如下两种方法都是错误的:void max(void){bit flag; //非法,位变量不能定义为局部自变量…………}void max(void){static bit flag = 1; //非法,位变量不能被静态初始化…………}PICC 支持在结构中定义位成员,位成员按最低有效位在前的方式存储,位成员总是以8bit为单位进行分配,当当前字节分配满后再分配下一个字节,但位成员不会跨字节存放.,例如定义:struct {unsigned lo: 1;unsigned mid: 1;unsigned hi: 7;} flag @ 0x60;结构flag占用两个单元0x60和0x61, lo分配到0x60单元的第0位, mid分配到0x60单元的第1位, 由于位成员不会跨字节存放,故hi分配到0x61单元的0-6位(第6位为最高有效位),而0x60单元的2-7位则跳过。
当然,上述的结构定义也可不使用绝对地址定义:struct {unsigned lo: 1;unsigned mid: 1;unsigned hi: 7;} flag;另外,不使用的位可用未命名的位成员来定义, 如果我们不使用mid, 就可定义为: struct {unsigned lo: 1;unsigned : 1;unsigned hi: 7;}flag;如果将一个整型数赋给位变量,只是将最低位赋给位变量,如果你是想要将一个整型变量是否为0赋值给一个位变量,必须用:bitvar = (char_var != 0);而不能象有些编译器那样可以用:bitvar = char_var;也不能用类型强制转换:bitvar = (bit)char_var;2、绝对地址变量的定义在某些特殊情况下,程序员可能不需要PICC动态分配某些特殊的全局或静态的局部变量,而使用@address结构定义全局或静态的局部变量,例如:static unsigned char var1 @ 0x60;定义了一个称为var1的变量,使其定位于单元0x60,但是需要程序员注意的是,编译器并不保留任何存储空间,而只是将此变量分配到此地址,在编译时,编译器也不能给出任何的警告或错误提示,因此程序员在用绝对地址定义变量时,应该自己查看编译器产生的映象文件或符号表,必须保证绝对变量被分配了唯一的地址,尤其是当此绝对地址正好落在了PICC分配的自动变量区时,查错是很困难的。
当然简单的方法就是程序员自己使用高端的一块寄存器区定义绝对变量,因为,PICC的变量先从低端分配的。
3、使用可位寻址绝对地址变量在某些特殊情况下,为编程方便,程序员可能需要定义如下变量:static unsigned char flag_var; //非法static bit flag0 @ (unsigned)& flag_var *8+0;static bit flag1 @ (unsigned)& flag_var *8+1;static bit flag2 @ (unsigned)& flag_var *8+2;static bit flag3 @ (unsigned)& flag_var *8+3;static bit flag4 @ (unsigned)& flag_var *8+4;程序员希望这个变量(假设是故障标志)既可以按字节访问,也可按位访问,这在有些编译器中是可以的,但是在PICC中这样定义是不合法的,而只有将flag_var按如下绝对地址变量定义才可以定义可位寻址位:static unsigned char flag_var @0x7f;static bit flag0 @ (unsigned)& flag_var *8+0;…………………………但这样定义以后flag_var就成为绝对地址变量,就要程序员自己来保证此地址不会和PICC 自己分配的变量冲突,这又带来一定的麻烦,经笔者测试,要解决此问题,还有一种方法,那就是使用联合和结构位成员的方法,例如上例可如下定义:union{struct {unsigned flag0:1;unsigned flag1:1;unsigned flag2:1;unsigned flag3:1;unsigned flag4:1;}bit_type;unsigned char byte_type;}flag_var;这样定义以后,程序员既可以按照字节访问此故障标志,也可按位访问某一类型故障。
例如:flag_var.bit_type.flag0 = 1; //按位访问if(flag_var.byte_type) //按字节访问{……………}这两种访问都是合法的,而且程序员也不用在担心绝对地址是否有冲突的问题。
4、const类型限定符const类型限定符用来通知编译器一个目标具有常数值,不能被改变,被const定义的常量被放在ROM中,例如:unsigned char const var1[] ={"Microchip"};unsigned char const var2[] ={0x00,0x01,0x02,0x03};这两种定义都是合法的,但若通过指针访问这些数组变量,必须将指针定义为常数字符指针才能访问。
例如某函数声明为:void func1(const unsigned char *ptr);则调用常数数组的方法为:void func2(void){…………func1((const unsigned char *)var1);…………}这一点程序员一定要认真对待,以免编译运行错误很难查找故障。
5、可变型变量volatile类型限定符可变型变量volatile类型限定符用来通知编译器某一变量不能保证在连续访问的条件下,其值不被改变,例如所有的与I/O口有关的变量在编译器自带的头文件中都是被声明为volatile类型,如下所示:static volatile unsigned char PORTA @ 0x05;需要程序员注意的是有可能在中断时被改变的变量应该被定义为volatile类型,尤其是编译时选择全局优化级别较高时,定义为volatile可以禁止编译器对此变量进行优化,这能够防止编译器进行程序优化时,将认为明显多余的可变型变量删除,我们可以查看一下编译后生成的编译列表文件就会发现,编译器对volatile目标的访问与对non-volatile的访问是不同的, 如对non-volatile目标置1是先将该变量清0后加1, 而对volatile目标置1是先将1放在W中后再将W赋值给可变型变量。