单片机第三讲_第1页
单片机第三讲_第2页
单片机第三讲_第3页
单片机第三讲_第4页
单片机第三讲_第5页
已阅读5页,还剩154页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、西京学院工程技术系电子信息教研室单片机原理与应用课程单片机原理与应用1第3讲 单片机C语言开发基础尽管汇编语言具有执行效率高的优点,但由于编程效率低、可移植性差、可读性差等缺点,应有受到了很大的限制。而简洁、结构优化的C语言以开发速度快、执行效率高、可移植性强等优点,受到了越来越多的单片机开发人员的喜爱。 (1)可以大幅度加快开发速度。特别是一些复杂的系统。程序量越大,C语言就越有优势。(2)无须精通单片机指令集和过多地了解硬件结构,也能迅速开发出功能强大的单片机应用系统。2第3讲 单片机C语言开发基础 尽管C语言代码比汇编语言占用的空间大5%20%,但是由于半导体技术的飞速发展,芯片容量和速

2、度已有大幅度的提高,占用的空间大小不再是开发者关心的主要因素。而随着市场竞争的日趋激烈,软件开发速度和质量才是决定能否在竞争中取胜的关键。所以,使用C语言已成为单片机应用系统开发的趋势。3第3讲 单片机C语言开发基础3.1 C语言源程序的结构特点C语言是一种结构化语言,它层次清晰,可以按模块化方式阻组织程序,易于调试何维护。它不仅有丰富的运算符和数据类型,便于实现各种运算,还可以直接对硬件进行操作。因此,C语言既具有高级语言的功能,也具有低级语言的优势。下面通过一个简单实例介绍C语言的结构特点和书写格式。 4第3讲 单片机C语言开发基础 这个程序的作用是通过单片机向P0口所接的硬件输出一个数据

3、,如可以点亮P0.0引脚的LED。(1)“文件包含”处理 程序的第一行是一个“文件包含”处理,是指一个文件将另一个文件的内容全部包含进来。由于单片机不认识“P0”(某寄存器的名字),因此必须给“P0”作定义。5第3讲 单片机C语言开发基础这种定义已经由开发软件(如Keil C51)完成了。在编程时必须将这种定义“包含”进去,才能使单片机认识“P0”等各种寄存器的名字。打开Keil的安装目录,在C51文件夹下找到“INC”子文件夹,打开里面的“reg51.h”文件,可以看到以下定义:6第3讲 单片机C语言开发基础7第3讲 单片机C语言开发基础 如果将“sfr P0= 0 x80;”语句中的“P0

4、”改为其他名字,如“Q0”。那么,在编程时,使用第一行的“文件包含”处理命令后,单片机就不再认识“P0”,而只认识“Q0”了。 (2)main()函数 main()函数称为主函数,每个C语言程序必须有且只有一个主函数,函数后面一定要有一对“”,程序就写在大括号里面。 (3)语句结束标志 语句必须以分号“;”结尾。8第3讲 单片机C语言开发基础 (4)注释 C语言程序中的注释是为了提高程序的可读性。在编译时,注释的内容不会被执行。3.2 标识符与关键字C语言规定:标志符只能是字母(A-Z,a-z)、数字(0-9)和下划线组成的字符串,并且第一个字符必须是字母或下划线。 在C语言编程中,为了定义变

5、量、表达语句功能和对一些文件预处理,还必须用到一些特殊意义的字符串,即关键字。关键字已被软件本身使用,不能再作为标志符使用。9第3讲 单片机C语言开发基础C语言的关键字分为三类:(1)类型说明符:用来定义变量、函数或其他数据类型,如unsigned char、int、long等。(2)语句定义符:用来标志一个语句的功能,如条件判断语句“if”、“while”等。函数printf,scanf,sin,isalum等等。 (3)预处理命令:表示预处理的关键字,如程序开头的“include”.所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。 ANSI C标准规定可以在C源程

6、序中加入一些“预处理命令”,以改进程序的10第3讲 单片机C语言开发基础设计环境,提高编程效率。预处理命令不是C语言本身的组成部分,不能直接对它们进行那个编译。必须在进行编译之前根据预处理命令对程序作相应的处理。由ANSI标准定义的32个关键字:11第3讲 单片机C语言开发基础12第3讲 单片机C语言开发基础13第3讲 单片机C语言开发基础另外,为了能够直接访问单片机的一些内部寄存器,Keil C51编译器扩充了关键字sfr。调用格式如下: sfr特殊功能寄存器名=地址常数示例: sfr P0=0 x80; /*定义地址为“0 x80”的特殊功能寄存器名字为“P0”,对P0的操作也就是对地址为

7、“0 x80”的寄存器操作*/。在8051系列单片机应用系统中,经常需要访问特殊功能寄存器的某些位,Keil C51编译器为此提供了另一种扩充关键字sbit,利用它可以定义位寻址对象。定义方法如下:14第3讲 单片机C语言开发基础sbit位变量名=特殊功能寄存器名位位置示例如下: sfr LED=P13; /位定义LED为P1.3(寄存器P1 的第三位) 作上述定义后,如果要点亮如图所示的发光二极管VD1,编程时就可以直接使用一下命令:LED=0; /将引脚P1.3电平置为“0”,对LED的操作 就是对P1.3的操作。15第3讲 单片机C语言开发基础3.3 C语言的数据类型与运算符3.3.1

8、数据类型在C语言中,可以将数据分为常量与变量两种。常量可以不经说明直接引用,而变量则必须定义类型后才能使用。常用的数据类型包括整型数据、字符型数据、实型数据、指针型数据和空类型数据等。1.常量与变量在程序运行过程中,数值不能被改变的变量为常量。常量分为不同类型,如12、0为整型常量,3.14、2.55为实型常量,“a”、“b”为字符型常量。16第3讲 单片机C语言开发基础C语言中还有一种符号常量,定义格式如下:#define符号常量的标志符 常量其中,#define是一条预编译处理命令,称为宏定义命令,功能是把该标志符定义为其后的符号常量值。一经定义,在程序中所有出现该标志的地方,就用之前定义

9、好的常量来代替。习惯上符号常量的标志符用大写字母表示。在程序运行中,数据可以改变的量成为变量,变量标志符常用小写字母表示。变量必须先定义后使用,一般放在程序的开头部分。17第3讲 单片机C语言开发基础2.整型数据整型数据包括整型常量和整型变量。(1)整型常量 不同的进制区分,整型常数有三种表示方法: 十进制数:以非0开始的数如:220,-560,45900 八进制数:以0开始的数如:06;0106,05788 十六进制数:以0X或0 x开始的数如:0X0D,0XFF(2)整型变量 整型变量可以分为基本型整型变量和无符号型整型变量,前者说明符为signed,在内存中占用2个字节;后者说 18第3

10、讲 单片机C语言开发基础明符为unsigned,在内存中占用1个字节。表列出了keil C51编译器支持的数据类型。19第3讲 单片机C语言开发基础整型变量定义的形式如下:类型说明符 变量标志1,变量标识2,3.实型数据 实型数据的表示形式 (1)小数形式数字和小数点组成3.14123.56-52.6812.5 (2)指数形式eE1.2356*1021.2356e2E前后必须有数字,E之后必须是整数,E和数字之间没有间隔。20第3讲 单片机C语言开发基础4.字符型数据字符型数据包括字符常量和字符变量。(1)字符常量用单引号括起来的一个字符,称为字符常量,如:“x”、“u”、“=”等。常用作显示

11、说明。(2)字符变量字符变量用来存储单个字符,说明符是“char”,定义形式如下: char a,b; char型数据的长度是1个字节。unsigned char与 21第3讲 单片机C语言开发基础signed char型数据的区别是有无符号位。(3)字符串常量由一对双引号括起来的字符序列称为字符串常量,如“beijing time:”等。5. 指针型数据指针是一个特殊的变量,存储的是某变量的地址,使用指针式C语言的精华所在,其使用方法后面介绍。6.位类型数据 位类型数据是C51编译器的一种扩充数据类型,利用它可以定义一个位变量,但不能定义位指针,也不能定义位数22第3讲 单片机C语言开发基础

12、组。该类型数据只能有两个取值:“0”和“1”。 7. 空类型数据 C语言经常使用函数,当函数被调用完后,通常会返回一个函数值。函数值也有一定类型,示例如下:int add( ) /将函数定义位整型数据 int sum; sum=12345+76543; Return sum; /返回计算值 23第3讲 单片机C语言开发基础函数add()返回一个整型数据,就说该函数是整型函数。但常有些函数不需要返回函数值,如LED流水灯点亮控制程序中的延时函数: void delay( ) /用“void”说明该函数为“空类 型”,即无返回值 unsigned int x; for(x=0;x20000;x+

13、24第3讲 单片机C语言开发基础8. 变量赋值在程序中常常需要变量赋值,C语言中的赋值方法如下: 类型说明符 变量=值;示例: int a=12345; unsigned char n=0 xab; 25第3讲 单片机C语言开发基础3.3.2 运算符1.算术运算符C语言有5中算术运算符。26第3讲 单片机C语言开发基础C语言中表示加1和减1时可以采用自增运算符和自减运算符。 2.关系运算符 用于比较运算。C语言有6种比较运算符,关系运算符的结果只有“0”和“1”两种,即满足条件时结果为“1”,否则为“0”。 27第3讲 单片机C语言开发基础28第3讲 单片机C语言开发基础 3. 逻辑运算符 逻

14、辑运算的结果只有“真”和“假”两种,“1”表示真,“0”表示假。29第3讲 单片机C语言开发基础 4. 位运算符利用位操作运算可以对一个二进制格式进行位操作。设x=25(0001 1001B),y=77(0100 1101B)为例介绍位操作运算符的使用。(1)按位“与”运算“&” “&”运算的功能是对二进制数按位进行“与”运算。根据“与”运算规则“有0为0,全1出1”,则30第3讲 单片机C语言开发基础 (2)按位“或”运算符“|” “|”运算的功能是对二进制数按位进行“或”运算。根据“或”运算规则“有1为1,全0出0”,则31第3讲 单片机C语言开发基础 (3)按位“异或”运算符“” “”运

15、算的功能是对二进制数按位进行“异或”运算。根据“异或”运算规则“相异1,相同出0”,则32第3讲 单片机C语言开发基础 (4)按位“取反”运算符“” “”运算的功能是对二进制数按位进行“取反”运算。根据“取反”运算规则“有1为0,有0出1”. (5)左移运算符“”右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,左边移出的空位,正数高位补0,负数的高位补1。5.赋值运算符 赋值运算符将一个数据赋给一个变量,也可以将一个表达式的值赋给一个变量。C语言中有以下两类赋值运算符。34第3讲 单片机C语言开发基础(1)简单赋值运算符(=),他的作用是将一个数据赋给一个变量,如c=a

16、+b。(2)复合赋值运算符(+=、-=、*=、/=、%=、&=、|=、=、=、b)?a:b因为ab为假,所以应取表达式2即b的值,结果max=13.38第3讲 单片机C语言开发基础8.强制转换符当参与运算的数据类型不同时,则先转换成同一数据类型,再进行计算。数据类型的转换方式有两种:一种是自动转换,另一种是强制转换。在C语言程序中进行算术运算时,必须注意数据类型的转换。自动类型转换是在对程序进行编译时由编译器自动处理的。自动类型转换的基本规则是转换后计算精度不能降低,所以当char、int、unsigned、long、double类型的数据同时存在时,其转换高低关系为charintunsign

17、edlongdouble。39第3讲 单片机C语言开发基础例如,当char型数据与int型数据共存时,则先将char型转化为int型再计算。强制转换通过强制类型转换运算符“()”进行的,其作用是将一个表达式转化为所需类型。格式如下:(类型名)(表达式)示例如下: (int) a; /将a强制转化为整型 (int)(3.58) ; /将实型变量3.58转化为整 型,结果为340第3讲 单片机C语言开发基础3.3.3 实例8:用不同数据类型的数据控制LED的闪烁 本例使用无符号整型数据和无符号字符型数据设计延时函数,分别用以控制图3-2中的VD1和VD2的闪烁,从而研究这两种不同数据的不同效果。

18、1.实现方法 为比较这两种数据的使用效果,将延时函数的循环次数设置相同,然后通过比较延时效果,直观地看出两种数据类型的效果。 2.程序设计 先建立文件夹“Ex8”,然后建立“Ex8”工程项目,最后建立源41第3讲 单片机C语言开发基础程序文件“Ex8.c”。输入源程序。图3.2 不同数据类型控制LED闪烁42第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到VD1的闪烁时间明显慢于VD2,即整型数据实现的延时函数延时时间较长。 由于整型数据占两个字节,而无符号字符型数据占一个字节,因此无符号整型数据进行操作花费的时间长。所

19、以,为了提高程序的运行速度,尽可能采用无符号字符型数据。43第3讲 单片机C语言开发基础3.3.4 实例9:用P0口、P1口分别显示加法和减法运算结果 本例用单片机实现“63+40”和“63-40”两道运算,并将加法运算结果送P1口显示,减法结果送P0口显示,采用电路如图3.4所示。 1.实现方法 设置两个无符号字符型变量n和m,并将其值分别赋值为63和40,然后直接将(n+m)和(n-m)的结果分别送入寄存器P1和P0。 2.程序设计 先建立文件夹“Ex9”,然后建立“Ex9”工程项目,最后建立源44第3讲 单片机C语言开发基础图3.345第3讲 单片机C语言开发基础程序文件“Ex9.c”。

20、输入源程序按。46第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到VD1的闪烁时间明显慢于VD2,即整型数据实现的延时函数延时时间较长。 由于整型数据占两个字节,而无符号字符型数据占一个字节,因此无符号整型数据进行操作花费的时间长。所以,为了提高程序的运行速度,尽可能采用无符号字符型数据。47第3讲 单片机C语言开发基础3.3.5 实例10:用P0口、P1口显示乘法运算结果 本例用单片机实现乘法“64X71”的运算,并通过P1口和P0口显示结果,用LED亮灭验证。本例采用如图3.4所示电路。 1.实现方法 先设置两个字符

21、变量m和n,并将其赋值为64和71.再设置一个整型变量s存储m和n的乘积。s=64X71=4544,需要16为二进制数表示,可将高8为送P1口,低8为送P0口。 2.程序设计 先建立文件夹“Ex10”,然后建立“Ex10”工程项目,最后建立源程序文件“Ex10.c”。输入源程序。48第3讲 单片机C语言开发基础图3.449第3讲 单片机C语言开发基础源程序50第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到P1.0口、P1.4口的LED熄灭,其余均被点亮,表明高8位数P1=0001 0001B=0 x11;而P0口除P0

22、.6和P0.7口的LED熄灭外,其余均被点亮,表明低8为数P0=1100 0000B=0 xc0,则P1口和P0口表示的16进制数为11c0H,化为10进制数为4544. 51第3讲 单片机C语言开发基础3.3.6 实例11:用P0口、P1口显示除法运算结果 本例用单片机实现除法“36/5=7.2”的运算,所得商的整数部分送P1口显示,小数部分送P0口显示。电路如图3.4所以。 1.实现方法 整数部分“7”可以用除法运算“36/5=7”来实现。36除以5的余数为1,若用除法运算“1/5”则得“0”(小数部分自动舍去)。因此需将余数“1”再乘以10,然后用所得的积除以“5”,即(36%5)*10

23、)/5,结果即为小说部分的数字“2”。 注意:上述方法在单片机控制小数的显示时非常有用。 (如温度为29.6摄氏度) 52第3讲 单片机C语言开发基础图3.453第3讲 单片机C语言开发基础 2.程序设计 先建立文件夹“Ex11”,然后建立“Ex10”工程项目,最后建立源程序文件“Ex11.c”。输入源程序。54第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到,P1.2口、P1.1口、P1.0口LED熄灭,其余均被点亮,表明P1=0000 0111B=7;而P0口只有P0.1口LED熄灭,其余均被点亮,表明P0=0000

24、 0010B=2. 55第3讲 单片机C语言开发基础3.3.7 实例12:用自增运算控制P0口8位LED的闪烁花样 本例用单片机自增运算控制P0口8位LED的流水花样,采用的电路图如图3.4. 1.实现方法 只要 送到P0口的数值发生变化,P0口8位LED点亮的状态就会发生变化。可以先将变量的初值送到P0口延时一段时间,再利用自增运算使变量加1,然后将新的变量值送到P0口并延时一段时间,即可使8为LED的闪烁花样变化。56第3讲 单片机C语言开发基础图3.457第3讲 单片机C语言开发基础 2.程序设计 先建立文件夹“Ex12”,然后建立“Ex12”工程项目,最后建立源程序文件“Ex12.c”

25、。输入源程序。58第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到,P0口8位LED的闪烁花样不断发生变化. 59第3讲 单片机C语言开发基础3.3.8 实例13:用Po口显示逻辑“与”运算结果 本例用P0口显示逻辑与运算(40&(90 xab)的结果,采用的电路图如图3.4. 1.实现方法 (40)&(90 xab)=1&0=0,直接将结果送到P0口,8位LED即可全部被点亮。 2.程序设计 先建立文件夹“Ex13”,然后建立“Ex12”工程项目,最后建立源程序文件“Ex13.c”。输入源程序。60第3讲 单片机C语言

26、开发基础图3.461第3讲 单片机C语言开发基础62第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到,P0口8位LED全部被点亮. 63第3讲 单片机C语言开发基础3.3.9 实例14:用P0口显示条件运算结果 本例用P0口显示逻辑与运算“(84)?8:4”的结果,采用的电路图如图3.4. 1.实现方法 先判断条件“84”是否满足,若满足,取8作为计算结果;否则,取4作为计算结果,本例条件运算的结果为8,直接将结果送到P0口即可。 2.程序设计 先建立文件夹“Ex14”,然后建立“Ex14”工程项目,最后建立源程序文件“

27、Ex14.c”。输入源程序。64第3讲 单片机C语言开发基础图3.465第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到,P0口8位LED全部被点亮. 66第3讲 单片机C语言开发基础3.3.10 实例15:用P0口显示按位“异或”运算结果 本例用P0口显示“异或”运算“0 xa20 x3c”的结果,采用的电路图如图3.4. 1.实现方法 异或运算的规则是“相异出1,相同出0”。因此 将该结果送到P0口即可。因为P0=1001 1110=0 x9e,所以P0.5、P0.0、P0.6引脚LED被点亮,其它LED均处于熄灭状

28、态。67第3讲 单片机C语言开发基础 2.程序设计 先建立文件夹“Ex15”,然后建立“Ex15”工程项目,最后建立源程序文件“Ex15.c”。输入源程序。68第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。可以看到,P0.5、P0.0、P0.6引脚LED被点亮,其它LED均处于熄灭状态。69第3讲 单片机C语言开发基础3.3.11 实例16:用P0口显示左移运算结果 本例用P0口显示左移运算“0 x3bb) max=a; else max=b; 82第3讲 单片机C语言开发基础 (3)if(表达式1) 语句1 else if(

29、表达式2) 语句2 else if(表达式3) 语句3 2. switchcase语句 if语句比较适合从两者之间选择。当要实现从多种选一时,采用switchcase多分支选择语句,可是程序变得更为简洁。一般格式如下:83第3讲 单片机C语言开发基础84第3讲 单片机C语言开发基础 注意:对于switch语句,有两点注意事项,一是表达式的必须是整型或字符型;而是最好使用“break”。 85第3讲 单片机C语言开发基础86第3讲 单片机C语言开发基础 3. for循环语句 for循环语句结构可以使程序按指定的次数重复执行一个语句或一组语句。一般格式如下: for(初始化表达式;条件表达式;增量

30、表达式) 语句; for循环语句的执行过程如下: 初始化表达式 求解条件表达式。若值为“真”,则执行for后面的 语句;若值为“假”,跳过循环语句。 若条件表达式为“真”,则执行指定语句,执行增87第3讲 单片机C语言开发基础 量表达式。 执行for后面的语句 4. while循环语句 while语句先判定循环条件为真或假。如果为真,则执行循环体;否则,跳出循环体,执行后续操作。一个是如下: while(表达式) 循环体 注意:1.循环体包含一个以上的语句,应该用括 起来。 2.一般情况下,在循环体中应该有让循环最终能 结束的语句,否则将造成死循环。 88第3讲 单片机C语言开发基础89第3讲

31、 单片机C语言开发基础 5. dowhile循环语句 dowhile循环是先执行一次循环体,再判断表达式的值。若为真,则继续执行循环;否则退出循环。格式如下: do 循环体语句 while(表达式) dowhile循环语句执行过程如下: 先执行一次指定的循环体语句,然后判断表达式 当表达式的值为非零时,返回到第一步重新执行循环 体语句 如此反复,直到表达式的值等于0时,结束循环 90第3讲 单片机C语言开发基础 注意:1.do是C语言关键字,必须和while联合使用。 2.while(表达式)后的分号不能丢,它表示整 个循环语句的结束。 6.goto无条件转移语句 goto语句是无条件转移语句

32、,它将程序执行流向转到它指定的标号处去执行。格式如下: goto标号; 使用goto语句时应谨慎,尽量避免使用goto语句。因为该语句会破坏程序的模块化结构,使得可读性变差,难于正确运行和维护。 91第3讲 单片机C语言开发基础3.4.4 实例20:用switch语句控制P0口8位LED的点亮状态 本例用switch实现方法语句控制P0口8位LED的点亮状态。第一次按下S1时,VD1被点亮,第一次按下S2时,VD2被点亮,以此类推,第八次按下S1时,VD8被点亮.然后再次次按下S1时,VD1又被点亮,如此循环电路图如图3.9所示。 1.实现方法 设置一个变量i,当i=1时,点亮VD1;当i=2

33、时,点亮VD2;以此类推,当i=8时,点亮VD8.由switch语句根据i的值来实现相应的功能。 需要说明的是,按下按键时,通常都会有抖动(后面详92第3讲 单片机C语言开发基础细介绍)。表面上看是按了一次按键,但由于按键的抖动,单片机可能认为按了多次,从而使输入不可控制。此问题可用“软件消抖”来解决。当单片机第一次检测到按键按下时,将认为是抖动而不理会,若延时2080ms后,再次检测到按键按下,才认为按键确实按下了,再执行相应的程序。 2.程序设计 先建立文件夹“Ex20”,然后建立“Ex20”工程项目,最后建立源程序文件“Ex20.c”。输入源程序。93第3讲 单片机C语言开发基础图3.9

34、94第3讲 单片机C语言开发基础95第3讲 单片机C语言开发基础96第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到,当用鼠标按下按键S1时,P0口的LED将按照S1被按下的次数而被点亮。97第3讲 单片机C语言开发基础3.4.5 实例21:用for语句设计鸣笛报警器程序 本例硬件电路如下图所示。要求用for语句设计一个鸣笛报警程序。具体设计要求如下: (1)能交替发出频率为1600Hz和800Hz的声音; (2)高音(1600Hz)发音的时间约为0.5s,低音发音的时间约为0.5s。注意:本例看似是一个简单的小

35、程序,但该程序用到的一些方法将在后面章节经常用到,尤其在写某些芯片的驱动程序时必须用到。98第3讲 单片机C语言开发基础99第3讲 单片机C语言开发基础 1.实现方法 (1)音频的实现 首先分析如何发出频率为f的声音。因为该声音的周期T=1/f,所以要让蜂蜜器发出频率f的声音,只要让单片机给蜂蜜器输送图3-10所示周期为T的脉冲方波电平即可。也就是让单片机的输出电平每半个周期取反一次。以1600Hz为例,周期T=(1/1600)s=0.000625s=625us,半个周期T/2312u即需要输出电平312us取反一次。显然,半周期可通过延时实现。100第3讲 单片机C语言开发基础 (2)延时时

36、间的控制通过前面的例子可知,采用循环的方法可以实现延时,但延时时间和循环次数之间有什么关系呢?下面通过一个实例分析。先编写如下的C语言程序:101第3讲 单片机C语言开发基础102第3讲 单片机C语言开发基础 在Keil C51环境下编译后,先单击菜单“调试”“开始/停止”命令;再单击菜单“视图”“反汇编”命令。此时,系统弹出图3.11所示的反汇编代码窗口。图3.11103第3讲 单片机C语言开发基础 其中有一段汇编程序(以0 x001D开头) 这一段代码就是由C语言延时函数形成的汇编代码,它消耗的机器周期等于C语言延时程序消耗的机器周期。查汇编指令表可以知道,在上述程序段中:第01行指令“C

37、LR”消耗1个机器周期第02行指令“MOV”消耗1个机器周期第03行指令“INC”消耗一个机器周期第04行指令“CJNE”消耗2个机器周期104第3讲 单片机C语言开发基础 根据循环条件,第03行和第04行总共要执行100次(0 x64=100)。所以,上述程序共消耗机器周期数:N=1+1+(1+2)x100=302根据上述分析可知,一重循环for(i=0;in;i+)所消耗的机器周期为N=3n+2。其中,N为消耗的机器周期数;n为设定的循环次数(n必须为无符号字符型数据)。同理可得,二重循环程序:for(i=0;in;i+) for(i=0;im;i+) ;105第3讲 单片机C语言开发基础

38、所消耗的机器周期数为N=3nm+5m+2.(3)声音周期的控制如果单片机的晶振频率为11.059MHz,则机器周期为1.085us。根据分析要发出频率为1600Hz的声音,就要让单片机每312us将输出电平取反一次,而延时312us需要消耗机器周期数N=312/1.085286300(一般应用,延时不需要特别精确)。循环次数应选为n=300/3=100,即每循环100次,让输出电平取反1次就可以得到1600Hz的音频。因此1600Hz音频延时函数的定义如下:106第3讲 单片机C语言开发基础107第3讲 单片机C语言开发基础(4)音频发声时间的控制 以1600Hz音频发声时间控制为例,要使其发

39、声0.5s=500ms。该音频的一个震动周期为625us06ms,则共需要500/0.6830个声音周期。类似的,800Hz音频发声时间需设置约200个声音周期。 2.程序设计 先建立文件夹“Ex21”,然后建立“Ex21”工程项目,最后建立源程序文件“Ex21.c”。输入源程序。108第3讲 单片机C语言开发基础109第3讲 单片机C语言开发基础110第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以听到发出的报警声。111第3讲 单片机C语言开发基础3.4.6 实例22:用while语句控制P0口8位LED闪烁花样

40、 本例用while语句控制P0口8位LED闪烁花样,硬件电路图及某时刻的仿真效果图如3.12所示。 1.实现方法 在while循环中设置一个变量i,当i0 xff时,将i的值送到P0口显示并自增1;当i等于0 xff时,跳出while循环。 2.程序设计 先建立文件夹“Ex22”,然后建立“Ex22”工程项目,最后建立源程序文件“Ex22.c”。输入源程序。112第3讲 单片机C语言开发基础图3.12113第3讲 单片机C语言开发基础114第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到P0口的8位LED以各种花

41、样不断闪烁。115第3讲 单片机C语言开发基础3.4.7 实例23:用dowhile语句控制P0口8位LED流水点亮 本例用dowhile语句控制P0口8位LED流水点亮,硬件电路图如3.12所示。 1.实现方法 本例只需在循环中将8位LED依次点亮,再将循环条件设为“死循环”即可。 2.程序设计 先建立文件夹“Ex23”,然后建立“Ex23”工程项目,最后建立源程序文件“Ex23.c”。输入源程序。116第3讲 单片机C语言开发基础117第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到P0口的8位LED被循环流

42、水点亮。118第3讲 单片机C语言开发基础3.5 C语言的数组 数组是同类型的一组变量,引用这些变量时可用同一个标志,借助于下标来区分各个变量。数组中的每一个变量称为数组元素。数组连续的存储区域组成,最低地址对应于数组的第一个元素,最高地址对应于最后一个元素。数组可以是一维的,也可以使多维的。3.5.1 数组的定义和引用1.一维数组一维数组的表达形式如下: 类型说明符 数组名常量;119第3讲 单片机C语言开发基础方括号中的常量称为下标。C语言中,下标是从0开始的。示例如下: int a10;/定义整型数组a,它有a0-a9共10 个元素,每个元素都是整型变量一维数组的赋值方法有一下几种。(1

43、)在数组定义时赋值,示例如下: int a10=0,1,2,3,4,5,6,7,8,9;数组元素的下标从0开始,赋值后,a0=0,a1=1,依次类推,直至a9=9。120第3讲 单片机C语言开发基础(2)对于一个数组也可以部分赋值,示例如下: int a10=0,1,2,3,4,5; 这里面对前6个元素赋值。对于没有赋值的a6至a9,默认的初始值为0.(3)如果一个数组的全部元素都已经赋值,可以省去方括号中的下标,示例如下: int a =0,1,2,3,4,5,6,7,8,9;数组元素的赋值与普通变量相同。可以把数组元素像普通变量一样使用。121第3讲 单片机C语言开发基础2.二维数组C语言

44、允许使用多维数组,最简单的多维数组是二维数组。其一般表达形式如下: 类型说明符 数组名下标1下标2;示例如下: Unsigned char x34; /定义无符号字符型二 维数组,第二个下标表示列 二维数组的赋值表达方法可以采用以下几种方式。 (1)按存储顺序整体赋值,这是一种比较直观的赋值方式,示例如下:122第3讲 单片机C语言开发基础 int 34=0,1,2,3,4,5,6,7,8,9,10,11; 如果是全部元素赋值,可以不指定行数,即 int 4=0,1,2,3,4,5,6,7,8,9,10,11;(2)按每行分别赋值。为了能更直观的给二维数组赋值,可以按每行分别赋值,这时要用 标

45、明,没有说明的部分默认为0,示例如下: int 34=0,1,2,3, 4,5,6,7, 8/最后三个元素被默认为0123第3讲 单片机C语言开发基础 3.字符数组用来存放字符型数据的数组称为字符数组。与整型数组一样,字符数组也可以在定义时进行初始化赋值。示例如下: char a8=B,e,i,-,J,i,n,g;上述语句定义了字符型数组,它有a0-a7共有8个元素,每个元素都是字符型变量。还可以用字符串的形式来对全体字符数组进行赋值,示例如下: char str =“Now,Temperature is:”;或者写成更简洁形式: char str =“Now,Temperature is:”

46、;124第3讲 单片机C语言开发基础注意:字符串是以0作为结束标志的。所以,当把一个字符串存入数组时,也把结束标志0存入了数组。因此,上面定义的字符数组”str20”最后一个元素不是“:”,而是0。 4.数组元素的引用 数组必须先定义,然后才能使用。在C语言中只能逐个引用数组元素。125第3讲 单片机C语言开发基础3.5.2 实例24:用字符型数组控制P0口8位LED流水点亮 本例用字符型数组控P0口8位LED流水点亮,硬件电路图如3.12所示。 1.实现方法 只要把流水点亮P0口8位LED的控制码赋给一个数组,再依次引用数组元素,并送P0口显示即可。本例使用无符号字符型数组,定义如下: un

47、signed char code Tab = 0 xfe,0 xfd,0 xfb,0 xf7,0 xef,0 xdf,0 xbf,0 x7f; 因为上述数组中的各个元素在使用过程中不发生变化,126第3讲 单片机C语言开发基础图3.12127第3讲 单片机C语言开发基础所以使用关键字“code”可以大大减小数组的存储空间。 2.程序设计 先建立文件夹“Ex24”,然后建立“Ex24”工程项目,最后建立源程序文件“Ex24.c”。输入源程序。 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到P0口的8位LED被流水点亮。128第3讲 单片机C语

48、言开发基础129第3讲 单片机C语言开发基础3.5.3 实例25:用P0口显示字符串常量 本例用字符型数组控P0口8位LED流水点亮,硬件电路图如3.12所示。 1.实现方法 只要把流水点亮P0口8位LED的控制码赋给一个数组,再依次引用数组元素,并送P0口显示即可。本例使用无符号字符型数组,定义如下: unsigned char code Tab = 0 xfe,0 xfd,0 xfb,0 xf7,0 xef,0 xdf,0 xbf,0 x7f; 因为上述数组中的各个元素在使用过程中不发生变化,130第3讲 单片机C语言开发基础4.6 C语言的指针 指针是C语言中的一个重要概念,也是C语言的

49、一个重要特色。正确灵活的运用指针,可以有效地表示复杂的数据结构,动态的分配内存,方便地使用字符串,有效地使用数组。4.6.1 指针的定义和引用1.指针的概念 一个数据的“指针”就是它的地址。通过变量的地址能找到该变量在内存中的存储单元,从而能得到它的值。指针是一种特殊类型的变量。它具有一般变量的三个要素:名字、类型和值。指针的命名和一般变量的区别在于类型和值上。131第3讲 单片机C语言开发基础 (1)指针的值 指针存放的是某个变量在内存中的地址。被定义过的变量都有一个内存地址。如果一个指针存放了某个变量的地址,就称这个指针指向该变量。由此可见,指针本身具有一个内存地址。另外,它还存放了它所指

50、向的变量的地址值。 (2)指针的类型 指针的类型就是该指针指向的变量的类型。例如,一个指针指向int型变量,该指针就是int型指针。 (3)指针的定义格式 指针变量不同于整型或字符型等其它类型的数据,使用132第3讲 单片机C语言开发基础前必须将其定义为“指针类型”。指针定义的一般形式如下: 类型说明符 *指针名字 示例如下: int i;/定义一个整型变量 int *pointer;/定义整型指针,名字为pointer 可以用取地址运算符“&”使一个指针变量指向一个变量,例如: pointer=&i;/“&i表示取i的地址,将i的地址 存放在指针变量pointer中。133第3讲 单片机C语

51、言开发基础 在定义指针时要注意两点: (1)指针名字前的”*”表示该变量为指针变量。 (2)一个指针变量只能指向同一个类型的变量。 2.指针的初始化 在使用指针前必须初始化,一般格式如下: 类型说明符 指针变量=初始地址值; 未经初始化的指针变量严禁使用,否则会引起严重后果。 3.指针数组 指针可以指向某类变量,也可以指向数组。以指针变量为元素的数组称为指针数组。这些指针变量应具有相同的存134第3讲 单片机C语言开发基础储类型,并且指向的数据类型也必须相同。 指针数组定义的一般格式如下: 类型说明符 *指针数组名元素个数 示例如下: int *p2;/是含有两个指针的指针数组 指针数组的初始

52、化可以在定义时同时进行,示例如下: unsigned char a =0,1,2,3; unsigned char *p4=&a0,&a1,&a2,&a3; 4.指向数组的指针 一个变量有地址,一个数组元素也有地址,所以可以用一个指针指向一个数组元素。如果一个指针存放了某数组的135第3讲 单片机C语言开发基础第一个元素的地址,就是该指针是指向这一数组的指针。数组的指针即数组的起始地址。示例如下: unsigned char a =0,1,2,3; unsigned char *p; p=&a0; /将数组a的首地址存放在指针变量P 经上述定义以后,指针p就是数组a的指针。 C语言规定:数组名

53、代表数组的首地址,也就是第一个元素的地址。 引用数组元素可以用下标(a3),但是用指针速度更快,且占用内存少。这正是是用指针的优点和C语言的精华所在。136第3讲 单片机C语言开发基础 对于二维数组,C语言规定:如果指针p指向该二维数组的首地址(可以用a表示,也可以用&a00表示),那么pi+j指向的元素就是aij。这里i,j分别表示二维数组的第i行和第j列。137第3讲 单片机C语言开发基础3.6.2 实例26:用P0口显示指针运算结果 本例进行一个简单的指针运算“*p1+*p2,并用P0口显示运算结果,采用的电路图如图3-12所示。 1.实现方法 先对指针进行定义初始化,使指针p1和p2都

54、有特定的指向,再用指针运算符“*”取得两个指针所指变量的值,然后将两个值的和送P0口即可。 2.程序设计 先建立文件夹“Ex26”,然后建立“Ex24”工程项目,最后建立源程序文件“Ex26.c”。输入源程序。138第3讲 单片机C语言开发基础139第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到仿真效果。此时,P0.3、P0.5引脚LED处于熄灭状态,其余均被点亮,表明P0=0010 1000B=0 x28=2x16+8=40,与预期的“25+15”相同。140第3讲 单片机C语言开发基础3.6.3 实例27:

55、用指针数组控制P0口8位LED流水点亮 本例使用指针数组控制P0口8位LED流水点亮,采用的电路图如图3-12所示。 1.实现方法 显然,指针数组的元素必须为流水灯控制码的地址。可先定义如下控制码组: unsigned char code Tab=0 xfe,0 xfd,0 xfb,0 xf7,0 xef,0 xdf,0 xbf,0 x7f; 然后将元素的地址一次存入如下指针数组: 141第3讲 单片机C语言开发基础 unsignedchar*p = &Tab0,&Tab1,&Tab2,&Tab3,&Tab4,&Tab5, &Tab6,&Tab7; 最后利用指针运算符“*”取得各个指针所指的值

56、,并送P0口即可。 2.程序设计 先建立文件夹“Ex27”,然后建立“Ex24”工程项目,最后建立源程序文件“Ex27.c”。输入源程序。142第3讲 单片机C语言开发基础143第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到P0口位LED被流水点亮。144第3讲 单片机C语言开发基础3.6.4 实例28:用数组的指针控制P0口8位LED流水点亮 本例使用指针数组控制P0口8位LED流水点亮,采用的电路图如图3-12所示。 1.实现方法 先定义流水灯控制码组,再将数组名(数组的首地址)赋给指针。然后即可通过指针引

57、用数组的元素,从而控制8位LED的流水点亮。 2.程序设计 先建立文件夹“Ex28”,然后建立“Ex28”工程项目,最后建立源程序文件“Ex28.c”。输入源程序。145第3讲 单片机C语言开发基础146第3讲 单片机C语言开发基础 3.用Proteus软件仿真 经keil软件编译通过后,利用Proteus软件仿真。启动仿真可以看到P0口8位LED显示出更为丰富的流水花样。147第3讲 单片机C语言开发基础4.7 C语言的函数 一个C语言程序可以由一个主函数main()和若干个其他函数构成。主函数调用其他函数,其他函数也可以相互调用,但其他函数不能调用主函数。4.7.1 函数的定义与调用1.函数的定义 从函数的形式看,函数可以分为无参数函数和有参数函数。前者在被调用时没有参数传递,后者在被

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论