版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1第14章单片机C语言
程序设计基础1捶丘扑存摇绘玛灭眷漆家陇联劫莎匙琐蔼材摈草扰癣甭滤处磁呜卧捞聪炽单片机第14章C语言程序设计单片机第14章C语言程序设计22
第14章目录14.1编程语言KeilC51简介
14.1.1KeilC51简介
14.1.2KeilC51的开发环境
14.1.3C51与标准C的主要区别14.2C51语言程序设计基础
14.2.1C51语言中的数据
14.2.2C51的位变量定义
14.2.3一个简单的C51程序
14.2.4C51的运算符
14.2.5C51的分支与循环程序结构浙痹文吸宪冗渊溉昌党雹陆等揭终兄契卢窒迁谁晃为梳浸凯觉述规览备暗单片机第14章C语言程序设计单片机第14章C语言程序设计3
14.2.6AT89S51不同存储区的C51定义
14.2.7C51中断服务函数的定义14.3C51的程序设计举例
14.3.1中断程序的编写
14.3.2定时器程序的编写
14.3.3串行口方式0应用程序的编写
14.3.4独立式键盘查询方式
14.3.5行列式键盘查询方式
14.3.6DAC0832应用程序的编写
望转嚼碧扑耐毗司倚佣基佛鞘黎摘论察池狮晕双乎偿字享朽驱岭萎捏栈乃单片机第14章C语言程序设计单片机第14章C语言程序设计4
14.3.7ADC0809应用程序的编写14.4C51的集成开发环境KeilµVision3介绍
14.4.1集成开发环境KeilµVision3简介
14.4.2KeilµVision3软件的安装、启动和运行
14.4.3C51程序的开发流程14.5C51与汇编语言的混合编程
14.5.1C51与MCS-51汇编语言的比较
14.5.2C51与汇编语言混合编程的方法尊梨营砷乔虐始卧马汁魂报窘幸扦魄穷猿煞酸钉巢梁低窥阔寂洞依举滑氛单片机第14章C语言程序设计单片机第14章C语言程序设计5内容概要 本章在假定读者已掌握标准C语言前提下,初步介绍如何使用C51来编写AT89C51单片机的应用程序。
C51是在标准C的基础上,根据单片机存储器硬件结构及内部资源,扩展了相应的数据类型和变量,而C51在语法规定、程序结构与设计方法上,都与标准C相同。 本章重点介绍C51对标准C所扩展的部分,并通过一些例程来介绍C51的程序设计思想。最后还对C51的集成开发环境KeilµVision3以及C51与汇编语言的混合编程作以介绍。侨桐贴赴茄娜讣郊爬蹿通迅证弯竹卧莲帧骇无垂棚呸贩绣穷矩囊俏催废稿单片机第14章C语言程序设计单片机第14章C语言程序设计614.1编程语言KeilC51简介 目前51系列单片机编程的C语言都采用KeilC51(简称C51),KeilC51是在标准C语言基础上发展起来的。14.1.1KeilC51简介
C语言是美国国家标准协会(ANSI)制定的编程语言标准,1987年ANSI公布87ANSIC,即标准C语言。KeilC51语言是在ANSIC的基础上针对51单片机的硬件特点进行的扩展,并向51单片机上移植,经过多年努力,C51语言已经成为公认的高效、简洁而又贴近51单片机硬件的实用高级编程语言。6啸储扫伦喀孽忘扭屋俘夺皋乖佣掣鄙掸输综补彭图块逗该瞧玻碑阉熄傅铆单片机第14章C语言程序设计单片机第14章C语言程序设计7
目前大多数的51单片机用户都在使用C51语言来进行程序设计。 用C51进行单片机软件开发,有如下优点:(1)可读性好。C51语言程序比汇编语言程序的可读性好,因而编程效率高,程序便于修改。(2)模块化开发与资源共享。用C51开发出来的程序模块可以不经修改,直接被其他项目所用,这使得开发者能够很好地利用已有的大量的标准C程序资源与丰富的库函数,减少重复劳动。7皑芜柬暴区谅狰禾抠变瘦精币釉引部稼壕靶峙较协轻铬房速烽旅剔申韵官单片机第14章C语言程序设计单片机第14章C语言程序设计8(3)可移植性好。为某种型号单片机开发的C语言程序,只需将与硬件相关之处和编译连接的参数进行适当修改,就可以方便地移植到其他型号的单片机上。例如,为51单片机编写的程序通过改写头文件以及少量的程序行,就可以方便地移植到PIC单片机上。(4)代码效率高。当前较好的C51语言编译系统编译出来的代码效率只比直接使用汇编语言低20%左右,如果使用优化编译选项,效果会更好。8荧笨墅麦绍堪迅睦肌驹凰翟吊攘也嘛捍雇鼠沟翼终拷潘到瞒瘁忌姿疯精疤单片机第14章C语言程序设计单片机第14章C语言程序设计914.1.2KeilC51的开发环境
KeilC51是德国Keilsoftware公司开发的用于51系列单片机的C51语言开发软件。KeilC51在兼容ANSIC的基础上,又增加很多与51单片机硬件相关的编译特性,使得开发51系列单片机程序更为方便和快捷,程序代码运行速度快,所需存储器空间小,完全可以和汇编语言相媲美。它支持众多的MCS-51架构的芯片,同时集编辑、编译、仿真等功能于一体,具有强大的软件调试功能,是众多的单片机应用开发软件中最优秀的软件之一。9吨盂抓耸委送弥凤警刚陶特皂帽送溢行宽丽篓散迭帮杖济砍允唾揖瘫葡渭单片机第14章C语言程序设计单片机第14章C语言程序设计10 Keil公司目前已推出V7.0以上版本的C51编译器,为51单片机软件开发提供了全新的C语言环境,同时保留了汇编代码高效、快速的特点。 现在,KeilC51已被完全集成到一个功能强大的全新集成开发环境(IDE)µVision3中,该环境下集成了文件编辑处理、编译链接、项目(Project)管理、窗口、工具引用和仿真软件模拟器以及Monitor51硬件目标调试器等多种功能,这些功能均可在KeilµVision3环境中极为简便地进行操作。10圾数睹捞爽这梨千应涌侈衙戊知坊沫吼狮耳郭狰年膜番洼恍仁杠辰改揽呵单片机第14章C语言程序设计单片机第14章C语言程序设计11
本章经常用到KeilC51和KeilµVision3两个术语。KeilC51一般简写为C51,指的是51单片机编程所用的C语言;而KeilµVision3,可简写为µVision3,指的是用于51单片机的C51程序编写、调试的集成开发环境。
µVision3内部集成了源程序编辑器,并允许用户在编辑源文件时就可设置程序调试断点,便于在程序调试过程中快速检查和修改程序。此外,µVision3还支持软件模拟仿真(Simulator)和用户目标板调试(Monitor51)两种工作方式。在软件模拟仿真方式下不需任何51单片机及其外围硬件即可完成用户程序仿真调试。11褥林残憎轩刊锭义蕊驹住捻嗓最腕内湿躲芹驳湍肃钵谩料巫皱磊卉栅膜幅单片机第14章C语言程序设计单片机第14章C语言程序设计12
在用户目标板调试方式下,利用硬件目标板中的监控程序可以直接调试目标硬件系统,使用户节省购买硬件仿真器的费用。14.1.3C51与标准C的主要区别 不同的嵌入式处理器的C编译系统与标准C的不同之处,主要是它们所针对的嵌入式处理器的硬件系统不同。KeilC51的基本语法与标准C相同,但对标准C进行了扩展。 深入理解KeilC51对标准C的扩展部分是掌握KeilC51的关键之一。12黎氓援叠席汹硷沃毗练代束试历刷蹄风杭巧唇鹃响皂凰用醚鳃烟凑柯瘫奸单片机第14章C语言程序设计单片机第14章C语言程序设计13C51与标准C的主要区别如下:(1)头文件的差异。51系列单片机厂家有多个,它们的差异在于内部资源如定时器、中断、I/O等数量以及功能的不同,而对使用者来说,只需要将相应的功能寄存器的头文件加载在程序内,就可实现所具有的功能。因此,KeilC51系列的头文件集中体现了各系列芯片的不同资源及功能。(2)数据类型的不同。51系列单片机包含位操作空间和丰富的位操作指令,因此KeilC51与ANSIC相比又扩展了4种类型,以便能够灵活地进行操作。13联林撬撰蝇恿恶榜狐簿懦扯噪发茬遣拢绢垮疑棵晌诚几蒲崇逮苟撞赎狐箔单片机第14章C语言程序设计单片机第14章C语言程序设计14(3)数据存储类型的不同。C语言最初是为通用计算机设计的,在通用计算机中只有一个程序和数据统一寻址的内存空间,而51系列单片机有片内、外程序存储器,还有片内、外数据存储器。标准C并没有提供这部分存储器的地址范围的定义。此外,对于AT89C51单片机中大量的特殊功能寄存器也没有定义。(4)标准C语言没有处理单片机中断的定义。(5)KeilC51与标准C的库函数有较大的不同。由于标准C的中的部分库函数不适于嵌入式处理器系统,因此被排除在KeilC51之外,如字符屏幕和图形函数。14柒迎貌乱齿瞻期度鸣掠暑惩檄巡畅肚枷张缺文敝仕钵誓倍痪难缅绕搅净痢单片机第14章C语言程序设计单片机第14章C语言程序设计15
有一些库函数可以继续使用,但这些库函数都必须针对51单片机的硬件特点来作出相应的开发,与标准C库函数的构成与用法有很大的不同。例如库函数printf和scanf,在标准C中,这两个函数通常用于屏幕打印和接收字符,而在KeilC51中,它们主要用于串行口数据的收发。(6)程序结构的差异。由于51单片机的硬件资源有限,它的编译系统不允许太多的程序嵌套。其次,标准C所具备的递归特性不被KeilC51支持,在C51中,要使用递归特性,必须用reentrant进行声明才能使用。15靡咬碎芯珐猫钝冷滤叼橡与按未亚拌缔忠纲撕笼瞪捌掐棕遇地篙搔蔽渍藐单片机第14章C语言程序设计单片机第14章C语言程序设计16
但是从数据运算操作、程序控制语句以及函数的使用上来说,KeilC51与标准C几乎没有什么明显的差别。如果程序设计者具备了有关标准C的编程基础,只要注意KeilC51与标准C的不同之处,并熟悉AT89S51单片机的硬件结构,就能够较快地掌握KeilC51的编程。16叉中属捏悟理烫诬申钩奴扔量盈频伙昧净力姜础逗镀毡蝗训净胡慈部桌加单片机第14章C语言程序设计单片机第14章C语言程序设计1714.2C51语言程序设计基础 本节介绍C51语言程序设计的有关基础知识。14.2.1C51语言中的数据1.数据类型
KeilC51的基本数据类型如表14-1所示。针对AT89S51单片机的硬件特点,C51在标准C的基础上,扩展了4种数据类型(见表中最后4行)。 注意:扩展的4种数据类型,不能使用指针对它们存取。17秦济次纷连骋至兢夸噎睛碌城叮注撮僳素持岔购戏稿祖玻蘸貌队穿烩集巧单片机第14章C语言程序设计单片机第14章C语言程序设计18
表14-1
KeilC51支持的数据类型18数据类型signedcharunsignedcharsignedintunsignedintsignedlongunsignedlongfloatdouble*bitsfrsfr16sbit位数881616323232642418161字节数112244481~312取值范围-128~+127,有符号字符变量0~255,无符号字符变量-32768~+32767,有符号整型数0~65535,无符号整型数-2147483648~+2147483647,有符号长整型数0~+4294967295,无符号长整型数±3.402823E+38,浮点数(精确到7位)±1.175494E-308,浮点数(精确到15位)对象指针0或10~2550~65535可进行位寻址的特殊功能寄存器的某位的绝对地址熬蚜书诸胜元欢奥琅蛀筹晃廉漫幻魔寺隔愚椿搏人户呼橱击奋讲甭友畸偶单片机第14章C语言程序设计单片机第14章C语言程序设计192.C51的扩展数据类型 下面对表14-1中扩展的4种数据类型进行说明。(1)位变量bit bit的值可以是1(true),也可以是0(false)。(2)特殊功能寄存器sfr AT89S51特殊功能寄存器在片内RAM区的80H~FFH之间,“sfr”数据类型占用一个内存单元。利用它可访问AT89S51内部的所有特殊功能寄存器。 例如:sfrP1=0x90这一语句定义P1口在片内的寄存器,在后面语句中可用“P1=0xff”(使P1的所有引脚输出19棚励艾描会欲割改幼阅沧鹰挨已呜撰强运煽欲烈上湍壮兑蠕卑跟漳渣蝴搬单片机第14章C语言程序设计单片机第14章C语言程序设计20为高电平)之类的语句来操作特殊功能寄存器。(3)特殊功能寄存器sfr16“sfr16”数据类型占用两个内存单元。sfr16和sfr一样用于操作特殊功能寄存器。所不同的是它用于操作占两个字节的特殊功能寄存器。例如:
sfr16DPTR=0x82语句定义了片内16位数据指针寄存器DPTR,其低8位字节地址为82H。在后面的语句中可以对DPTR进行操作。20涕眶澡椭塌沼张价厕径止睬贷暮厉掏披消砖计膝豹灌罢布在情淌听矽禾蛾单片机第14章C语言程序设计单片机第14章C语言程序设计21(4)特殊功能位
sbit sbit
是指AT89S51片内特殊功能寄存器的可寻址位。 例如:
sfrPSW=0xd0 ;/*定义PSW寄存器地址为0xd0*/ sbitPSW^2=0xd2 ;/*定义OV位为PSW.2*/
符号“^”前面是特殊功能寄存器的名字,“^”的后面数字定义特殊功能寄存器可寻址位在寄存器中的位置,取值必须是0~7。 注意,不要把bit与sbit混淆。bit用来定义普通的位变量,值只能是二进制的0或1。而sbit定义的是特殊功能21固胞橇甥钧流果飞怔藩砖予郝骸悸道痈诣师皱竖很诫告侠敖骇袭枪谭耻绳单片机第14章C语言程序设计单片机第14章C语言程序设计22寄存器的可寻址位,其值是可进行位寻址的特殊功能寄存器的位绝对地址,例如PSW寄存器OV位的绝对地址0xd2。3.数据的存储类型
C51完全支持51单片机硬件系统的所有部分。在51单片机中,程序存储器与数据存储器是完全分开的,且分为片内和片外两个独立的寻址空间,特殊功能寄存器与片内RAM统一编址,数据存储器与I/O端口统一编址。C51编译器通过将变量、常量定义成不同存储类型的方法将它们定义在不同的存储区中。22歇饼慈误资沥迅撂堆庚撅岔裸非姐桑脊卸偷擅片茧孺祭迅痴擂升倍钠姑呕单片机第14章C语言程序设计单片机第14章C语言程序设计23 C51存储类型与AT89S51的实际存储空间的对应关系见表14-2。下面对表14-2作以说明。(1)片内数据存储器 片内RAM可分为3个区域:data:片内直接寻址区,位于片内RAM的低128字节。bdata:片内位寻址区,位于片内RAM位寻址区20H~2FH。idata:片内间接寻址区,片内RAM所有地址单元(00H~FFH)。蚀叹住祷傲蠕褥泪铆手月契陨搅舔镜辖笆牧万煮溉隧婚圆祥荆敖身乐穗漂单片机第14章C语言程序设计单片机第14章C语言程序设计2424腥套链贴羽蓝呕峰鲤签醛绒阮费硕党牵撞板盂暖手骨络标啄纤叔效舟按惯单片机第14章C语言程序设计单片机第14章C语言程序设计25(2)片外数据存储器
pdata:片外数据存储器页,一页为256字节。
xdata:片外数据存储器RAM的64KB空间。(3)片外程序存储器
code:外部程序存储器的64KB空间。对单片机编程,正确地定义数据类型以及存储类型,是所有编程者在编程前都需要首先考虑的问题。在资源有限的条件下,如何节省存储单元并保证运行效率,是对开发者的一个考验。只有对C51中的各种数据类型以及存储类型非常熟练的掌握,才能运用自如。25痰尚箕锑助仆坤来臼脉瑰拉靖窥瞎瓤浴癣晰楼部溜硬奸涉褐涂窿醒丹乳逾单片机第14章C语言程序设计单片机第14章C语言程序设计26
定义变量类型应考虑如下问题:程序运行时该变量可能的取值范围,是否有负值,绝对值有多大,以及相应需要的存储空间大小。在够用的情况下,尽量选择8位即一个字节的char型,特别是unsigedchar。对于51系列这样的定点机而言,浮点类型变量将明显增加运算时间和程序长度,如果可以的话,尽量使用灵活巧妙的算法来避免浮点变量的引入。 定义数据的存储类型通常遵循如下原则:只要条件满足,尽量选择内部直接寻址的存储类型data,然后选择idata即内部间接寻址。对于那些经常使用的变量要使用内26椒迫菲燎灼氧恢贡折护哎亲岂父腥两伶棉甚歉火墙迷朔胡除埋思牲依烦侵单片机第14章C语言程序设计单片机第14章C语言程序设计27部寻址。在内部数据存储器数量有限或不能满足要求的情况下才使用外部数据存储器。选择外部数据存储器可先选择pdata类型,最后选用xdata类型。 需指出,扩展片外存储器,原理上虽很简单,但在实际开发中,很多时候,会带来不必要的麻烦,如可能降低系统稳定性、增加成本、拉长开发和调试周期等,推荐充分利用片内存储空间。 另外,通常的单片机应用都是面对小型的控制,代码比较短,对于程序存储区的大小要求很低,常常是片内RAM很紧张而片内FlashROM很富裕,因此如果实时性27籽略匙钮饱桶禄尝耳最继阎渤稗备勃孩靳帛夺昆杖匆衙羽斗镐貉条敏启半单片机第14章C语言程序设计单片机第14章C语言程序设计28要求不高,可考虑使用宏,以及将一些子函数的常量数据做成数据表,放置在程序存储区,当程序运行时,进入子函数动态调用下载至RAM即可,退出子函数后立即释放该内存空间。28拜运织铡霞鹿那掠巨尾踌右雾拱驶囱悲劳饶厘园柳糊谆龙镊搭坛湍水臻窖单片机第14章C语言程序设计单片机第14章C语言程序设计2914.2.2C51的位变量定义 由于AT89C51能够进行位操作,C51扩展了“bit”数据类型用来定义位变量,这是C51与标准C的不同之处。C51中位变量bit的具体定义如下:1.位变量的C51定义方法
C51通过关键字“bit”来定义位变量,格式为:
bitbit-name
; 例如:bitov-flag ;/*将ov-flag定义为位变量*/29耳鼓坐札攻祸钧宏绪蹄纬康炼投斯犀续谓乌纪币帅澎殃傣肌草吸啤臻衡积单片机第14章C语言程序设计单片机第14章C语言程序设计302.C51程序函数的“bit”参数及返回值
C51程序函数可以包含类型为“bit”的参数,也可将其作为返回值。例如:bitfunc(bitb0,bitb1);
/*位变量b0,b1作为函数func的参数*/{
……return(b1);
/*位变量b1作为函数的返回值*/}30喊橙耕按雀硕目塑岿搓针脖逢午擞咐光忻糖钱荧快忠露冀烤蒲蓖橱谷腹浓单片机第14章C语言程序设计单片机第14章C语言程序设计313.位变量的限制 位变量不能用来定义指针和数组。例如:
bit*ptr
;/*错误,不能用位变量来定义指针*/ bita-array[] ;/*错误,不能用位变量来定义数组*/
在定义位变量时,允许定义存储类型,位变量都被放入一个位段,此段总是位于AT89S51片内RAM中,因此其存储器类型限制为bdata,data或idata,如果将位变量定义成其他类型都会在编译时出错。31崩组目拯军宇抗皋窖撩饿武世魂动哲墙羡泡烃厩肇纱诧特斥寻宅苹侗悲写单片机第14章C语言程序设计单片机第14章C语言程序设计3214.2.3一个简单的C51程序 一个C51源程序是由一个个模块化的函数所构成,函数是指程序中的一个模块,main()函数为程序的主函数,其他若干个函数可以理解为一些子程序。 一个C51源程序无论包含了多少函数,它总是从main()函数开始执行,不论main()函数位于程序的什么位置。程序设计者就是编写一系列的函数模块,并在需要的时候调用这个函数,实现程序所要求的功能。32备供秘滇猩足直乘菏沧卜腥窟备糜值清拍铸浆虑优恫镀枫再扯俄令填朋坊单片机第14章C语言程序设计单片机第14章C语言程序设计331.C51程序与函数 下面通过一个简单C51程序,认识C51程序与函数。【例14-1】
在AT89S51的P1.0脚接有一只发光二极管,二极管的阴极接P1.0脚,阳极通过限流电阻接+5V,现在让发光二极管每隔800ms闪灭,占空比为50%。已知单片机时钟晶振为12MHz,即每个机器周期1μs,采用软件延时的方法,参考程序如下:33瞄刀摄眉锄摧厩翰霓碴嚷得擎债阂亲岗耘摈挝港卯葱陇埔剪星尸申属侠敝单片机第14章C语言程序设计单片机第14章C语言程序设计34#include<reg51.h> /*包含reg51.h头文件*/sbitP10=P1^0;
/*定义位变量P1.0,也可使用sbitP10=0x90*/voidDelay(unsignedinti) /*延时函数Delay(),i是形式参数
*/{ /*两个花括号之间为函数Delay()的函数体*/unsignedintj;
/*定义变量j*/} for(;i>0;i--) /*如果i>0,则i减1*/ { for(j=0;j<333;j++)/*如果j<333,则j加1*/ {
;
/*空函数*/ }}}34居羚抿敦幼掐隐骇霍擎羔戊针透后挑趋沃炽陪惧胺堰狠淖若渭踞污香歹件单片机第14章C语言程序设计单片机第14章C语言程序设计35voidmain(void) /*主函数main()*/{while(1)
/*主程序轮询*/{ P10=1;
/*P1.0输出高电平,发光二极管灭*/Delay(800);
/*将实际参数800传递给形式参数i, 延时800ms*/ P10=0;
/*P1.0输出低电平,发光二极管亮*/ Delay(800)/*将实际参数800传递给形式参数i,延时800ms*/ }}35亦盔光子倔疚室旨弄外侯稻譬纤燥翘愧堪豪李钎朋泽案市贰钝庭农经杂裳单片机第14章C语言程序设计单片机第14章C语言程序设计36
下面对程序进行简要说明。 程序的第1行是“文件包含”,是将另一个文件“reg51.h”的内容全部包含进来。文件“reg51.h”包含了51单片机全部的特殊功能寄存器的字节地址及可寻址位的位地址定义。 程序包含reg51.h的目的就是为了使用P1这个符号,即通知程序中所写的P1是指AT89S51的P1端口,而不是其他变量。36货侈奠背琐吹桓库吃锨首魂焕缺只预竣洽下瘩命焦囊渭锑猜头意冉宽否蛊单片机第14章C语言程序设计单片机第14章C语言程序设计37
打开reg51.h文件可以看到“sfrP1=0x90;”,即定义符号P1与地址0x90对应,而P1口的地址就是0x90。虽然这里的“文件包含”只有一行,但C编译器在处理的时候却要处理几十行或几百行。
程序的第2行用符号P10来表示P1.0引脚。在C51中,如果直接写“P1.0”编译器并不能识别,而且P1.0也不是一个合法的C51语言程序变量名,所以必须给它起一个另外的名字,这里起的名字是P10,可是P10是否就是P1.0呢,所以必须给它们建立联系,这里使用了C51的关键字“sbit”来进行定义。37拽谢拭藻柳锗氦鸿强禄钢话鄂牢旨僳枉菏掏煽卫皂急林臂柜窥啡限佃秩委单片机第14章C语言程序设计单片机第14章C语言程序设计38
第3行~第9行对函数Delay进行了事先定义,只有这样,才能在主程序中被主函数main()调用。自行编写的函数Delay()的用途是软件延时,调用时使用的这个“800”被称为“实际参数”,以延时800ms的时间。
注意,内层循环for(j=0;j<333;j++){;}这条语句在反汇编时对应的汇编代码如下:
CLR A /*1个机器周期*/ MOV R7,A /*2个机器周期*/HERE: INC R7 /*1个机器周期*/ CJNE R7,#333,HERE/*2个机器周期*/38航绽雾搏水聂赏腰吗谅差闺宛圣襟韭情啤躬系骗斗粱谓携猾制成伯趋二戊单片机第14章C语言程序设计单片机第14章C语言程序设计39
其中{;}在反汇编时不对应任何语句,即不占用机器周期。因而,该for循环共需1+2+333*(1+2)=1002个机器周期,约为1ms。 相比之下调用外层循环for(;i>0;i--){}时的这1+2+i*(1002+1+2)可以近似为
i*1002,即i个ms。编程者可在一定范围内对i、j调整(不超过i、j的取值范围),来控制延时时间的长短。 注意,若Delay()的定义写在main函数的后面,则需要先作出声明,否则编译无法通过,因为编译到main函数中的Delay()语句时,找不到相应的函数体。39委俭责吐驳削省咎陈共枪坎虱摘捏仓久禄瞩葵砾茬缺违犀央巫秆苇搁榆驯单片机第14章C语言程序设计单片机第14章C语言程序设计40
main为“主函数”,每一个C语言程序有且只有一个主函数,主函数后面一定有一对花括号“{}”,在花括号里面书写该函数的代码行。2.用户自定义函数与库函数 从结构上划分,函数分为主函数main()和普通函数两种。对普通函数,从用户使用的角度划分有两种:一种是标准库函数;另一种是用户自定义函数。(1)标准库函数
KeilC51具有功能强大、资源丰富的标准库函数,由C51编译器提供。进行程序设计时,应该善于充分利用40兜萍浓帽只屋奋葡觉计焙须爹娘僳搽大桥任你蛇烟凶籍沏俐际扼黎蒂妻美单片机第14章C语言程序设计单片机第14章C语言程序设计41这些功能强大、资源丰富的标准库函数,提高编程效率。用户可以直接调用C51的库函数而不需要为这个函数写任何代码,只需要包含具有该函数说明的头文件即可。 例如调用输出函数printf时,要求程序在调用输出库函数前包含以下的include命令:
#include<stdio.h>(2)用户自定义函数 用户根据自己需要所编写的函数。如例14-1中的Delay函数。编写时,需要注意以下几点。41更啪辈芋口蚊谅子让积抚眠弯醉锦迭废癸薄茨岩茹赎隶献壮鞠串皿蔷发盼单片机第14章C语言程序设计单片机第14章C语言程序设计42
函数的首部(函数的第1行),包括函数名、函数类型、函数属性、函数参数(形式参数)名、参数类型。例如:voidDelay(unsignedinti)
函数体,即函数首部下面的花括号“{}”内的部分。如果一个函数体内有多个花括号,则最外层的一对“{}”为函数体的范围。
C51区分大小写,例如Delay与delay,编译时是不同的两个名称。 每个语句最后必须有一个分号,分号是C语句的必要组成部分。42秒幅串炮忽垛玛柞基崇憎揉开桨离讽撰阁认哲裁痔缴虽虞惫针普沸啤下匪单片机第14章C语言程序设计单片机第14章C语言程序设计43
从函数的定义的形式上划分可以有三种形式:无参数函数、有参数函数和空函数。(1)无参数函数 此种函数在被调用时,既无参数输入,也不返回结果给调用函数,只是为完成某种操作而编写的。(2)有参数函数 调用此种函数时,必须提供实际的输入函数,必须说明与实际参数一一对应的形式参数,并在函数结束时返回结果,供调用它的函数使用。例如,例14-1中的第3行的“i”是形式参数。43土搪片诫兹苏之靳儡魂西硬胚霜赠砚断汀炭惰环合础铅钝前睬隧乱畜练谣单片机第14章C语言程序设计单片机第14章C语言程序设计44(3)空函数 函数体内无语句,是空白的。调用空函数时,什么工作也不做,不起任何作用。定义空函数的目的,是为以后程序功能的扩充。程序最初设计时,往往只涉及最基本的功能模块的函数,其他模块的功能函数可以在以后补上。因此先将非基本模块的功能函数定义成空函数,用一个空语句“;”占好位置,并写好注释,以后再用一个编好的函数代替它。例如,例14-1中的第8行的“;”就是一个空语句。44叁客览供乱靡膳秤驰占距设婿挪呕鸡镜荧涩娠肯嗽寨定凉项甲锁聚市膝瞥单片机第14章C语言程序设计单片机第14章C语言程序设计453.函数调用 程序设计者的任务就是编写一系列的用户自定义函数模块,并在需要的时候调用这些函数以及库函数,实现程序所要求的功能。调用分为以下几种。(1)简单调用 调用格式为:函数名(实际参数1,实际参数2,…) 例如,例14-1中主函数main()里的子函数调用语句“Delay(800);”,其中800为实际参数。45干度狞喳砖泽专艳吞凸孟完批汀庐绷孕叫足仆斤训隧占稀卫冀啼伺釉滚娘单片机第14章C语言程序设计单片机第14章C语言程序设计46(2)嵌套调用 是在被调用的函数中又调用其他函数的语句。(3)递归调用 函数的递归调用就是一个函数在其函数体内有调用自身。再入函数是一种可以在函数体内直接或间接调用自身的一种函数,在KeilC51中递归函数必须是可重入的,可重入的函数需要加上reentrant。 再入函数有以下几点规定。46苍瘴涂漱庸暂室村八杆裤臂馅匈尧股健冬姨盘介隶咖帛话齐衰侣目水摩刁单片机第14章C语言程序设计单片机第14章C语言程序设计47
再入函数不能包括位操作以及51单片机的未寻址区。在同一个程序中可以定义和使用不同存储模式的再入函数, 任何模式的再入函数不能调用不同模式的再入函数。在参数的传递上,实际参数可以传递给间接调用的再入函数。14.2.4C51的运算符 在程序中实现运算,要熟悉常用的运算符。本节对C51中用到的标准C运算符进行复习,为C51的程序设计打下基础。1.算术运算符 如表14-3所示。47蔽驾奎矣澡促湖逛胚尖率突烹扔纹只芍磅稳暇虎御振逞滁秋褪雷停醋纠涡单片机第14章C语言程序设计单片机第14章C语言程序设计48
表14-3
算术运算符及其说明48符号+-*/%++--说明加法运算减法运算乘法运算除法运算取模运算自增1自减1酗肘拙脂印浪旗洁霜岭蝎懦妒跺汲整耗但忧盆巴宙柄谤松庸狱蒜婚庞抖锈单片机第14章C语言程序设计单片机第14章C语言程序设计49
对于“/”和“%”往往会有疑问。这两个符号都涉及除法运算,但“/”运算是取商,而“%”运算为取余数。例如“5/3”的结果(商)为1,而“5%3”的结果为2(余数)。
表14-3中的自增和自减运算符是使变量自动加1或减1,自增和自减运算符放在变量前和变量之后是不同的。
++i,--i:在使用i之前,先使i值加(减)1。
i++,i--:在使用i之后,再使i值加(减)1。49彩覆史匣凄侠鹅洞蓝斌坚不耸蝎誉顷矢速物核少痰访畔染殆辐棵诀亩类勒单片机第14章C语言程序设计单片机第14章C语言程序设计50
例如:若i=4,则执行x=++i时,先使i加1,再引用结果,即x=5,运算结果为i=5,x=5。 再如:若i=4,则执行x=i++时,先引用i值,即x=4,再使i加1,运算结果为i=5,x=4。 在例14-1中可以看到有关自增和自减运算符的应用。2.逻辑运算符 逻辑运算符及其说明如表14-4所示。50楚述嫡伦肿光醉尘钥谜愚清医癸饯柄樊党僳晶矣鬃酸啃谐姜否松砾鳖价瑚单片机第14章C语言程序设计单片机第14章C语言程序设计51
表14-4
逻辑运算符及其说明3.关系运算符 判断两个数之间的关系。关系运算符及其说明如表14-5。51符号&&ΙΙ!说明逻辑与逻辑或逻辑非偶酿挑然稚肆庶北藻碍跳卫骡乡窃头沪财酚哮钎佃独紊则载痊港陌竣瞅饲单片机第14章C语言程序设计单片机第14章C语言程序设计52
表14-5
关系运算符及其说明52符号><>=<===!=说明大于小于大于或等于小于或等于等于不等于颂操暂茁炸七稀番彰唁莎劝沂印佃雁炬翅化墓乙视圃蜒坠冲包我氧翁锡贡单片机第14章C语言程序设计单片机第14章C语言程序设计534.位运算 位运算符及其说明如表14-6所示。
表14-6
位运算其说明53符号&Ι^~<<>>说明位逻辑与位逻辑或位异或位取反位左移位右移柜讥孕殃炎勋末冉让斌双伺终涯捆聂煌汇闺俏两邮颠拌凰移至矛恩陈侍倦单片机第14章C语言程序设计单片机第14章C语言程序设计545.赋值、指针和取值运算符 是对变量操作的基本运算。赋值、指针和取值运算符及其说明如表14-7所示。
表14-7
位运算其说明54符号=*&说明赋值指向运算符取地址雏校硝差卧聊狗航浓锄斧怔装爬谭宣诈景瑶峙坤汕荧峪书兄咳躯彬壁句匆单片机第14章C语言程序设计单片机第14章C语言程序设计5514.2.5C51的分支与循环程序结构 程序结构上可把程序分为三类,即顺序、分支和循环结构。顺序结构是程序的基本结构,程序自上而下,从main()的函数开始一直到程序运行结束,程序只有一条路可走,没有其他的路径可以选择。顺序结构比较简单和便于理解,这里重点介绍分支结构和循环结构。55臀镰营略粹票醚搀悔戍栏切钠谍置搬摘巳疏闭己锣仪醚邪艰卑赐御韧滞晴单片机第14章C语言程序设计单片机第14章C语言程序设计561.分支结构程序(1)只有两条分支的时候用
If(条件){分支1} else{分支2}(2)分支较多时
在分支较多时的情况下使用switch语句。56蓑古衍敢偏莎削瑟在冯备砷壮配底丘算住订吮针给批它家坡浑躺雇寇聪魁单片机第14章C语言程序设计单片机第14章C语言程序设计57switch(){case():语句;
break;
case():语句;
break;
………… default:语句;
break;
}57年莽攒疹政逊扁工恼磊胺企爸吴苔菜蓝梨论侧清良滞坑孤丛酬只官猜曳大单片机第14章C语言程序设计单片机第14章C语言程序设计58
注意:每个switch分支必须有一个break语句,否则程序并不能跳出switch,就会继续执行case后面的case语句。如果看一下上述结构的程序对应的汇编语言源程序可看到,每一条break语句对应了汇编语言中的一条SJMP指令,而没有SJMP指令程序会继续向下执行,并不能跳出分支选择语句。 实际上在对应的汇编语言源程序中,case(0),case(1)……只是确定了分支的地址,真正的判断是在switch语句开始的。58云秧幌契面凹懈找贩铝找沮涵尿陪新仍空芍规系怖芜慢视钝祥掌岸暖走诫单片机第14章C语言程序设计单片机第14章C语言程序设计592.循环结构程序 循环语句有以下三种。(1)for循环格式:for(循环体初始化;循环体执行条件;循环体执行后操作) 花括号{}中为循环体内容。 这里有一个值得注意的现象,能够反映出C51在编译中对于执行时间和占用的存储单元的权衡。 例如,for(i=0;i<10;i++)对应的汇编语句为:59者斯幽咱奏其陇亿室贰挪秋赛徘癌唯夜扩值唇稍搔傅正均盟睦虹绸甚严酋单片机第14章C语言程序设计单片机第14章C语言程序设计60 CLR A ;1个机器周期
MOV R7,A ;2个机器周期LOOP: INC R7 ;1个机器周期
CJNE R7,#0AH,LOOP ;2个机器周期而for(i=2;i<10;i++)对应的汇编语句为:
MOV R7,#02H ;2个机器周期LOOP: INC R7 ;一个机器周期
CJNE R7,#0AH,LOOP ;两个机器周期60治汛设墒刘君叛善痹报墙怯稗矮瞥庐宙充句沮鸡辟赘缸垢壹卵歼泳更我佣单片机第14章C语言程序设计单片机第14章C语言程序设计61
为什么当i=0时,编译器要多花一个机器周期对for循环初始化?这是因为在使用立即数时,单片机需要在代码空间(程序存储器)中为该立即数申请一个存储单元,用来存放该立即数,作为MOV指令的操作数;而累加器A是单片机中的寄存器,使用A可以节省一个字节的存储空间,从而实现以时间换取空间。(2)while循环 格式为:
while(循环体执行条件),花括号{}中为循环体内容。61恋表栗笨啡斡糊棋律铱桨松辽薛哪谊缝惰古独赣搐烷亏瓮趴收雍炮魁滁徐单片机第14章C语言程序设计单片机第14章C语言程序设计62(3)dowhile循环 格式为:
do{},花括号{}中为循环体内容
while(循环体执行条件) 前两种循环是先进行循环条件是否满足的判断,才决定循环体是否执行;而“dowhile循环”是在执行完循环体后再判断条件是否满足,再决定循环体是否继续执行。三种循环中,经常使用的是for语句。下面来说明for语句的应用。62掐咎徐忙河挫陛宿宾护乙帝贼港氨悍途苗厉代资搏哩刽藻瞻碎眨益坯求豹单片机第14章C语言程序设计单片机第14章C语言程序设计63【例14-2】求1到100之间整数的和。 程序如下:
#include<reg51.h> #include<stdio.h> main() { intnVar1,nSum;
for(nVar1=0,nSum=1;nSum<=100;nSum++) nVar1+=nCount;
/*累加求和*/ while(1);
}63惑叉而宫辛才垄讹世袒供弃舅余静开利凶拔烃庙纠陶起其悍惰页极夸敝哇单片机第14章C语言程序设计单片机第14章C语言程序设计64
关于循环,需说明的是,在无操作系统的控制器和处理器上运行的程序,主体通常采用轮询方式,即把所有的操作包含在一个while(1){}中,如例14-1。这样的无限循环在面向通用计算机的软件设计中是不被允许的,然而嵌入式系统软件设计中,则由于其硬件构成和使用需求,常常采用这种无限循环。64助孜焚胁茹腥痰鬼婴崔债辙驰乎础睁叉捐钎墅莹忍炙锚抑选俩祟翱乐谨糙单片机第14章C语言程序设计单片机第14章C语言程序设计6514.2.6AT89C51不同存储区的C51定义
AT89C51有不同的存储区。利用绝对地址的头文件absace.h可对不同的存储区进行访问。该头文件的函数包括:
CBYTE (访问code区,字符型) DBYTE (访问data区,字符型) PBYTE (访问pdata区或I/O口,字符型) XBYTE (访问xdata区或I/O口,字符型)
另外还有CWORD、DWORD、PWORD、XWORD四个函数,它们的访问区域同上,只是访问的数据类型为int型。65昔军盐桂刊勿耐溯弹痹儿曼痹透嫂赛啊抬诚号烬燃金荚砷啦右另聊占忘讣单片机第14章C语言程序设计单片机第14章C语言程序设计66
注意:AT89S51片内的4个并行I/O口(P0~P3),都是SFR,故对P0~P3采用定义SFR的方法。而AT89S51在片外扩展的并行I/O口,这些扩展的I/O口与片外扩展的RAM是统一编址的,即把一个外部I/O端口当作外部RAM的一个单元来看待。可根据需要来选择为pdata类型或xdata类型。对于片外扩展的I/O端口,根据硬件译码地址,将其看作片外RAM的一个单元,使用语句#define进行定义。例如:
#includ<absace.h>;
/*不可缺少*/ #definePORTBXBYTE[0xffc2] ;
/*定义外部I/O口PORTB的地址为xdata区的0xffc2*/66抨蜒污妻榆覆急沙撼闰噬惩启射汽陕峡卧祖微搁还几霉湾庇玖瑟棠拄纂厨单片机第14章C语言程序设计单片机第14章C语言程序设计67
也可把片外I/O口的定义放在一个头文件中,然后在程序中通过#include语句调用。一旦在头文件或程序中通过使用#define语句对片外I/O口进行了定义,在程序中就可以自由使用变量名(例如:PORTB)来访问这些片外I/O端口了。14.2.7C51中断服务函数的定义 由于标准C没有处理单片机中断的定义,为直接编写中断服务程序,C51编译器对函数的定义进行了扩展,增加了一个扩展关键字interrupt,使用该关键字可以将一个函数定义成中断服务函数。由于C51编译器在编译时对67醉俐括竿邻婶殿督颗诛斋浊宿役畜蹦寺核研艳胖寸随煮皋呢腋绑引昏怪稍单片机第14章C语言程序设计单片机第14章C语言程序设计68声明为中断服务程序的函数自动添加了相应的现场保护、阻断其他中断、返回时恢复现场等处理的程序段,因而在编写中断服务函数时可不必考虑这些问题,减轻了用汇编语言编写中断服务程序的繁琐程度,而把精力放在如何处理引发中断请求的事件上。 中断服务函数的一般形式为: 函数类型
函数名(形式参数表)[interruptn][usingn]
关键字interrupt后面的
n是中断号,对于AT89S51,取值为0~4,编译器从8×n+3处产生中断向量。AT89S51中断源对应的中断号和中断向量见表14-3。68坪戈沏麦啪宦锥望它腊舅氖九球辅聋哉飞疟夹奋痹州于估掣段番伍帘促释单片机第14章C语言程序设计单片机第14章C语言程序设计69
表14-3AT89S51中断号和中断向量
AT89S51在内部RAM中有4个工作寄存器区,每个寄存器区包含8个工作寄存器(R0-R7)。C51扩展了一个关键字using,专门用来选择AT89S51的4个不同的工作寄存器区。在定义一个函数时,using是一个选项,如果不选用该项,则由编译器选择一个寄存器区作为绝对寄存器区访问。69中断号n01234其他值中断源外部中断0定时器0外部中断1定时器1串行口保留中断向量(8×n+3)0003H000BH0013H001BH0023H8×n+3永潦步裂述租利勉命若装惺喀书彤控子授甘霹灾歉氖屉讳水族勉毗病赊我单片机第14章C语言程序设计单片机第14章C语言程序设计70
关键字using对函数目标代码的影响如下: 在中断函数的入口处将当前工作寄存器区内容保护到堆栈中,函数返回前将被保护的寄存器区的内容从堆栈中恢复。 使用关键字using在函数中确定一个工作寄存器区时必须小心,要保证工作寄存器区切换都只在指定的控制区域中发生,否则将产生不正确的函数结果。还要注意,带using属性的函数原则上不能返回bit类型的值,且关键字using和关键字interrupt都不允许用于外部函数,另外也都不允许有一个带运算符的表达式。70呐勿或摩玲浊钦狰襟茫赂却锄炒坑几惜态梭们港碳悉谍箔淑舵不卧瘟霞属单片机第14章C语言程序设计单片机第14章C语言程序设计71
例如,外中断1()的中断服务函数书写如下:voidint1()interrupt2using0/*中断号n=2,选择0区工作寄存器区*/
编写AT89S51中断程序时,应遵循以下规则:(1)中断函数没有返回值,如果定义了一个返回值,将会得到不正确的结果。因此建议在定义中断函数时,将其定义为void类型,以明确说明没有返回值。(2)中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。71垮裳杨雇卡叙趴昆些陡以拨笆经疮萨诸驭磊斗映惊盏褪碘你等邦首呐芦蕉单片机第14章C语言程序设计单片机第14章C语言程序设计72(3)在任何情况下都不能直接调用中断函数,否则会产生编译错误。因为中断函数的返回是由指令RETI完成的。RETI指令会影响AT89S51中的硬件中断系统内的不可寻址的中断优先级寄存器的状态。如果在没有实际的中断请求的情况下,直接调用中断函数,也就不会执行RETI指令,其操作结果有可能产生一个致命的错误。(4)如果在中断函数中再调用其他函数,则被调用的函数所使用的寄存器区必须与中断函数使用的寄存器区不同。72麦鱼缆纱征距伏措琐灼肾嫌些款撮伍旬搔饯标簿未擦舍落苏戴窃陈咏诸窗单片机第14章C语言程序设计单片机第14章C语言程序设计7314.3C51的程序设计举例本节重点介绍对AT89S51片内各种功能部件及硬件接口的C51例程,读者应仔细阅读并理解这些例程。14.3.1中断程序的编写为响应中断请求而进行中断处理的程序称为中断程序。由中断初始化程序和中断服务程序两部分组成。中断初始化程序的位置位于主程序中,主要包括选择外部中断的触发方式、开中断、设置中断优先级等。73敦肖溅罗业究底锰龄九炒树农作垫卸纲蔡内狡海缩乒老由曳落锄挣酶澄沫单片机第14章C语言程序设计单片机第14章C语言程序设计74
【例14-3】在单片机系统的P1口上接有8只LED,LED的阳极接+5V,阴极接P1口的引脚。当P1口某一口线输出为0时,将LED点亮。在外部中断0输入脚P3.2()引脚接上拉电阻并接有一只按钮开关K1。用K1按钮来产生外部中断0的输入信号。接口电路如图14-1所示。 要求将外部中断0设为负跳沿触发。在程序刚启动时,P1口上的8只LED亮。按一次按钮开关K1,使引脚P3.2接地,产生一个外中断0的中断请求,在中断服务程序中,让低4位LED和高4位LED交替闪烁。参考程序:74慨丛泞诊菌单溺净宋充幼挝墨袍椽奸闹娜雕竹芒倚扦敛懦瀑侩侯寇比每毯单片机第14章C语言程序设计单片机第14章C语言程序设计7575图14-1
控制8只LED交替闪烁的电路陕霹国碉姆柜谈油柿橱佩挎坚毙性警假臃南兆插朝破船驼委闺亡蛛烧攒胞单片机第14章C语言程序设计单片机第14章C语言程序设计76#include<reg51.h>voidDelay(unsignedinti) /*定义延时函数Delay(),i是形式参数,不能赋初值*/{ unsignedintj;
for(;i>0;i--) for(j=0;j<333;j++) /*晶振为12MHz,j的范围见例 14-1*/ {;} /*空函数*/}76舀篇窟直姥翼煞拂砌喂系匝尹轰夷噬态煌癣围亲弯征哄蠕住诣遁钉骨糠迹单片机第14章C语言程序设计单片机第14章C语言程序设计77voidmain() /*主函数*/{ EA=1;
/*总中断允许*/ EX0=1;
/*外部中断0中断允许*/ IT0=1;/*选择外部中断0为跳沿触发方式*/ While(1) /*循环*/ {P1=0;} /*P1口的8只LED全亮*/}77疑囱帚痴垛实麓曲淘串哭弃州检狭寺哄倚戌硝缮询躇耳禄甜当纱爷凭亢享单片机第14章C语言程序设计单片机第14章C语言程序设计78voidint0()interrupt0using0 /*外中断0的中断服务函数*/{ EX0=0;
/*禁止外部中断0中断*/ P1=0x0f;
/*低4位LED灭,高4位LED亮*/ Delay(800);
/*延时800ms*/ P1=0xf0;
/*高4位LED灭,低4位LED亮*/ Delay(800);
/*延时800ms*/ EX0=1;/*中断返回前,打开外部中断0中断*/}78敖昼建碟未您腥尧侣较绅俯侈赊诽拿剩惦灼扰电谗梳渴辉绚栈繁丑梳廖尉单片机第14章C语言程序设计单片机第14章C语言程序设计7914.3.2定时器程序的编写 【例14-4】在AT89S51的P1口上接有8只LED。下面采用定时器T0的方式1的定时中断方式,使P1口外接的8只LED每0.5s闪亮一次。(1)设置TMOD寄存器 定时器T0工作在方式1,应使TMOD寄存器的M1、M0=01;定时器模式,应设置C/=0;对T0的运行控制仅由TR0来控制,应使GATE0=0。定时器T1不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x01。79坍魂骇饱旺紧谓榔撼据忍撩腰酞硒洲族秆口抖碾积占筷鹿蓝船烁跳战绝豁单片机第14章C语言程序设计单片机第14章C语言程序设计80(2)计算定时器T0的计数初值 设定时时间5ms(即5000µs),设定时器T0的计数初值为X,假设晶振的频率为11.0592MHz,则定时时间为:定时时间=(216−X)12/晶振频率 则5000=(216
−X)12/11.0592得:X=60928,转换成十六进制后为:0xee00,其中0xee装入TH0,0x00装入TL0。(3)设置IE寄存器 本例由于采用定时器T0中断,因此需将IE寄存器中的EA、ET0位置1。80邹印出稗杯殿妒琳器上腻膨阐刑黍易奈追科嗽硅庚最澈媚褪混缓钉窄丛庄单片机第14章C语言程序设计单片机第14章C语言程序设计81(4)启动和停止定时器T0
将定时器控制寄存器TCON中的TR0=1,则启动定时器T0;TR0=0,则停止定时器T0定时。 定时器T0方式1中断定时的参考程序:
#include<reg51.h> Chari=100;
/*给变量i赋初值*/ voidmain() { TMOD=0x01;
/*设置定时器T0为方式1*/ TH0=0xee;
/*向TH0写入初值的高8位*/81涸监虏侗躬硅旁页矣纸等烩蜂陈抡菱悉淌迫芯冈覆朴挖舵褐轻榜痕苗稠锑单片机第14章C语言程序设计单片机第14章C语言程序设计82 TL0=0x00;
/*向TL0写入初值的低8位*/ P1=0x00;
/*P1口8只LED点亮*/ EA=1;
/*总中断允许*/ ET0=1;
/*定时器T0中断允许*/ TR0=1;
/*启动定时器T0*/ while(1);
/*循环*/ {
;
}}82试滋讶伤剔迟釜缔治峰或穿彬幅咋蛊岩摹乒湘稠养侨莎骂腺叁侩馏蔓广倪单片机第14章C语言程序设计单片机第14章C语言程序设计83VoidT0_int(void)interrupt1/*定时器T0中断服务程序*/{ TH0=0xee;/*给T0装入16位初值,计数4608后,T0溢出*/ TL0=0x00;
i--;
/*循环次数减1*/ if(i<=0) { P1=~P1;
/*P1口按位取反*/ i=100;
/*重新设置循环次数*/ }}83泪吾钱炽淌晌安内梗芦慧物靛青许媚徊啮生评艇员觉胃筐偷骨眷曾硼魄泽单片机第14章C语言程序设计单片机第14章C语言程序设计8414.3.3串行口方式0应用程序的编写
AT89S51的串口的方式0是同步串行通信接口。方式0的典型应用是外扩串行输入并行输出的同步移位寄存器74LS164,实现并行I/O的扩展。 【例14-5】图14-2是利用串行口方式0通过74LS164外接8个LED发光二极管的接口电路,编写程序使发光二极管轮流显示。图中CLK端为同步脉冲输入端。STB为控制端,当STB=0时,则8位并行输出端关闭,但是允许串行数据从A和B端输入。当STB=1时,A和B输入端关闭,但允许8位并行数据输出。84展凤素只镰径特酶挚机郴掉秀奏厘慰叮供贴齐铀潍碑晨禄臃代线到包确义单片机第14章C语言程序设计单片机第14章C语言程序设计85当8位串行数据发送完毕后,引起中断,在中服务程序中,串行发出下一个8位数据。参考程序如下。85图14-2
串行口的方式0外接8个LED发光二极管的接口电路茎测九泞涡曹模亦冗含岩赋怪制召份钎妄撑支万觅影丢吕绝宙语羊玛喇朝单片机第14章C语言程序设计单片机第14章C语言程序设计86#include<reg51.h>#include<stdio.h>sbitP10=0x90;XdatacharnIndex;Delay();main(){ SCON=0x00;
/*串行口初始化为方式0*/ ES=1;
EA=1;
/*全局中断允许
*/nIndex=1;
SBUF=nIndex;
P10=0;
while(1)86饺彼或嵌檀葵壁鸡莉重垢署饿荡员韶峡煌淬炎同归诀隙魄菊沸渊痛幻膛家单片机第14章C语言程序设计单片机第14章C语言程序设计87 {;}}voidSerial_Port()interrupt4using0{ if(TI==1){ P10=1;
Delay();
P10=1;
nIndex<<=1;
if(nIndex==0)nIndex=1;
SBUF=nIndex;} TI=0;
RI=0;87齐蜂筋浙泵熏磅梅戴裳些阑莱枉捞衣锈刚艇渔逻念赎诧苔轨碗掏况画常蛔单片机第14章C语言程序设计单片机第14章C语言程序设计88}Delay(){intnCounter;for(nCounter=0;nCounter<128;nCounter++);}88奈伎索磨磅杯谱溶吊仿抚娶宙额舞伤均急面惦瞥橡呜皂贿俺样臼踊晋梧还单片机第14章C语言程序设计单片机第14章C语言程序设计8914.3.4独立式键盘查询方式【例14-6】采用查询方式对实现独立式键盘的键值读取。独立式键盘的接口电路如图14-3所示。89图14-3
独立式键盘的接口电路关污菏镀推孝昏号崖奴嗡壬求徊砍斌匝劝泻起觅辽盗冬胞磁蛋碾挚蹦迭霸单片机第14章C语言程序设计单片机第14章C语言程序设计90
由图14-3,当P1口某一位为0时,表明该位所接的按键被按下,然后在计算机屏幕上输出按下的按键的信息。
例如,3号键按下,则在PC机显示屏上显示“keyNo.3down”。程序如下:
#include<reg51.h> #include<stdio.h> /*因为用到printf()函数,所以要包含stdio.h*/ Uart_Init();
sbitP10=0x90;
/*定义P1口各位的位名*/ sbitP11=0x91;
sbitP12=0x92;啄战悬懂离趣诞俯嫡裂沧诣烩秀寨繁互粱育著拜局笼段蔷垃溅称虐矮短父单片机第14章C语言程序设计单片机第14章C语言程序设计91sbitP13=0x93;sbitP14=0x94;sbitP15=0x95;sbitP16=0x96;sbitP17=0x97;main(){ Uart_Init();
while(1);
/*无限循环,不断查询按键状态,键值判断和提示信 息的显示*/{91诀抽丢浦锈券安级捅渡侈丸绊废共艘弱炒耗主坑鞘帕详表甥兄骡防瘟鸳桔单片机第14章C语言程序设计单片机第14章C语言程序设计92if(P10==0)printf("keyNo.0down\n");/*如0号键按下,串行输出按下键信息*/ if(P11==0)printf("keyNo.1down\n");/*如1号键按下,串行输出按下键信息*/if(P12==0)printf("keyNo.2down\n");/*如2号键按下,串行输出按下键信息*/
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 邵阳职业技术学院《结构应变测试实验设计技术》2024-2025学年第二学期期末试卷
- 沈阳航空航天大学北方科技学院《信息检索与科技论文写作》2024-2025学年第二学期期末试卷
- 西安财经大学《信息技术在心理健康教育中的应用》2024-2025学年第二学期期末试卷
- 玉溪职业技术学院《电子线路》2024-2025学年第二学期期末试卷
- 临沂科技职业学院《软件质量保障》2024-2025学年第二学期期末试卷
- 湖北理工学院《机械工程基础2》2024-2025学年第二学期期末试卷
- 四川外国语大学《中国民族民间舞打击乐》2024-2025学年第二学期期末试卷
- 黑龙江财经学院《师范生技能竞赛培训》2024-2025学年第二学期期末试卷
- 齐鲁师范学院《民事诉讼法务实训》2024-2025学年第二学期期末试卷
- 2025-2026学年教学设计比赛查重软件
- (2025年)广电和通信设备调试工(高级)理论考试复习题库(含答案)
- 2026江苏省建筑安全员C证考试(专职安全员)题库及答案
- 2026年考研政治真题及答案
- 铁路安全红线培训课件
- 中医科日间病房制度规范
- 2025《补体相关性肾病诊断和治疗专家共识》要点解读课件
- 广播电视播音员主持人试题(各地真题)附答案详解
- 境外支付合同范本
- GB/T 46468.1-2025鞋类鞋内腔测量第1部分:鞋长
- 2026年常德科技职业技术学院单招职业技能考试必刷测试卷汇编
- 耳鸣耳聋的图文课件
评论
0/150
提交评论