第5章单片机的C语言程序设计_第1页
第5章单片机的C语言程序设计_第2页
第5章单片机的C语言程序设计_第3页
第5章单片机的C语言程序设计_第4页
第5章单片机的C语言程序设计_第5页
已阅读5页,还剩83页未读 继续免费阅读

下载本文档

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

文档简介

1、1/89第五章第五章 单片机的单片机的C语言程序设语言程序设计计 及仿真调试及仿真调试本章学习目标本章学习目标掌握单片机掌握单片机C语言程序中的常用功能语言程序中的常用功能掌握掌握Keil C的程序设计的程序设计掌握掌握STC15F2K60S2单片机单片机C语言程序调试过程语言程序调试过程2/89汇编语言和汇编语言和C语言的选择问题语言的选择问题设计规模较小的嵌入式应用系统时,可以使用设计规模较小的嵌入式应用系统时,可以使用汇编语言。因为代码一般不长,且较简单。当汇编语言。因为代码一般不长,且较简单。当程序比较复杂,且没有很好的注释时,使用汇程序比较复杂,且没有很好的注释时,使用汇编编程的可读

2、性和可维护性会很差,代码的可编编程的可读性和可维护性会很差,代码的可重性也比较低。重性也比较低。使用使用C语言编程,编写简单、直观易读、便于语言编程,编写简单、直观易读、便于维护、通用性好。在控制任务比较复杂或者具维护、通用性好。在控制任务比较复杂或者具有大量运算的系统中,有大量运算的系统中,C语言优势明显。由于语言优势明显。由于模块化,用模块化,用C语言编写的程序具有很好的可移语言编写的程序具有很好的可移植性。植性。3/895.1 5.1 单片机单片机C C语言程序中的常用功能语言程序中的常用功能一、逻辑运算和位运算一、逻辑运算和位运算1、逻辑运算符、逻辑运算符按逻辑运算符用于逻辑运算,包括

3、与(按逻辑运算符用于逻辑运算,包括与(&)、或)、或(|)、非()、非(!)三种。)三种。对于使用逻辑运算符的表达式,返回对于使用逻辑运算符的表达式,返回0表示表示“假假”,返回,返回1表示表示“真真”。4/89与运算符(与运算符(&)功能:两个条件同时满足时(即两个条件都为功能:两个条件同时满足时(即两个条件都为真时),结果才为真。真时),结果才为真。如一个程序在同时满足条件如一个程序在同时满足条件a10和和b=7时,时,必须执行某些操作,应使用关系运算符和逻辑必须执行某些操作,应使用关系运算符和逻辑与运算符(与运算符(&)来写这个条件的代码。)来写这个条件的代码。可

4、写为:可写为: (a10) & (b=7);5/89或运算符(或运算符(|)功能:检查两个条件中是否有一个为真的运算功能:检查两个条件中是否有一个为真的运算符,只要有一个条件为真,运算结果就为真。符,只要有一个条件为真,运算结果就为真。上例改为:如果任一语句为真,程序需执行某上例改为:如果任一语句为真,程序需执行某些操作,则条件代码如下:些操作,则条件代码如下: (a10) | (b=7);6/89逻辑非运算符(逻辑非运算符(!)功能功能:表示对表达式的真值取反。表示对表达式的真值取反。例如,如果变量例如,如果变量s小于小于10,程序需执行某些操,程序需执行某些操作,则条件代码如下:作

5、,则条件代码如下: (s=10) /s不大于等于不大于等于107/892、位运算符、位运算符很多系统程序常要求进行位(很多系统程序常要求进行位(bit)运算或处理。)运算或处理。语言提供了语言提供了六种六种位运算符:位运算符:按位与(按位与(&)、按位或()、按位或(|)、按位异或()、按位异或()、)、取反(取反()、左移()、左移()。)。8/89(1)按位)按位“与与”运算运算按位与运算符按位与运算符“&”是双目运算符。是双目运算符。功能是功能是参与运算的两数各对应的二进制位相与。参与运算的两数各对应的二进制位相与。只有对应的两个位均为只有对应的两个位均为1时,结果位才为

6、时,结果位才为1,否则,否则为为0。例如,例如,9&5 00001001&0000010100000001按位与运算通常用来对某些位清按位与运算通常用来对某些位清0或保留某些位。或保留某些位。例如把例如把a 的高八位清的高八位清0,保留低八位,保留低八位 可用可用 a&255 (255的二进制数为的二进制数为0000000011111111)。9/89(2)按位)按位“或或”运算运算按位或运算符按位或运算符“|”是双目运算符。是双目运算符。功能是功能是参与运算的两数各对应的二进制位相或。参与运算的两数各对应的二进制位相或。只要对应的两个位有一个为只要对应的两个位有一个为

7、1时,结果位就为时,结果位就为1。例如,例如,9|5 00001001|00000101=00001101 (十进制为十进制为13)或运算通常用来对某些位置或运算通常用来对某些位置1。10/89(3)按位)按位“异或异或”运算运算按位异或运算符按位异或运算符“”是双目运算符。是双目运算符。功能是功能是参与运算的两数各对应的二进制位相异或。参与运算的两数各对应的二进制位相异或。当两个对应的位相异时,结果为当两个对应的位相异时,结果为1。例如,例如,95 0000100100000101 00001100 (十进制为十进制为12)异或运算通常用来对某些位取反。异或运算通常用来对某些位取反。11/8

8、9(4)求反运算)求反运算求反运算符求反运算符“”为单目运算符,具有右结合性。为单目运算符,具有右结合性。功能是功能是对参与运算的数的各二进制位按位求反。对参与运算的数的各二进制位按位求反。例如,例如,9 (0000000000001001) 结果为:结果为:111111111111011012/89(5)左移运算)左移运算左移运算符左移运算符“”是双目运算符。是双目运算符。功能是功能是把把“”左边的运算数的各二进制位全部左边的运算数的各二进制位全部左移若干位,由左移若干位,由“”右边的数指定移动的位数,右边的数指定移动的位数,高位丢弃,低位补高位丢弃,低位补0。例如:例如:a”是双目运算符。

9、是双目运算符。功能是功能是把把“”左边的运算数的各二进制位全部右移左边的运算数的各二进制位全部右移若干位,若干位,“”右边的数指定移动的位数。右边的数指定移动的位数。例如,设例如,设 a=15,a2 000001111右移为右移为00000011(十进制十进制3)。 对于有符号数,在右移时,符号位将随同移动。对于有符号数,在右移时,符号位将随同移动。 当为正数时,最高位补当为正数时,最高位补0,而为负数时,符号位为,而为负数时,符号位为 1,最高位是补,最高位是补0或是补或是补1 取决于编译系统的规定。取决于编译系统的规定。14/89二、预处理二、预处理 以以“#”号开头的命令是预处理命令。语

10、言提号开头的命令是预处理命令。语言提供了多种预处理功能,如宏定义供了多种预处理功能,如宏定义#define、文件包、文件包含含#include、条件编译等。、条件编译等。 合理地使用预处理功能,可以使得编写的程序合理地使用预处理功能,可以使得编写的程序便于阅读、修改、移植和调试,也利于模块化程便于阅读、修改、移植和调试,也利于模块化程序设计。下面介绍常用的预处理功能。序设计。下面介绍常用的预处理功能。15/891、宏定义、宏定义(define)在语言源程序中允许用一个标识符来表示一个在语言源程序中允许用一个标识符来表示一个字符串,称为宏。被定义为宏的标识符称为宏名。字符串,称为宏。被定义为宏的

11、标识符称为宏名。在编译预处理时,对程序中所有出现的宏名,都在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为宏代换或宏用宏定义中的字符串去代换,这称为宏代换或宏展开。宏代换是由预处理程序自动完成的。在展开。宏代换是由预处理程序自动完成的。在语言中,宏分为语言中,宏分为有参数有参数和和无参数无参数两种。两种。16/89(1)无参宏定义)无参宏定义无参宏的宏名后不带参数。其定义的一般形式为:无参宏的宏名后不带参数。其定义的一般形式为: #define 标识符标识符 字符串字符串其中,标识符为所定义的宏名。字符串可以是常其中,标识符为所定义的宏名。字符串可以是常数、表达式、格

12、式串等。符号常量的定义就是一数、表达式、格式串等。符号常量的定义就是一种无参宏定义。此外,常对程序中反复使用的表种无参宏定义。此外,常对程序中反复使用的表达式进行宏定义。如要终止宏定义,可使用达式进行宏定义。如要终止宏定义,可使用# undef命令。命令。17/89(2)带参宏定义)带参宏定义在宏定义中的参数称为形式参数,在宏调用中的在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。不仅要宏展开,而且要用实参去代换形参。带参宏定义的一般形式为:带参宏定义的一般形式为: #defin

13、e 宏名宏名(形参表形参表) 字符串字符串18/89在字符串中含有各个形参。带参宏调用的一般在字符串中含有各个形参。带参宏调用的一般形式为:形式为: 宏名宏名(实参表实参表);例如:例如:#define MAX(a,b) (ab)?a:b /取取a和和b的最大数的最大数19/892、文件包含(、文件包含(include)文件包含的一般形式为:文件包含的一般形式为: #include 文件名文件名功能是功能是把指定的文件插入该命令行位置取代该把指定的文件插入该命令行位置取代该命令行,命令行, 从而把指定的文件和当前的源程序从而把指定的文件和当前的源程序文件连成一个源文件。文件连成一个源文件。20

14、/89说明以下几点:说明以下几点: 包含命令中的文件名可以用双引号括起来,也可包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如:以用尖括号括起来。例如: #include stdio.h #include 二者的区别二者的区别:使用尖括号表示在包含文件目录:使用尖括号表示在包含文件目录中去查找(包含目录由用户在开发环境中设置),中去查找(包含目录由用户在开发环境中设置),而不在源文件目录去查找;使用双引号则表示首先而不在源文件目录去查找;使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目在当前的源文件目录中查找,若未找到才到包含目录中去查找。录中去查找。21/89

15、3、条件编译、条件编译条件编译就是按不同的条件去编译不同的程序条件编译就是按不同的条件去编译不同的程序部分,从而产生不同的目标代码文件。部分,从而产生不同的目标代码文件。条件编译对于程序的移植和调试(可以分段调条件编译对于程序的移植和调试(可以分段调试)非常有用。特别是在操作系统的裁减中,试)非常有用。特别是在操作系统的裁减中,经常使用条件编译。经常使用条件编译。22/89(1)第一种形式:)第一种形式: #ifdef 标识符标识符 程序段程序段1 #else 程序段程序段2 #endif功能是功能是:如果标识符已被:如果标识符已被#define命令定义过,命令定义过,则对程序段则对程序段1进

16、行编译;否则对程序段进行编译;否则对程序段2进行编进行编译。如果没有程序段译。如果没有程序段2(它为空),本格式中(它为空),本格式中的的#else可以没有。可以没有。23/89(2)第二种形式:)第二种形式: #ifndef 标识符标识符 程序段程序段1 #else 程序段程序段2 #endif功能是功能是:如果标识符未被:如果标识符未被#define命令定义过命令定义过则对程序段则对程序段1进行编译,否则对程序段进行编译,否则对程序段2进行编进行编译。这与第一种形式的功能正相反。译。这与第一种形式的功能正相反。24/89(3)第三种形式:)第三种形式: #if 常量表达式常量表达式 程序段

17、程序段1 #else 程序段程序段2 #endif功能是功能是,如果常量表达式的值为真(非,如果常量表达式的值为真(非0),),则对程序段则对程序段1进行编译,否则对程序段进行编译,否则对程序段2进行编进行编译。因此可以使程序在不同条件下,完成不同译。因此可以使程序在不同条件下,完成不同的功能。的功能。25/895.2 Keil C 和和 ANSI C一、一、Keil C51扩展关键字扩展关键字C51有以下扩展关键字(有以下扩展关键字(共共19个个):): _at_、sbit、sfr、bit、sfr16、idata、bdata、xdata、pdata、data、code、alien、small

18、、compact、 large、using、reentrant、interrupt、_task_26/891、内存区域(、内存区域(Memory Areas):):(1)程序存储器:)程序存储器:code:程序存储区。可以使用:程序存储区。可以使用code定义表格定义表格常数。常数。(2)内部)内部RAM:用以下关键字说明:用以下关键字说明:data:直接寻址区,内部:直接寻址区,内部RAM的低的低128字节,字节,地址范围为地址范围为00H7FH。idata:间接寻址区,包括整个内部:间接寻址区,包括整个内部RAM区,区,256字节,地址范围为字节,地址范围为00H0FFH。bdata:可位

19、寻址区,地址范围为:可位寻址区,地址范围为20H2FH。27/89(3)外部数据存储器:外部)外部数据存储器:外部RAM视使用情况可视使用情况可由以下关键字标识:由以下关键字标识:xdata:可指定多达:可指定多达64KB的外部直接寻址区,的外部直接寻址区,地址范围地址范围0000H0FFFFH。pdata:能访问:能访问1页(页(256Bytes)的外部)的外部RAM(很少用)。(很少用)。28/89存储类型的指定:存储类型的指定: 变量或参数的存储类型可由存储模式指定变量或参数的存储类型可由存储模式指定缺省类型,也可由关键字缺省类型,也可由关键字code、data、idata、xdata、

20、pdata直接声明指定。直接声明指定。例如:例如: data buffer; char code array =“hello!”; unsigned char xdata arr1044;29/89(4)特殊功能寄存器()特殊功能寄存器(SFR)STC15F2K60S2单片机的特殊功能寄存器单片机的特殊功能寄存器(SFR)寻址区,用来控制定时器、计数器、)寻址区,用来控制定时器、计数器、串口、串口、I/O及其他部件。及其他部件。为了支持为了支持SFR及其可寻址位的声明,引入了及其可寻址位的声明,引入了sfr、sbit等关键词。等关键词。30/89sfr:字节寻址。语法如下:字节寻址。语法如下:

21、 sfr sfr_name=int_constant;如如 sfr P0=0 x80; 0 x80为为P0口的地址,口的地址,“=”后为常数,并且这后为常数,并且这个个常数必须在特殊功能寄存器的地址范围内,位于常数必须在特殊功能寄存器的地址范围内,位于0 x80到到0 xFF之间。之间。31/89sfr16:字寻址:字寻址如如sfr16 DPTR=0 x82; 指定指定DPTR的地址的地址DPL=0 x82,DPH=0 x83。sbit:位寻址:位寻址 用于声明可位寻址的特殊功能寄存器的位变用于声明可位寻址的特殊功能寄存器的位变量。量。32/89sbit可以有下面声明方法:可以有下面声明方法:

22、方法方法1:sbit bitname=sfr_namebit_number; 其中,其中,sfr_name必须是已定义的必须是已定义的SFR的名字的名字, bit_number是位号(是位号(07)。)。 如:如:sbit CY=PSW7;/定义定义CY为为PSW的第的第7位。位。方法方法2:sbit bitname=sfr_addressbit_number; 其中,其中,sfr_address是是SFR所在的地址(所在的地址(0 x800 xff), bit_number是位号(是位号(07)。)。 如:如:sbit OV=0 xD02;/定义定义PSW中的中的OV位位方法方法3:sbit

23、 bitname=bit_address; 其中,其中,bit_address是位地址。是位地址。 如:如:sbit EA=0 xAF;/第第0 xAF位为位为EA33/89对于大多数对于大多数8051内核单片机,内核单片机,Keil提供了一个提供了一个包含所有特殊功能寄存器和它们的位的定义的包含所有特殊功能寄存器和它们的位的定义的头文件头文件reg51.h。通过包含头文件可以很容易。通过包含头文件可以很容易的进行新的扩展。的进行新的扩展。附录附录C提供了提供了STC15F2K60S2单片机的头文件单片机的头文件stc15.h的内容,其中包含了标准的内容,其中包含了标准8051单片机单片机寄存

24、器的定义,编程时只需包含这一个文件即寄存器的定义,编程时只需包含这一个文件即可。该文件可以从可。该文件可以从中下载。中下载。34/892、_at_关键字关键字 若要实现变量的绝对定位(称为绝对变量),若要实现变量的绝对定位(称为绝对变量),可以直接在数据定义后加上可以直接在数据定义后加上“_at_ 常数地址常数地址”即即可。可。 注意:注意:(1)绝对变量不能被初始化;)绝对变量不能被初始化;(2)bit型函数及变量不能用型函数及变量不能用_at_指定。指定。35/89例如:例如: unsigned char idata ADCdata _at_ 0 x40; /指定指定ADCdata变量在变

25、量在40H处处 unsigned char xdata buffer20 _at_ 0 x0010; /指定指定buffer数组从数组从XRAM的的0010H单元开始单元开始36/893、存储模式、存储模式存储模式决定了没有明确指定存储类型的变量时,存储模式决定了没有明确指定存储类型的变量时,函 数 参 数 等 的 缺 省 存 储 区 域 , 有函 数 参 数 等 的 缺 省 存 储 区 域 , 有 S m a l l 、Compact和和Large三种模式。三种模式。指定存储模式图图5-1 指定存储模式指定存储模式 37/89(1)Small模式模式在该模式中所有变量都默认位于在该模式中所有

26、变量都默认位于单片机内部数单片机内部数据存储器据存储器,这和使用,这和使用data指定存储器类型的方指定存储器类型的方式一样。此模式访问变量的效率很高,但所有式一样。此模式访问变量的效率很高,但所有的数据对象和堆栈必须适合内部的数据对象和堆栈必须适合内部RAM堆栈的堆栈的大小。如果将变量都配置在内部数据存储器内,大小。如果将变量都配置在内部数据存储器内,Small模式是最佳选择。模式是最佳选择。该模式的优点是访问速度快,缺点是空间有限,该模式的优点是访问速度快,缺点是空间有限,只适用于小程序。只适用于小程序。38/89(2)Compact模式模式所有缺省变量均位于所有缺省变量均位于外部外部RA

27、M区的一页内区的一页内(256字节),字节),这和使用这和使用pdata指定存储器类指定存储器类型一样,在型一样,在STARTUP.A51文件中说明,也可文件中说明,也可用用pdata指定。指定。该模式空间比该模式空间比Small宽裕,速度比宽裕,速度比Small慢,慢,比比Large快,是一种中间状态。快,是一种中间状态。39/89(3)Large模式模式所有缺省变量可放在所有缺省变量可放在多达多达64KB的外部的外部RAM区区,这和使用这和使用xdata指定存储器类型一样,使用数指定存储器类型一样,使用数据指针据指针DPTR进行寻址。通过数据指针访问外进行寻址。通过数据指针访问外部数据存储

28、器的效率较低,特别是当变量为部数据存储器的效率较低,特别是当变量为2个字节或更多字节时。该模式的数据访问比个字节或更多字节时。该模式的数据访问比Small和和Compact产生更多的代码。产生更多的代码。优点是空间大,可存变量多,缺点是速度较慢。优点是空间大,可存变量多,缺点是速度较慢。40/89数据类型数据类型含含 义义位数(位数(bit)字节数(字节数(byte)取值范围取值范围bit*位型位型11/80或或1signed char带符号字符型带符号字符型81-128+127unsigned char无符号字符型无符号字符型810255enum8/161 or 2-128+127or-32

29、768+32767signed short带符号短型带符号短型162-32768+32767unsigned short无符号短型无符号短型162065535signed int带符号整型带符号整型162-32768+32767unsigned int无符号整型无符号整型162065535signed long带符号长整型带符号长整型324-2147483648+2147483647unsigned long无符号长整型无符号长整型32404294967295float浮点型浮点型324+1.175494E38+3.402823E+38sbit*11/80-1sfr*810 x80-0 xff

30、sfr16*1620 x800 xff4、变量或数据类型、变量或数据类型表表5-1 C51数据类型数据类型41/89C51提供以下几种扩展数据类型:提供以下几种扩展数据类型: bit:位变量值为:位变量值为0或或1。 sbit:从字节中定义的位变量(:从字节中定义的位变量(0或或1)。)。 sfr:sfr字节地址(字节地址(0 x800 xff)。)。 sfr16:sfr字地址(字地址(0 x800 xff,其实是占用,其实是占用 两个连续的地址)。两个连续的地址)。 其余数据类型如:其余数据类型如:char、enum、short、int、long、float等与等与ANSI C相同。下面着相

31、同。下面着重介绍位变量及其声明。重介绍位变量及其声明。42/89(1)bit型变量型变量bit型变量可用于变量类型和函数声明、函数返回型变量可用于变量类型和函数声明、函数返回值等,存储于内部值等,存储于内部RAM的的20H2FH单元中。单元中。注意:注意: 1)使用禁止中断()使用禁止中断(#pragma disable)或包含明确)或包含明确的寄存器组切换(的寄存器组切换(using n)的函数不能返回位值,)的函数不能返回位值,否则,编译器会识别出来并产生一个错误信息。否则,编译器会识别出来并产生一个错误信息。 2)位不能声明为一个指针。如)位不能声明为一个指针。如bit *bit_poi

32、ter;是错;是错误的。误的。 3)不能有)不能有bit数组如:数组如:bit arr5;是错误的。;是错误的。43/89(2)可位寻址区说明)可位寻址区说明使用使用sbit声明可独立访问可位寻址对象的位。声明可独立访问可位寻址对象的位。sbit声明要求基址对象的存贮器类型为声明要求基址对象的存贮器类型为“bdata”,否则只有绝对的位声明方法是合,否则只有绝对的位声明方法是合法的。法的。位的位置(位的位置(操作符号后的数字)的最大值操作符号后的数字)的最大值依赖于指定的基类型依赖于指定的基类型对于对于char/uchar而言是而言是07,对于对于int/uint/short/ushort而言

33、是而言是015,对于对于long/ulong而言是而言是031。44/89下面举例说明位寻址的声明方法。下面举例说明位寻址的声明方法。例如,例如, int bdata bittest _at_ 0 x20; /也可以省略也可以省略“_at_ 0 x20” sbit bit0bittest 0; /0 x20单元的第单元的第0位位 sbit bit15= bittest 15; /0 x21单元的第单元的第7位位注意注意:可位寻址对象的位的声明只能放到:可位寻址对象的位的声明只能放到main函函数的外部,作为全局变量使用,否则,编译会出数的外部,作为全局变量使用,否则,编译会出错。错。45/89

34、二、二、扩展扩展I/O口的使用口的使用 STC15F2K60S2单片机除了芯片上的单片机除了芯片上的I/O口口外,还可在片外扩展外,还可在片外扩展I/O端口。端口。 由于使用由于使用C语言访问外部语言访问外部I/O时用到指针的功时用到指针的功能,因此,首先介绍能,因此,首先介绍Keil C51的指针。的指针。 46/891、Keil C51指针指针Keil C51支持一般指针(支持一般指针(Generic Pointer)和存储器指针(和存储器指针(Memory Specific Pointer)。)。一般指针的声明和使用均与标准一般指针的声明和使用均与标准C相同,同时相同,同时还可以说明指针

35、的存储类型。还可以说明指针的存储类型。47/89例如,下面的语句都声明例如,下面的语句都声明pt为指向保存在外部为指向保存在外部RAM中中unsigned char数据的指针,但数据的指针,但pt本身本身的保存位置却不同:的保存位置却不同: unsigned char xdata *pt; /pt本身依存储模式存放本身依存储模式存放 unsigned char xdata * data pt; /pt被保存在内部被保存在内部RAM中中 unsigned char xdata * xdata pt; /pt被保存在外部被保存在外部RAM中中48/89一般指针本身用一般指针本身用3个字节存放,分别

36、为存储器个字节存放,分别为存储器类型,高位偏移量和低位偏移量。基于存储器类型,高位偏移量和低位偏移量。基于存储器的指针,说明时即指定了存储类型,例如:的指针,说明时即指定了存储类型,例如: char data * str; /str指向指向data区中区中char型数据型数据 int xdata * pow; /pow指向外部指向外部RAM的的int型整数型整数这种指针存放时,只需一个字节或这种指针存放时,只需一个字节或2个字节就个字节就够了,因为只需存放偏移量。够了,因为只需存放偏移量。49/89关于堆栈指针关于堆栈指针SP 的设定的设定一般情况下,用户不需要在一般情况下,用户不需要在C语言

37、程序中修改堆栈指针语言程序中修改堆栈指针SP,但要关心一下,但要关心一下SP的位置。的位置。C51为变量分配好内部为变量分配好内部RAM后,将后,将SP放在第一个空闲的内部放在第一个空闲的内部RAM处,可以处,可以在编译后生成的在编译后生成的.m51文件中观察到栈顶的位置,一般文件中观察到栈顶的位置,一般程序编译连接成功后要习惯性地看一下程序编译连接成功后要习惯性地看一下.m51文件,看文件,看一下是不是有足够的栈空间可用。一下是不是有足够的栈空间可用。 另外,另外,C51是在是在startup.A51中设置中设置SP指针的,用指针的,用CODE选项生成的汇编代码中是找不到这段代码的。选项生成

38、的汇编代码中是找不到这段代码的。startup.A51是是C51的初始化代码,单片机复位后先执的初始化代码,单片机复位后先执行这段代码,完成初始化后由它调用行这段代码,完成初始化后由它调用main( )函数。特函数。特殊需要时,可以修改这段代码,然后连接到用户的程殊需要时,可以修改这段代码,然后连接到用户的程序中去。序中去。50/892、外部扩展、外部扩展I/O口的访问口的访问在在C51中有两种方法访问外部中有两种方法访问外部I/O端口。端口。 方法方法1:使用自定义指针。:使用自定义指针。 由于片外由于片外I/O端口与片外存储器统一编址,所端口与片外存储器统一编址,所以可以定义以可以定义xd

39、ata类型的指针访问外部类型的指针访问外部I/O端口。端口。51/89例如,某单片机应用系统中,使用例如,某单片机应用系统中,使用8255扩展扩展I/O端口,采用线选法对端口,采用线选法对8255进行地址译码,进行地址译码,单片机的单片机的P 2.7(A15)接)接8255的片选引脚,的片选引脚, 8255的命令字地址为的命令字地址为7FF3H, PA口地址为口地址为7FF0H, PB口地址为口地址为7FF1H, PC口地址为口地址为7FF2H,访问访问8255的的C程序如下:程序如下:52/89写端口程序:写端口程序: char xdata *com8255; /定义指向外部存储区的指针定义

40、指向外部存储区的指针 com8255=0 x7ff3; /使指针指向使指针指向8255的控制口地址的控制口地址7FF3H *com8255=0 x81; /输出输出81H到端口到端口 以上以上C程序相当于下面的汇编语言程序:程序相当于下面的汇编语言程序: MOV DPTR,#7FF3H MOV A,#81H MOVX DPTR,A 53/89读端口程序:读端口程序: char xdata *com8255; /定义指针定义指针 com8255=0 x7ff0; /使指针指向使指针指向8255的的PA口地址口地址7FF0H char i; i=*com8255; /读读PA端口到变量端口到变量i

41、54/89方法方法2:使用:使用C51预定义指针。预定义指针。 为了方便地访问外部存储器及为了方便地访问外部存储器及I/O端口,在端口,在C51中的中的absacc.h头文件做了如下定义,利用头文件做了如下定义,利用这这些定义可以方便地访问外部些定义可以方便地访问外部I/O端口。端口。#define CBYTE (unsigned char volatile code *) 0)#define DBYTE (unsigned char volatile data *) 0)#define PBYTE (unsigned char volatile pdata *) 0)#define XBYT

42、E (unsigned char volatile xdata *) 0)55/89例如:例如:#include #define PORTA XBYTE 0 x7ff0 /其中,其中,PORTA为程序定义的为程序定义的I/O端口名称,端口名称, 内的内容内的内容/7ff0H为为PORTA的地址的地址void main(void) char a; PORTA=0 x81; /*输出输出81H到端口到端口7ff0H a=PORTA; /读端口读端口7ff0H到变量到变量a 56/89三、三、Keil C51函数函数 C51的函数声明对的函数声明对ANSI C作了扩展,具体包作了扩展,具体包括:括:

43、1、中断函数声明、中断函数声明中断函数通过使用中断函数通过使用interrupt关键字和关键字和中断号中断号(031)来声明。中断号告诉编译器中断服)来声明。中断号告诉编译器中断服务程序的入口地址。务程序的入口地址。57/89STC15F2K60S2单片机的中断号单片机的中断号及中断服务程序及中断服务程序入口地址如表所入口地址如表所示。示。 中断号中断号中断源中断源入口地址入口地址0外部中断外部中断INT00003H1T0溢出中断溢出中断000BH2外部中断外部中断INT10013H3T1溢出中断溢出中断001BH4串行口串行口UART1中断中断0023H5ADC中断中断002BH6LVD中断

44、中断0033H7PCA中断中断003BH8串行口串行口UART2中断中断0043H9SPI中断中断004BH10外部中断外部中断INT20053H11外部中断外部中断INT3005BH12T2溢出中断溢出中断0063H16外部中断外部中断INT40083H表表5-2中断号及中断服务程序入口地址中断号及中断服务程序入口地址58/89例如,串行口例如,串行口1的中断函数可以声明如下:的中断函数可以声明如下: void UART1_ISR (void) interrupt 4 using 1 /* 中断服务程序的代码中断服务程序的代码 */ 上述代码声明了串行口上述代码声明了串行口1中断服务函数。其

45、中中断服务函数。其中,interrupt 4说明是串行口说明是串行口1的中断,的中断,using 1指明采用指明采用工作寄存器区工作寄存器区1区,区,using 1在中括号中,说明该段可在中括号中,说明该段可以省略。其他中断函数的定义与此类似。中断函数具以省略。其他中断函数的定义与此类似。中断函数具体是哪个中断的函数,与中断号有关,而与函数名无体是哪个中断的函数,与中断号有关,而与函数名无关关 。59/892、指定工作寄存器区、指定工作寄存器区当需要指定函数中使用的工作寄存器区时,使当需要指定函数中使用的工作寄存器区时,使用关键字用关键字using后跟一个后跟一个0到到3的数,对应着工的数,对

46、应着工作寄存器作寄存器0到到3区。区。例如,在下面的函数中使用了工作寄存器例如,在下面的函数中使用了工作寄存器1区区(相当于(相当于PSW.4=0,PSW.3=1):): unsigned char GetKey(void) using 1 /*用户程序代码用户程序代码*/ 60/893、指定存储模式、指定存储模式用户可以使用用户可以使用small,compact 及及large说明说明存储模式。存储模式。例如:例如: void fun1(void) small 提示:提示:small说明的函数内部变量全部使用内部说明的函数内部变量全部使用内部RAM。关键的、经常性的、耗时的地方可以这样关键的

47、、经常性的、耗时的地方可以这样声明,以提高运行速度。声明,以提高运行速度。61/894、函数的参数传递规则、函数的参数传递规则最多只能有最多只能有3个参数通过寄存器传递,规律如个参数通过寄存器传递,规律如表表5-3所示。所示。参数数目参数数目charintlong, float一般指针一般指针1R7R6 & R7R4R7R1R32R5R4 & R5R4R7R1R33R3R2 & R3R1R3表表5-3 函数的参数传递规则函数的参数传递规则62/895、函数返回值的规定、函数返回值的规定函数返回值一律放于寄存器中,规则如表函数返回值一律放于寄存器中,规则如表5-4所示。所

48、示。返回值类型返回值类型寄存器寄存器说明说明bitCychar/unsigned char,1_byte指针指针R7单字节由单字节由R7返回返回int/unsigned int 2_byte指针指针R6,R7R6放高位,放高位,R7放低位放低位long&unsigned longR4R7R4放最高位,放最高位,R7放最低位放最低位floatR4R7IEEE标准标准 R7放符号位及阶码放符号位及阶码一般指针一般指针R1,R2,R3R3放存储空间码,放存储空间码,R2放高放高位,位,R1放低位放低位表表5-4 函数返回值的规定函数返回值的规定63/896、函数的重入、函数的重入可以在函数前

49、声明函数的可重入性,只对一个函数有可以在函数前声明函数的可重入性,只对一个函数有效。效。如果声明为不可重入的,说明该函数调用过程中将不如果声明为不可重入的,说明该函数调用过程中将不可被中断。可被中断。递归或可重入函数指定在主程序和中断中都可调用的递归或可重入函数指定在主程序和中断中都可调用的函数,容易产生问题。因为单片机和函数,容易产生问题。因为单片机和PC不同,不同,PC使使用堆栈传递参数,且静态变量以外的内部变量都在堆用堆栈传递参数,且静态变量以外的内部变量都在堆栈中;而单片机一般使用寄存器传递参数,内部变量栈中;而单片机一般使用寄存器传递参数,内部变量一般在一般在RAM中,函数重入时会破

50、坏上次调用的数据。中,函数重入时会破坏上次调用的数据。64/89可以用以下两种方法解决函数的重入问题:可以用以下两种方法解决函数的重入问题:第一种方法第一种方法: 在相应的函数前使用在相应的函数前使用“#pragma disable”声声明,即只允许主程序或中断之一调用该函数。明,即只允许主程序或中断之一调用该函数。第二种方法第二种方法: 将该函数说明为可重入的。如下:将该函数说明为可重入的。如下: void func(param.) reentrant;65/89Keil C51编译后将生成一个可重入变量堆栈,编译后将生成一个可重入变量堆栈,然后就可以模拟通过堆栈传递变量的方法。然后就可以模

51、拟通过堆栈传递变量的方法。因为单片机内部堆栈空间的限制,因为单片机内部堆栈空间的限制,C51没有像没有像大系统那样使用调用堆栈。一般在大系统那样使用调用堆栈。一般在C语言中调语言中调用过程时,会把过程的参数和过程中使用的局用过程时,会把过程的参数和过程中使用的局部变量入栈。部变量入栈。66/89为了提高效率,为了提高效率,C51没有提供这种堆栈,而是提供一种没有提供这种堆栈,而是提供一种压缩栈。每个过程被给定一个空间,用于存放局部变量。压缩栈。每个过程被给定一个空间,用于存放局部变量。过程中的每个变量都存放在这个空间的固定位置。当递过程中的每个变量都存放在这个空间的固定位置。当递归调用这个过程

52、时,会导致变量被覆盖。归调用这个过程时,会导致变量被覆盖。在某些实时应用中,非重入函数是不可取的。因为,函在某些实时应用中,非重入函数是不可取的。因为,函数调用时可能会被中断程序中断,而在中断程序中可能数调用时可能会被中断程序中断,而在中断程序中可能再次调用这个函数,所以再次调用这个函数,所以C51允许将函数定义成重入函允许将函数定义成重入函数。重入函数可被递归调用和多重调用,而不用担心变数。重入函数可被递归调用和多重调用,而不用担心变量被覆盖,因为每次函数调用时的局部变量都会被单独量被覆盖,因为每次函数调用时的局部变量都会被单独保存。因为这些堆栈是模拟的,重入函数一般都比较大,保存。因为这些

53、堆栈是模拟的,重入函数一般都比较大,运行起来也比较慢。运行起来也比较慢。67/89由于一般可重入函数由主程序和中断调用,所由于一般可重入函数由主程序和中断调用,所以通常中断程序使用与主程序不同的工作寄存以通常中断程序使用与主程序不同的工作寄存器组。器组。另外,对可重入函数,在相应的函数前面加上另外,对可重入函数,在相应的函数前面加上开关开关#pragma noaregs,以禁止编译器使用,以禁止编译器使用绝对寄存器寻址,可生成不依赖于寄存器组的绝对寄存器寻址,可生成不依赖于寄存器组的代码。代码。68/89四、四、 STC15F2K60S2单片机单片机C51程序框架程序框架#include “s

54、tc15.h” /* stc15.h为单片机寄存器定义头文件,具体内容参见附录为单片机寄存器定义头文件,具体内容参见附录C */void delay(long delaytime); /声明子函数,子函数可以有返回值声明子函数,子函数可以有返回值void main(void) /此处可存放应用系统的初始化代码此处可存放应用系统的初始化代码 while(1) /主程序循环主程序循环 /根据需要填入适当的内容根据需要填入适当的内容 delay(100); /可以调用用户自定义的子函数可以调用用户自定义的子函数 69/89/-各个子函数的声明各个子函数的声明-void delay(long dela

55、ytime)while(delaytime0) delaytime-; /子函数的实现代码子函数的实现代码/-各个中断函数的实现各个中断函数的实现-void INT0_ISR(void) interrupt 0 /外部中断外部中断0服务子函数服务子函数 /根据需要填入程序代码根据需要填入程序代码void T0_ISR(void) interrupt 1 /定时器定时器0中断服务子函数中断服务子函数 /根据需要填入程序代码根据需要填入程序代码void INT1_ISR(void) interrupt 2 /外部中断外部中断1服务子函数服务子函数 /根据需要填入程序代码根据需要填入程序代码void

56、 T1_ISR(void) interrupt 3 /定时器定时器1中断服务子函数中断服务子函数 /根据需要填入程序代码根据需要填入程序代码70/89void UART1_ISR(void) interrupt 4 /串口串口1中断服务子函数中断服务子函数 /根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零void ADC_ISR (void) interrupt 5 /ADC中断服务子函数中断服务子函数 /根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零void LVD_ISR (void) interrupt 6

57、/低电压检测中断子函数低电压检测中断子函数 /根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零void PCA_ISR (void) interrupt 7 /PCA中断子函数中断子函数 /根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零void UART2_ISR (void) interrupt 8 /串口串口2中断子函数中断子函数 /根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零void SPI_ISR (void) interrupt 9 /SPI中断子函数中断子函数 /

58、根据需要填入程序代码根据需要填入程序代码,注意中断请求标志的清零注意中断请求标志的清零71/89void INT2_ISR(void) interrupt 10 /外部中断外部中断2服务子函数服务子函数 /根据需要填入程序代码根据需要填入程序代码void INT3_ISR(void) interrupt 11 /外部中断外部中断3服务子函数服务子函数 /根据需要填入程序代码根据需要填入程序代码void T2_ISR(void) interrupt 12 /定时器定时器2中断服务子函数中断服务子函数 /根据需要填入程序代码根据需要填入程序代码void INT4_ISR(void) interru

59、pt 16 /外部中断外部中断4服务子函数服务子函数 /根据需要填入程序代码根据需要填入程序代码72/89【例【例5-1】编程实现通过延时函数,】编程实现通过延时函数,P1.0输出方波信号,并输出方波信号,并通过示波器观察程序输出波形的周期。通过示波器观察程序输出波形的周期。 #include “stc15.h” /STC15F2K60S2单片机寄存器定义头文件单片机寄存器定义头文件 sbit P10=P10;/定义定义P1.0引脚引脚 void delay(unsigned long cnt); /延时函数声明延时函数声明 void main(void) P10=1; while(1) /主

60、程序循环主程序循环 delay(60000); P10=P10; void delay(unsigned long cnt) /延时函数延时函数 while(cnt0) cnt-; 73/89 可以使用可以使用集成开发环境(集成开发环境(IDE)对单片机程序对单片机程序进行进行软件模拟调试软件模拟调试。由于此时无需任何硬件与开。由于此时无需任何硬件与开发,可以降低程序开发的成本,并且程序开发可发,可以降低程序开发的成本,并且程序开发可以在系统硬件完成之前开始。以在系统硬件完成之前开始。5.3 单片机单片机C语言程序调试语言程序调试74/89 模拟仿真调试的方法和过程与汇编语言模拟模拟仿真调试的方法和过程与汇编语言模拟仿仿真调试的过程相同。但是,真调试的过程相同。但是,软件模拟调试无法仿

温馨提示

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

最新文档

评论

0/150

提交评论