首页 单片机的 C语言轻松入门

单片机的 C语言轻松入门

举报
开通vip

单片机的 C语言轻松入门 单片机的 C语言轻松入门 随着单片机开发技术的不断发展,目前已有越来越多的人从普遍使用汇编语言到逐渐使 用高级语言开发,其中主要是以 C 语言为主,市场上几种常见的单片机均有其 C 语言开发 环境。这里以最为流行的 80C51单片机为例来学习单片机的 C语言编程技术。 本书共分六章,每章一个专题,以一些待完成的任务为中心,围绕该任务介绍 C 语言 的一些知识,每一个任务都是可以独立完成的,每完成一个任务,都能掌握一定的知识,等 到所有的任务都完成后,即可以完成 C语言的入门工作。 第 1章 C语言...

单片机的 C语言轻松入门
单片机的 C语言轻松入门 随着单片机开发技术的不断发展,目前已有越来越多的人从普遍使用汇编语言到逐渐使 用高级语言开发,其中主要是以 C 语言为主,市场上几种常见的单片机均有其 C 语言开发 环境。这里以最为流行的 80C51单片机为例来学习单片机的 C语言编程技术。 本书共分六章,每章一个专题,以一些待完成的任务为中心,围绕该任务介绍 C 语言 的一些知识,每一个任务都是可以独立完成的,每完成一个任务,都能掌握一定的知识,等 到所有的任务都完成后,即可以完成 C语言的入门工作。 第 1章 C语言概述及其开发环境的建立 学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好。Keil软件是目 前最流行开发 80C51系列单片机的软件,Keil提供了包括 C编译器、宏汇编、连接器、库 管理和一个功能强大的仿真调试器等在内的完整开发 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 ,通过一个集成开发环境 (µVision)将这些部份组合在一起。 在学会使用汇编语言后,学习 C 语言编程是一件比较容易的事,我们将通过一系列的 实例介绍 C 语言编程的 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 。图 1-1 所示电路图使用 89S52 单片机作为主芯片,这种单片 机性属于 80C51系列,其内部有 8K的 FLASH ROM,可以反复擦写,并有 ISP功能,支 持在线下载,非常适于做实验。89S52的 P1引脚上接 8个发光二极管,P3.2~P3.4引脚上接 4个按钮开关,我们的任务是让接在 P1引脚上的发光二极管按要求发光。 1.1 简单的 C程序介绍 例 1-1: 让接在 P1.0引脚上的 LED发光。 /************************************************* 平凡单片机工作室 http://www.mcustudio.com Copyright 2003 pingfan's mcustudio All rights Reserved 作者:周坚 dddl.c 单灯点亮程序 *************************************************/ 图 1-1 接有 LED的单片机基本电路 P1.0 EA/VPP VCC XTAL2 XTAL1 GND RST +5V +5V + R1 E1 10K 10U CY27P 27P 1KPZ1 D8 D1 89××× #include “reg51.h” sbit P1_0=P1^0; void main() { P1_1=0; } 这个程序的作用是让接在 P1.0引脚上的 LED点亮。下面来分析一下这个 C语言程序包 含了哪些信息。 1)“文件包含”处理。 程序的第一行是一个“文件包含”处理。 所谓“文件包含”是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序 虽然只有 4行,但 C编译器在处理的时候却要处理几十或几百行。这里程序中包含 REG51.h 文件的目的是为了要使用 P1这个符号,即通知 C编译器,程序中所写的 P1是指 80C51单 片机的 P1端口而不是其它变量。这是如何做到的呢? 打开 reg51.h可以看到这样的一些内容: /*------------------------------------------------------------------------- REG51.H Header file for generic 80C51 and 80C31 microcontroller. Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved. --------------------------------------------------------------------------*/ /* BYTE Register */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; sfr PSW = 0xD0; sfr ACC = 0xE0; sfr B = 0xF0; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99; /* BIT Register */ /* PSW */ sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0; /* TCON */ sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88; /* IE */ sbit EA = 0xAF; sbit ES = 0xAC; sbit ET1 = 0xAB; sbit EX1 = 0xAA; sbit ET0 = 0xA9; sbit EX0 = 0xA8; /* IP */ sbit PS = 0xBC; sbit PT1 = 0xBB; sbit PX1 = 0xBA; sbit PT0 = 0xB9; sbit PX0 = 0xB8; /* P3 */ sbit RD = 0xB7; sbit WR = 0xB6; sbit T1 = 0xB5; sbit T0 = 0xB4; sbit INT1 = 0xB3; sbit INT0 = 0xB2; sbit TXD = 0xB1; sbit RXD = 0xB0; /* SCON */ sbit SM0 = 0x9F; sbit SM1 = 0x9E; sbit SM2 = 0x9D; sbit REN = 0x9C; sbit TB8 = 0x9B; sbit RB8 = 0x9A; sbit TI = 0x99; sbit RI = 0x98; 熟悉 80C51 内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地 址的对应关系。注意其中有 sfr P1 = 0x90; 这样的一行(上文中用黑体表示),即定义 P1与地址 0x90对应,P1口的地址就是 0x90 (0x90是 C语言中十六进制数的写法,相当于汇编语言中写 90H)。 从这里还可以看到一个频繁出现的词:sfr sfr并 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 C语言的关键字,而是 Keil 为能直接访问 80C51中的 SFR而提供了一个新 的关键词,其用法是: sfrt 变量名=地址值。 2)符号 P1_0来表示 P1.0引脚。 在 C语言里,如果直接写 P1.0,C编译器并不能识别,而且 P1.0也不是一个合法的 C 语言变量名,所以得给它另起一个名字,这里起的名为 P1_0,可是 P1_0 是不是就是 P1.0 呢?你这么认为,C编译器可不这么认为,所以必须给它们建立联系,这里使用了 Keil C 的关键字 sbit来定义,sbit的用法有三种: 第一种方法:sbit 位变量名=地址值 第二种方法:sbit 位变量名=SFR名称^变量位地址值 第三种方法:sbit 位变量名=SFR地址值^变量位地址值 如定义 PSW中的 OV可以用以下三种方法: sbit OV=0xd2 (1)说明:0xd2是 OV的位地址值 sbit OV=PSW^2 (2)说明:其中 PSW必须先用 sfr定义好 sbit OV=0xD0^2 (3)说明:0xD0就是 PSW的地址值 因此这里用 sfr P1_0=P1^0;就是定义用符号 P1_0来表示 P1.0引脚,如果你愿意也可以 起 P10一类的名字,只要下面程序中也随之更改就行了。 3)main称为“主函数”。 每一个 C语言程序有且只有一个主函数,函数后面一定有一对大括号“{}”,在大括号 里面书写其它程序。 从上面的分析我们了解了部分 C语言的特性,下面再看一个稍复杂一点的例子。 例 1-2 让接在 P1.0引脚上的 LED闪烁发光 /************************************************* 平凡单片机工作室 http://www.mcustudio.com Copyright 2003 pingfan's mcustudio All rights Reserved Administrator 高亮 Administrator 高亮 Administrator 打字机 直接方位单片机内部特殊寄存器资源。 Administrator 打字机 sbit提供了直接访问某一位的方法,访问的为必须是 能够位寻址的区域。 Administrator 打字机 Administrator 高亮 Administrator 箭头 Administrator 打字机 sbit 作者:周坚 ddss.c 单灯闪烁程序 *************************************************/ #include "reg51.h" #define uchar unsigned char #define uint unsigned int sbit P10=P1^0; /*延时程序 由 Delay参数确定延迟时间 */ void mDelay(unsigned int Delay) { unsigned int i; for(;Delay>0;Delay--) { for(i=0;i<124;i++) {;} } } void main() { for(;;) { P10=!P10; //取反 P1.0引脚 mDelay(1000); } } 程序分析:主程序 main中的第一行暂且不看,第二行是“P1_0=!P1_0;”,在 P1_0前有 一个符号“!”,符号“!”是 C语言的一个运算符,就像数学中的“+”、“-”一样,是一种 运算任号,意义是“取反”,即将该符号后面的那个变量的值取反。 注意:取反运算只是对变量的值而言的,并不会自动改变变量本身。可以认为 C 编译 器在处理“!P1_0”时,将 P1_0的值给了一个临时变量,然后对这个临时变量取反,而不 是直接对 P1_0取反,因此取反完毕后还要使用赋值符号(“=”)将取反后的值再赋给 P1_0, 这样,如果原来 P1.0是低电平(LED亮),那么取反后,P1.0就是高电平(LED灭),反之, 如果 P1.0是高电平,取反后,P1.0就是低电平,这条指令被反复地执行,接在 P1.0上灯就 会不断“亮”、“灭”。 该条指令会被反复执行的关键就在于 main中的第一行程序:for(;;),这里不对此作详细 的介绍,读者暂时只要知道,这行程序连同其后的一对大括号“{}”构成了一个无限循环语 句,该大括号内的语句会被反复执行。 第三行程序是:“mDelay(1000);”,这行程序的用途是延时 1s时间,由于单片机执行指 令的速度很快,如果不进行延时,灯亮之后马上就灭,灭了之后马上就亮,速度太快,人眼 根本无法分辨。 这里 mDelay(1000)并不是由 Keil C提供的库函数,即你不能在任何情况下写这样一行 程序以实现延时。如果在编写其它程序时写上这么一行,会发现编译通不过。那么这里为什 么又是正确的呢?注意观察,可以发现这个程序中有 void mDelay(…)这样一行,可见, mDelay 这个词是我们自己起的名字,并且为此编写了一些程序行,如果你的程序中没有这 么一段程序行,那就不能使用 mDelay(1000)了。有人脑子快,可能马上想到,我可不可 以把这段程序也复制到我其它程序中,然后就可以用 mDelay(1000)了呢?回答是,那当然 就可以了。还有一点需要说明,mDelay 这个名称是由编程者自己命名的,可自行更改,但 一旦更改了名称,main()函数中的名字也要作相应的更改。 mDelay后面有一个小括号,小括号里有数据(1000),这个 1000被称之“参数”,用它 可以在一定范围内调整延时时间的长短,这里用 1000来要求延时时间为 1000毫秒,要做到 这一点,必须由我们自己编写的 mDelay那段程序决定的,详细情况在后面循环程序中再作 分析,这里就不介绍了。 1.2 Keil工程的建立 要使用 Keil 软件,首先要正确安装 Keil 软件,该软件的 Eval 版本可以直接去 http://www.keil.com下载,安装时选择 Eval Vision,其它步骤与一般Windows程序安装类似, 这里就不再赘述了。安装完成后,将 Ledkey.dll 文件复制到 Keil 安装目录下的 C51\BIN 文 件夹下,这是作者提供的键盘与 LED实验仿真板,可与 Keil软件配合,在计算机上模拟 LED 和按键的功能。 启动µVison,点击“FileÆNew…”在工程管理器的右侧打开一个新的文件输入窗口, 在这个窗口里输入例 1-2中的源程序,注意大小写及每行后的分号,不要错输及漏输。 输入完毕之后,选择“FileÆSave”,给这个文件取名保存,取名字的时候必须要加上扩 展名,一般 C语言程序均以“.C”为扩展名,这里将其命名为 exam2.c,保存完毕后可以将 该文件关闭。 Keil不能直接对单个的 C语言源程序进行处理,还必须选择单片机型号;确定编译、汇 编、连接的参数;指定调试的方式;而且一些项目中往往有多个文件,为管理和使用方便, Keil使用工程(Project)这一概念,将这些参数设置和所需的所有文件都加在一个工程中, 只能对工程而不能对单一的源程序进行编译和连接等操作。 点击“Project->New Project…”菜单,出现对话框,要求给将要建立的工程起一个名字, 这里起名为 exam2,不需要输入扩展名。点击“保存”按钮,出现第二个对话框,如图 1-2 所示,这个对话框要求选择目标 CPU(即你所用芯片的型号),Keil 支持的 CPU 很多,这 里选择 Atmel公司的 89S52芯片。点击 ATMEL前面的“+”号,展开该层,点击其中的 89S52, 然后再点击“确定”按钮,回到主窗口,此时,在工程窗口的文件页中,出现了“Target 1”, 前面有“+”号,点击“+”号展开,可以看到下一层的“Source Group1”,这时的工程还是 一个空的工程,里面什么文件也没有,需要手动把刚才编写好的源程序加入,点击“Source Group1”使其反白显示,然后,点击鼠标右键,出现一个下拉菜单,如图 1-3所示,选中其 中的“Add file to Group”Source Group1”,出现一个对话框,要求寻找源文件。 双击 exam2.c文件,将文件加入项目,注意,在文件加入项目后,该对话框并不消失, 等待继续加入其它文件,但初学时常会误认为操作没有成功而再次双击同一文件,这时会出 现如图 1-4 所示的对话框,提示你所选文件已在列表中,此时应点击“确定”,返回前一对 话框,然后点击“Close”即可返回主接口,返回后,点击“Source Group 1”前的加号,exam3.c 文件已在其中。双击文件名,即打开该源程序。 1.3 工程的详细设置 工程建立好以后,还要对工程进行进一步的设置,以满足要求。 首先点击左边 Project窗口的 Target 1,然后使用菜单“Project->Option for target ‘target1’” 即出现对工程设置的对话框,这个对话框共有 8个页面,大部份设置项取默认值就行了。 Target页 图 1-2 选择单片机型号 图 1-3 加入文件 如图 1-5 所示,Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频 率值,该值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设 置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相 同,如果没必要了解程序执行的时间,也可以不设。 Memory Model用于设置 RAM使用情况,有三个选择项: Small: 所有变量都在单片机的内部 RAM中; Compact:可以使用一页(256字节)外部扩展 RAM; Larget: 可以使用全部外部的扩展 RAM。 Code Model用于设置 ROM空间的使用,同样也有三个选择项: Small:只用低于 2K的程序空间; Compact:单个函数的代码量不能超过 2K,整个程序可以使用 64K程序空间; Larget:可用全部 64K空间; 这些选择项必须根据所用硬件来决定,由于本例是单片应用,所以均不重新选择,按默 认值设置。 Operating:选择是否使用操作系统,可以选择 Keil 提供了两种操作系统:Rtx tiny 和 Rtx full,也可以不用操作系统(None),这里使用默认项 None,即不用操作系统。 图 1-5 设置目标 图 1-4 重复加入源程序得到的提示 Administrator 高亮 Administrator 高亮 Administrator 高亮 OutPut页 如图 1-6所示,这里面也有多个选择项,其中 Creat Hex file用于生成可执行代码文件, 该文件可以用编程器写入单片机芯片,其格式为 intelHEX格式,文件的扩展名为.HEX,默 认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项。 工程设置对话框中的其它各页面与 C51编译选项、A51的汇编选项、BL51连接器的连 接选项等用法有关,这里均取默认值,不作任何修改。以下仅对一些有关页面中常用的选项 作一个简单介绍。 Listing页 该页用于调整生成的列表文件选项。在汇编或编译完成后将产生(*.lst)的列表文件, 在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件的内容和形式进行细致 的调节,其中比较常用的选项是“C Compile Listing”下的“Assamble Code”项,选中该项 可以在列表文件中生成 C 语言源程序所对应的汇编代码,建议会使用汇编语言的 C 初学者 选中该项,在编译完成后多观察相应的 List 文件,查看 C 源代码与对应汇编代码,对于提 高 C语言编程能力大有好处。 C51页 该页用于对 Keil 的 C51 编译器的编译过程进行控制,其中比较常用的是“Code Optimization”组,如图 1.7所示,该组中 Level是优化等级,C51在对源程序进行编译时, 可以对代码多至 9级优化,默认使用第 8级,一般不必修改,如果在编译中出现一些问题, 可以降低优化级别试一试。Emphasis 是选择编译优先方式,第一项是代码量优化(最终生 成的代码量小);第二项是速度优先(最终生成的代码速度快);第三项是缺省。默认采用速 度优先,可根据需要更改。 图 1-6 设置输出文件 Debug页 该页用于设置调试器,Keil提供了仿真器和一些硬件调试方法,如果没有相应的硬件调 试器,应选择 Use Simulator,其余设置一般不必更改,有关该页的详细情况将在程序调试部 分再详细介绍。 至此,设置完成,下面介绍如何编译、连接程序以获得目标代码,以及如何进行程序的 调试工作。 1.4 编译、连接 下面我们通过一个例子来介绍 C 程序编译、连接的过程。这个例子使 P1 口所接 LED 以流水灯状态显示。 将下面的源程序输入,命名为 exam3.c,并建立名为 exam3的工程文件,将 exam3.c文 件加入该工程中,设置工程,在 Target页将 Xtal后的值由 24.0改为 12.0,以便后面调试时 观察延时时间是否正确,本项目中还要用到我们所提供的实验仿真板,为此需在 Debug 页 对 Dialog DLL对话框作一个设置,在进行项目设置时点击 Debug,打开 Debug页,可以看 到 Dialog DLL对话框后的 Parmeter:输入框中已有默认值-pAT52,在其后键入空格后再输入 -dledkey,如图 1-8所示。 例 1-3 使 P1口所接 LED以流水灯状态显示 /************************************************** ; 平凡单片机工作室 ; http://www.mcustudio.com ; Copyright 2003 pingfan's McuStudio ; All rights Reserved 图 1-7 C51编译器选项 ;作者:周坚 ;lsd.c ;流水灯程序 **************************************************/ #include "reg51.h" #include "intrins.h" #define uchar unsigned char #define uint unsigned int /*延时程序 由 Delay参数确定延迟时间 */ void mDelay(unsigned int Delay) { unsigned int i; for(;Delay>0;Delay--) { for(i=0;i<124;i++) {;} } } void main() { unsigned char OutData=0xfe; for(;;) { 图 1-8 Debug选项设置 P1=OutData; OutData=_crol_(OutData,1); //循环左移 mDelay(1000); /*延时 1000毫秒*/ } } 设置好工程后,即可进行编译、连接。选择菜单 Project->Build target,对当前工程进行 连接,如果当前文件已修改,将先对该文件进行编译,然后再连接以产生目标代码;如果选 择 Rebuild All target files将会对当前工程中的所有文件重新进行编译然后再连接,确保最终 生产的目标代码是最新的,而 Translate ….项则仅对当前文件进行编译,不进行连接。以上 操作也可以通过工具栏按钮直接进行。图 1-9是有关编译、设置的工具栏按钮,从左到右分 别是:编译、编译连接、全部重建、停止编译和对工程进行设置。 编译过程中的信息将出现在输出窗口中的 Build页中,如果源程序中有语法错误,会有 错误 报告 软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载 出现,双击该行,可以定位到出错的位置,对源程序修改之后再次编译,最终要得 到如图 1-10 所示的结果,提示获得了名为 exam3.hex 的文件,该文件即可被编程器读入并 写到芯片中,同时还可看到,该程序的代码量(code=63),内部 RAM的使用量(data=9), 外部 RAM的使用量(xdata=0)等一些信息。除此之外,编译、连接还产生了一些其它相关 的文件,可被用于 Keil的仿真与调试,到了这一步后即进行调试。 1.5 程序的调试 在对工程成功地进行汇编、连接以后,按 Ctrl+F5或者使用菜单 Debug->Start/Stop Debug Session 即可进入调试状态,Keil 内建了一个仿真 CPU 用来模拟执行程序,该仿真 CPU 功 能强大,可以在没有硬件和仿真机的情况下进行程序的调试。 进入调试状态后,Debug菜单项中原来不能用的命令现在已可以使用了,多出一个用于 运行和调试的工具条,如图 1-11 所示,Debug 菜单上的大部份命令可以在此找到对应的快 捷按钮,从左到右依次是复位、运行、暂停、单步、过程单步、执行完当前子程序、运行到 当前行、下一状态、打开跟踪、观察跟踪、反汇编窗口、观察窗口、代码作用范围分析、1 #串行窗口、内存窗口、性能分析、工具按钮等命令。 点击菜单 Peripherals,即会多出一项“键盘 LED仿真板(K)”,选中该项,即会出现如 图 1-9 有关编译、连接、项目设置的工具条 图 1-11 调试工具条 图 1-10 编译、连接后得到目标代码 图 1-12所示界面。 使用菜单 STEP或相应的命令按钮或使用快捷键 F11可以单步执行程序,使用菜单 STEP OVER 或功能键 F10 可以以过程单步形式执行命令,所谓过程单步,是指把 C 语言中的一 个函数作为一条语句来全速执行。 按下 F11键,可以看到源程序窗口的左边出现了一个黄色调试箭头,指向源程序的第一 行。每按一次 F11,即执行该箭头所指程序行,然后箭头指向下一行,当箭头指向 “mDelay(1000);”行时,再次按下 F11,会发现,箭头指向了延时子程序 mDelay的第一行。 不断按 F11键,即可逐步执行延时子程序。 如果 mDelay 程序有错误,可以通过单步执行来查找错误,但是如果 mDelay程序已正 确,每次进行程序调试都要反复执行这些程序行,会使得调试效率很低,为此可以在调试时 使用 F10来替代 F11,在 main函数中执行到 mDelay(1000)时将该行作为一条语句快速执行 完毕。 Keil软件还提供了一些窗口,用以观察一些系统中重要的寄存器或变量的值,这也是很 重要的调试方法。 以下通过一个对延时程序的延迟时间的调整来对这些调试方法作一个简单的介绍。 这个程序中用到了延时程序 mDelay,如果使用汇编语言编程,每段程序的延迟时间可 以非常精确地计算出来,而使用 C 语言编程,就没有办法事先计算了。为此,可以使用观 察程序执行时间的方法了来解。进入调试状态后,窗口左侧是寄存器和一些重要的系统变量 的窗口,其中有一项是 sec,即统计从开始执行到目前为止用去的时间。按 F10,以过程单 步的形式执行程序,在执行到 mDelay(1000)这一行之前停下,查看 sec的值(把鼠标停在 sec 后的数值上即可看到完整的数值),记下该数值,然后按下 F10,执行完 mDelay(1000)后再 次观察 sec值,如图 1-13所示,这里前后两次观察到的值分别是:0.00040400和 1.01442600, 其差值为 1.014022s,如果将该值改为 124可获得更接近于 1s的数值,而当该值取 123时所 获得的延时值将小于 1s,因此,最佳的取值应该是 124。 图 1-12 51单片机实验仿真板 1.6 C语言的一些特点 通过上述的几个例子,可以得出一些结论: 1、C程序是由函数构成的,一个 C源程序至少包括一个函数,一个 C源程序有且只有 一个名为 main()的函数,也可能包含其它函数,因此,函数是 C 程序的基本单位。主程序 通过直接书写语句和调用其它函数来实现有关功能,这些其它函数可以是由 C 语言本身提 供给我们的(如例 3 中的_crol_(…)函数),这样的函数称之为库函数,也可以是用户自 己编写的(如例 2、3中用的 mDelay(…)函数),这样的函数称之为用户自定义函数。那 么库函数和用户自定义函数有什么区别呢?简单地说,任何使用 Keil C 语言的人,都可以 直接调用 C 的库函数而不需要为这个函数写任何代码,只需要包含具有该函数说明的相应 的头文件即可;而自定义函数则是完全个性化的,是用户根据自己需要而编写的。Keil C提 供了 100多个库函数供我们直接使用。 2、一个函数由两部份组成: (1)函数的首部、即函数的第一行。包括函数名、函数类型、函数属性、函数参数(形 参)名、参数类型。 例如:void mDelay (unsigned int DelayTime) 一个函数名后面必须跟一对圆括号,即便没有任何参数也是如此。 (2)函数体,即函数首部下面的大括号“{}”内的部份。如果一个函数内有多个大括 号,则最外层的一对“{}”为函数体的范围。 函数体一般包括: 声明部份:在这部份中定义所用到的变量,例 1.2中 unsigned char j。 执行部份:由若干个语句组成。 在某此情况下也可以没有声明部份,甚至即没有声明部份,也没有执行部份,如: void mDelay() {} 这是一个空函数,什么也不干,但它是合法的。 在编写程序时,可以利用空函数,比如主程序需要调用一个延时函数,可具体延时多少, 怎么个延时法,暂时还不清楚,我们可以主程序的框架结构弄清,先编译通过,把架子搭起 来再说,至于里面的细节,可以在以后慢慢地填,这时利用空函数,先写这么一个函数,这 样在主程序中就可以调用它了。 3、一个 C 语言程序,总是从 main 函数开始执行的,而不管物理位置上这个 main()放 在什么地方。例 1.2中就是放在了最后,事实上这往往是最常用的一种方式。 图 1-13 观察 sec确定延时时间 4、主程序中的 mDelay如果写成 mdelay就会编译出错,即 C语言区分大小写,这一点 往往让初学者非常困惑,尤其是学过一门其它语言的人,有人喜欢,有人不喜欢,但不管怎 样,你得遵守这一规定。 5、C 语言书写的格式自由,可以在一行写多个语句,也可以把一个语句写在多行。没 有行号(但可以有标号),书写的缩进没有要求。但是建议读者自己按一定的规范来写,可 以给自己带来方便。 6、每个语句和资料定义的最后必须有一个分号,分号是 C语句的必要组成部份。 7、可以用/*…..*/的形式为 C程序的任何一部份作注释,在“/*”开始后,一直到“*/” 为止的中间的任何内容都被认为是注释,所以在书写特别是修改源程序时特别要注意,有时 无意之中删掉一个“*/”,结果,从这里开始一直要遇到下一个“*/”中的全部内容都被认 为是注释了。原本好好的一个程序,编译已过通过了,稍作修改,一下出现了几十甚至上百 个错误,初学 C 的人往往对此深感头痛,这时就要检查一下,是不是有这样的情况,如果 有的话,赶紧把这个“*/”补上。 特别地,Keil C也支持 C++风格的注释,就是用“//”引导的后面的语句是注释,例: P1_0=!P1_0; //取反 P1.0 这种风格的注释,只对本行有效,所以不会出现上面的问题,而且书写比较方便,所以 在只需要一行注释的时候,我们往往采用这种格式。但要注意,只有 Keil C支持这种格式, 早期的 Franklin C以及 PC机上用的 TC都不支持这种格式的注释,用上这种注释,编译时 通不过,会报告编译错误。 第 2章 分支程序设计 第一部分课程学习了如何建立 Keil C的编程环境,并了解了一些 C语言的基础知识, 这一部分将通过一个键控流水灯程序的分析来学习分支程序设计。 2.1 程序功能与实现 硬件电路描述如下:89S52单片机的 P1口接有 8个 LED,当某一端口输出为“0”时, 相应的 LED 点亮,P3.2、P3.3、P3.4、P3.5 分别接有四个按钮 K1~K4,按下按钮时,相应 引脚被接地。现要求编写可键控的流水灯程序,当 K1 按下时,开始流动,K2 按下时停止 流动,全部灯灭,K3使灯由上往下流动,K4使灯由下往上流动。 下面首先给出程序,然后再进行分析。 例 2-1:键控流水灯的程序 #include "reg51.h" #include "intrins.h" #define uchar unsigned char void mDelay(unsigned int DelayTime) { unsigned int j=0; for(;DelayTime>0;DelayTime--) { for(j=0;j<125;j++) {;} }} uchar Key() { uchar KeyV; uchar tmp; P3=P3|0x3c; //四个按键所接位置 KeyV=P3; if((KeyV|0xc3)==0xff) //无键按下 return(0); mDelay(10); //延时,去键抖 KeyV=P3; if((KeyV|0xc3)==0xff) return(0); else { for(;;){ tmp=P3; if((tmp|0xc3)==0xff) break;} return(KeyV);}} void main() { unsigned char OutData=0xfe; bit UpDown=0; bit Start=0; uchar KValue; Administrator 打字机 等到按键释放。 for(;;) { KValue=Key(); switch (KValue) { case 0xfb: //P3.2=0,Start { Start=1; break; } case 0xf7: //P3.3=0,Stop { Start=0; break; } case 0xef: //P3.4=0 Up { UpDown=1; break; } case 0xdf: //P3.5=0 Down { UpDown=0; break; } } if(Start) { if(UpDown) OutData=_crol_(OutData,1); else OutData=_cror_(OutData,1); P1=OutData; } else P1=0xff; //否则灯全灭 mDelay(1000); } } 单片机的 C语言轻松入门 19 输入源程序,保存为 exam21.c,建立名为 exam21 的工程文件,选择的 CPU 型号为 AT89S52,在 Debug页加入-ddpj6,以便使用单片机实验仿真板,其他按默认设置。正确编 译、链接后进入调试模式,点击 PeripheralsÆ51 实验仿真板,打开实验仿真板,选择 Run (全速运行),此时实验仿真板没有变化,用鼠标点击上方的 K1按钮,松开后即可看到 Led “流动”起来,初始状态是由下往上流动,点击 K3 按钮,可改变 LED 的流动方向,改为 由上往下流动,点击 K4按钮,又可将流动方向变换回来。点击 K2按钮,可使流动停止, 所有 LED“熄灭”。 2.1.1 程序分析 本程序中运用到了两种选择结构的程序:if和 switch,if语句最常用的形式是: if(关系表达式)语句 1 else 语句 2 2.1.2 关系运算符和关系表达式 所谓“关系运算”实际上是两个值作一个比较,判断其比较的结果是否符合给定的条件。 关系运算的结果只有 2种可能,即“真”和“假”。例:3>2的结果为真,而 3<2的结果为 假。 C语言一共提供了 6种关系运算符:“<”(小于)、“<=”(小于等于)、“>”(大于)、 “>=(大于等于)”、“==”(等于)和“!=”(不等于)。 用关系运算符将两个表达式连接起来的式子,称为关系表达式。例: a>b,a+b>b+c,(a=3)>=(b=5)等都是合法的关系表达式。关系表达式的值只有两种 可能,即“真”和“假”。在 C语言中,没有专门的逻辑型变量,如果运算的结果是“真”, 用数值“1”表示,而运算的结果是“假”则用数值“0”表示。 如式子:x1=3>2的结果是 x1等于 1,原因是 3>2的结果是“真”,即其结果为 1,该结 果被“=”号赋给了 x1,这里须注意,“=”不是等于之意(C语言中等于用“==”表示), 而是赋值号,即将该号后面的值赋给该号前面的变量,所以最终结果是 x1等于 1。 式子:x2=3<=2的结果是 x2=0,请自行分析。 2.2 逻辑运算符和逻辑表达式 用逻辑运算符将关系表达式或逻辑量连接起来的式子就是逻辑表达式。C语言提供了三 种逻辑运算符:“&&”(逻辑与)、“||”(逻辑或)和“!”(逻辑非)。 C语言编译系统在给出逻辑运算的结果时,用“1”表示真,而用“0”表示假,但是在 判断一个量是否是“真”时,以 0代表“假”,而以非 0代表“真”,这一点务必要注意。以 下是一些例子: (1) 若 a=10,则!a的值为 0,因为 10被作为真处理,取反之后为假,系统给出 的假的值为 0。 (2) 如果 a=--2,结果与上完全相同,原因也同上,初学时常会误以为负值为假, 所以这里特别提醒注意。 (3) 若 a=10,b=20,则 a&&b的值为 1,a||b的结果也为 1,原因为参于逻辑运算 时不论 a与 b的值究竟是多少,只要是非零,就被当作是“真”,“真”与“真” 相与或者相或,结果都为真,系统给出的结果是 1。 单片机的 C语言轻松入门 20 2.3 if语句 if语句是用来判定所给定的条件是否满足根据判定的结果(真或假)决定执行给出的两 种操作之一。 C语言提供了三种形式的 if语句 1. if(表达式) 语句 如果表达式的结果为真,则执行语句,否则不执行 2. if(表达式) 语句 1 else 语句 2 如果表达式的结果为真,则执行语句 1,否则执行语句 2 3.if(表达式 1) 语句 1 else if(表达式 2) 语句 2 else if(表达式 3) 语句 3 … else if(表达式 m) 语句 m else 语句 n 这条语句执行如图 2所示。 上述程序中的如下语句: if((KeyV|0xc3)==0xff) //无键按下 return(0); 是第一种 if语句的应用。该语句中“|”符号是 C语言中的位运算符,按位相或的意思, 相当于汇编语言中“ORL”指令,将读取的 P3口的值 KeyV与 0xc3(即 11000011B)按位 或,如果结果为 0xff(即 11111111B)说明没有键被按下,因为中间 4位接有按键,如果有 键按下,那么 P3口值的中间 4位中必然有一位或更多位是“0”。该语句中的“return(0)” 是返回之意,相当于汇编语言中的“ret”指令,通过该语句可以带返回值,即该号中的数 值,返回值就是这个函数的值,在这个函数被调用时,用了如下的形式:KValue=Key();因 此,返回的结果是该值被赋给 Kvalue 这个变量。因此,如果没有键被按下,则直接返回, 并且 Kvalue的值将变为 0。如果有键被按下,那么 return(0)将不会被执行。 程序其他地方还有这样的用法,请注意观察与分析。 程序中: if(Start) {… 灯流动显示的代码 } else P1=0xff; //否则灯全灭 是 if语句的第二种用法,其中 Start是一个位变量,该变量在 main函数的中被定义,并 赋以初值 0,该变量在按键 K1被按下后置为 1,而 K2按下后被清为 0,用来控制灯流动是 否开始。这里就是判断该变量并决定灯流动是否开始的代码,观察 if 后面括号中的写法, 与其他语言中写法很不一样,并没有一个关系表达式,而仅仅只有一个变量名,C根据这个 量是 0 还是 1 来决定程序的走向,如果为 1 则执行灯流动显示的代码,如果为 0,则执行 P1=0xff;语句。可见,在 C语言中,数据类型的概念比其他很多的编程语言要“弱化”,或 者说 C更着重从本质的角度去考虑问题,if后面的括号中不仅可以是关系表达式,也可以是 算术表达式,还可以就是一个变量,甚至是一个常量,不管怎样,C总是根据这个表达式的 值是零还是非零来决定程序的走向,这个特点是其他中所没有的,请注意理解。 if语句的第三种用法在本程序中没有出现,下面我们举一例说明。在上述的键盘处理函 单片机的 C语言轻松入门 21 数 Key中,如果没键被按下,返回值是 0,如果有键被按下,经过去键抖的处理,将返回键 值,程序中的“return(KeyV);”即返回键值。当 K1被按下(P3.2接地)时,返回值是 0xfb (11111011B),而 K2被按下(P3.3接地)时,返回值是 0xf7(11110111B),K3被按下(P3.4 接地)时,返回值是 0xef(11101111B),K4被按下(P3.5接地)时,返回值是 0xdf(11011111B), 该值将被赋给主程序中调用键盘程序的变量 KValue。程序用了另一种选择结构 switch 进行 处理,关于 switch将在稍后介绍。下面用 if语句来改写: if(KValue==0xfb) {Start=1;} else if(KValue==0xf7) {Start=0;} else if(KValue==0xef) {UpDown=1;} else if(KValue==0xdf) {UpDown=0;} else {//意外处理} …… 程序中第一条语句判断 Kvalue是否等于 0xfb,如果是就执行 Start=1;执行完毕即退出 if 语句,执行 if语句下面的程序,如果 Kvalue不等于 0xfb就转去下一个 else if即判断 Kvalue 是否等于 0xf7,如果等于则执行 Start=0;,并退出 if语句…这样一直到最后一个 else if后面 的条件判断完毕为止,如果所有的条件都不满足,那么就去执行 else 后面的语句(通常这 意味着出现了异常,在这里来统一处理这种异常情况)。 2.4 if语句的嵌套 在 if语句中又包含一个或多个语句称为 if语句的嵌套。一般形式如下 if() if() 语句 1 else 语句 2 else if() 语句 3 else 语句 4 应当注意 if与 else的配对关系,else总是与它上面的最近的 if配对。如果写成 if() if()语句 1 else 语句 2 编程者的本意是外层的 if与 else配对,缩进的 if语句为内嵌的 if语句,但实际上 else将 与缩进的那个 if 配对,因为两者最近,从而造迈岐义。为避免这种情况,建议编程时使用 大括号将内嵌的 if语句括起来,这样可以避免出现这样的问题。 单片机的 C语言轻松入门 22 2.5 swich语句 当程序中有多个分支时,可以使用 if 嵌套实现,但是当分支较多时,则嵌套的 if 语层 数多,程序冗长而且可读性降低。C 语言提供了 switch 语句直接处理多分支选择。Switch 的一般形式如下: switch(表达式) {case 常量表达式 1:语句 1 case 常量表达式 2:语句 2 …… case 常量表达式 n:语句 n default:语句 n+1 } 说明:switch后面括号内的“表达式”,ANSI标准允许它为任何类型;当表达式的值与 某一个 case后面的常量表达式相等时,就执行此 case后面的语句,若所有的 case中的常量 表达式的值都没有与表达式值匹配的,就执行 default后面的语句;每一个 case的常量表达 式的值必须不相同;各个 case和 default的出现次序不影响执行结果。 另外特别需要说明的是,执行完一个 case 后面的语句后,并不会自动跳出 switch,转 而去执行其后面的语句,如上述例子中如果这么写 switch (KValue) { case 0xfb: Start=1; case 0xf7: Start=0; case 0xef: UpDown=1; case 0xdf: UpDown=0; } if(Start) { ……} 假如 KValue的值是 0xfb,则在转到此处执行“Start=1;”后,并不是转去执行 switch语 句下面的 if语句,而是将从这一行开始,依次执行下面的语句即“Start=0;”、“UpDown=1;” “UpDown=0;”,显然,这样不能满足要求,因此,通常在每一段 case的结束加入“break;” 语句,使 流程 快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计 序退出 switch结构,即终止 switch语句的执行。 单片机的 C语言轻松入门 23 第 3章 数据类型 数据是计算机处理的对象,计算机要处理的一切内容最终将要以数据的形式出现,因此, 程序设计中的数据有着很多种不同的含义,不同的含义的数据往往以不同的形式表现出来, 这些数据在计算机内部进行处理、存储时往往有着很大的区别。下面我们来了解 C 语言数 据类型的有关知识。 3.1 C语言的数据类型概述 C语言中常的数据类型有:整型、字符型、实型等。 C语言中数据有常量与变量之分,它们分别属于以上这些类型。由以上这此数据类型还 可以构成更复杂的数据结构,在程序中用到的所有的数据都必须为其指定类型。 3.2 常量与变量 在程序运行过程中,其值不能被改变的量称为常量。常量区分为不同的类型,如 12、0 为整型常量,3.14、2.55为实型常量,‘a’、‘b’是字符型常量。 例 1符号常量的使用,在 P1口接有 8个 LED,执行下面的程序: #define LIGHT0 0xfe #include “reg51.h” void main() { P1=LIGHT0; } 程序中用#define LIGHT0 0xfe 来定义符号 LIGHT0 等于 0xfe,以后程序中所有出现 LIGHT0 的地方均会用 0xfe 来替代,因此,这个程序执行结果就是 P1=0xfe,即接在 P1.0 引脚上的 LED点亮。 这种用标识符代表的常量,称为符号常量。使用符号常量的好处是: 1.含义清楚。在单片机程序中,常有一些量是具有特
本文档为【单片机的 C语言轻松入门】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_963830
暂无简介~
格式:pdf
大小:406KB
软件:PDF阅读器
页数:48
分类:互联网
上传时间:2011-08-17
浏览量:14