MCS51单片机C语言编程

更新时间:2024-05-20 01:37:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验二 MCS-51单片机C语言编程练习

一. 实验目的

1. 了解单片机的C51语言与汇编语言以及标准C语言的异同,掌握C51语言的基本语法知识以及特有的程序设计特点。

2. 掌握使用C51语言进行顺序、分支、循环结构的程序设计方法。

3. 能够使用C51语言,独立设计出具有一定综合性的单片机应用程序,并与汇编语言的相应程序进行比较,加深理解。

4. 对应用问题能抽象出数学模型,绘制软件程序的流程图,并能用C51语言实现。

二.预习与思考

1. 预习理论教材中“C51语言程序设计”的相关内容,掌握C51程序设计的基本方法、思路以及设计规范。

2. 预习理论教材中“C51程序设计”的相关例程。

3. 掌握单片机C51语言的调试方法,体会与标准C语言的异同。

4. 思考如何使用C51语言,对顺序、分支、循环结构的单片机应用程序进行设计,重点体会C51语言特有的设计方法与思想。

三. 实验原理

1. 单片机的C51语言简介

通常,将一些能够对MCS—51系列单片机进行硬件操作的C语言统称为C51语言。在众多的C51语言中,功能最强、最受用户欢迎的是德国KEIL公司的Keil C51语言。单片机应用系统的程序设计,既可以采用汇编语言,也可以采用C51语言,两者各具特色。其中,汇编语言是一种用助记符来代表机器语言的符号语言。因为它最接近机器语言,所以汇编语言对单片机的操作直接、简捷,编写的程序紧凑、执行效率较高。但是,不同种类的单片机其汇编语言存在一定的差异。在一种单片机上开发的应用程序,通常不能直接应用到另一种单片机芯片上,如果进行程序的移植,难度也比较大。与此同时,汇编语言开发的程序可读性较差,不容易理解,特别是当单片机应用系统的规模比较大时,汇编语言的编程工作量非常大,从而影响应用系统的开发效率。

相对而言,C51语言恰好可以克服汇编语言的一些缺欠。例如,C51语言可读性好、可移植性高,与自然语言比较接近,并且相同功能的程序使用C51语句的数量要远小于汇编语句。通常,C51语言的入门学习相对于汇编语言更容易,而且在C51语言的程序中还可以嵌套汇编语言,从而满足对执行效率或操作的一些特殊要求。因此在单片机应用系统的开发过程中,C51语言逐渐成为了主要的编程语言。

2. 单片机C51语言的数据类型

C51语言的数据类型,既有与ANSI C语言通用的数据类型,也有自己所特有的数据类型。C51语言的具体数据类型见表5-1所示。从表中可以看出C51语言增加了bit、sfr、sfr16、sbit四种新的数据类型,分别用于定义2进制变量、特殊功能寄存器变量、16位特殊功能寄存器变量以及特殊功能位。另外,C51语言还有自己特有的变量存储类型以及存储模式,这里就不一一详述,具体可以参考理论教材的相关内容。

表2-1 C51语言所支持的数据类型

3. C51语言对单片机的SFR以及存储器的访问

C51语言除了具有特殊的数据类型、存储类型以及存储模式外,C51语言还可以对SFR以及片内或片外的存储器单元进行直接访问。这里的SFR是指MCS-51单片机的特殊功能寄存器。8051单片机的SFR一共有21个,具体见表5-2所示。从表中可以看到,这么多的特殊功能寄存器,如果每一个都用数据类型sfr定义一遍再使用,就显得比较麻烦。那么如何不用定义,还能在C51语言中随时使用这21个特殊功能寄存器呢?方法也很简单,只要在每个C51程序中包含头文件或者或者或者中的任意一个,就可以在C51程序中任意使用这21个特殊功能寄存器。因为在这些头文件中已经将相应的特殊功能寄存器用数据类型sfr定义好了,所以当C51程序包含了上述的头文件以后就可以直接用SFR了,而不必再重新一个一个的来定义这些寄存器了。例如,给特殊功能寄存器P3口赋值为0xff,程序可以这样编写:

//-------------------------------------------------------------------

#include //包含21个特殊功能寄存器地址定义的头文件 void main( ) {

P3=0xff; //给P3口赋值为0xff }

//-------------------------------------------------------------------

另外,C51语言还可以直接访问片内或片外的存储单元,这时需要在程序中包含绝对地址访问头文件。这个头文件使得C51语言对存储器单元的访问变得更加简便,在头文件中提供了一些对存储单元进行访问的宏定义,具体如下: (1)CBYTE[data]:该宏定义代表对单片机的片内ROM单元进行访问。 (2)DBYTE[data]:该宏定义代表对单片机的片内RAM单元进行读写操作。 (3)XBYTE[data]:该宏定义代表对单片机的片外RAM单元进行读写操作。

在这里举一个例子:例如要从单片机片内ROM的30H单元中读出数据,给片内RAM的50H单元,然后再从片内RAM的50H单元将该数据写入到片外RAM的ABCDH单元中。相应的C51语言程序可以这样编写:

//-------------------------------------------------------------------

#include //包含绝对地址访问头文件 #define a CBYTE[0x30] //定义片内ROM的30H单元 #define b DBYTE[0x50] //定义片内RAM的50H单元 #define c XBYTE[0xABCD] //定义片外RAM的ABCDH单元 void main( )

{ b = a; c = b; } //各个存储单元间相互赋值

//-------------------------------------------------------------------

表2-2 8051单片机的特殊功能寄存器

4. C51语言对特殊功能位的访问

C51语言除了可以对特殊功能寄存器进行整体访问以外,还可以对特殊功能寄存器的各个二进制位进行访问。通常把特殊功能寄存器中的各个二进制位,称为特殊功能位。C51语言若想对这些特殊功能位进行操作,事先要完成两步工作:第一步,先将特殊功能位所在的特殊功能寄存器进行定义或者在程序中直接包括已经定义了特殊功能寄存器的头文件,例如reg51.h,建议直接包含头文件;第二步,使用C51语言特有的数据类型sbit定义特殊功能位,然后用户的C51程序就可以对这些特殊功能位进行操作了。在这里举一个例子:例如要对单片机特殊功能寄存器P1口的两个特殊功能位进行赋值操作,使P1.1=0,而P1.6=1。相应的C51语言程序可以这样编写:

//-------------------------------------------------------------------

#include //包含21个特殊功能寄存器地址定义的头文件 sbit a = P1^1; //定义P1口的特殊功能位P1.1为a sbit b = P1^6; //定义P1口的特殊功能位P1.6为b

void main( ) {

a = 0; //给特殊功能位P1.1赋值为0 b = 1; //给特殊功能位P1.6赋值为1 }

//-------------------------------------------------------------------

四. 实验设备和器件

1. PC机一台,操作系统为Windows XP,内存256MB以上,硬盘10GB以上。 2. Keil μVision2集成开发环境的安装软件(绿色版本和安装版本均可),并将该软件安装到PC机上正常工作。

五. 实验内容

1. 顺序结构的C51语言程序设计(要求:创建工程,编程实现,用软件进行仿真) 给特殊功能寄存器和特殊功能位赋值。请使用C51语言,给单片机的P2口赋值为0x00,并使P3口的特殊功能位P3.2=0,P3.3=0,P3.6=0,要求在Keil软件中仿真P2口和P3口的功能,并看到实际的调试结果。具体调试要求:

(1)在Keil μVision2环境中,掌握查看各并行口数据的方法。

(2)在Keil μVision2环境中,如何对并行口的各个二进制位进行赋值和观察。 (3)使用单步调试的方式来执行程序。在调试过程中,配合观察并口寄存器的窗口,检验程序的运行结果是否正确。

(4)连续执行程序,在执行的过程中,配合观察并口寄存器窗口,检验程序运行结果。

【实验提示】:

此题主要使用C51语言,对特殊功能寄存器以及特殊功能位进行赋值。如何在Keil软件中仿真调试4个并行I/O口,是此题要掌握的一个重要知识点,它将会对以后单片机硬件部分的软件仿真打下基础。此题的参考程序代码如下:

//-----------------------------T21.C程序---------------------------- //文件名称:T21.c

//程序功能:给特殊功能寄存器以及特殊功能位赋值。 //编制时间:2010年1月

//------------------------------------------------------------------- #include //包含定义51单片机寄存器的头文件 sbit a=P3^2; //定义P3口引脚P3.2 sbit b=P3^3; //定义P3口引脚P3.3 sbit c=P3^6; //定义P3口引脚P3.6 void main( ) //主函数 {

P2=0x00; //给P2口赋值为00

a=0; b=0; c=0; //P3.2、P3.3、P3.6引脚赋值为0 }

//-------------------------- T21.C程序结束-------------------------

在这里,对如何使用Keil软件仿真调试P0~P3四个并行I/O口进行简要的介绍。当在Keil环境中把程序编写完毕以后,并编译为0个错误0个警告时,点击“调试菜单下的‘开始/停止调试’选项”,这时进入到调试环境。若想观察P0~P3这四个并行口的软件仿真结果,首先需要将这四个并行口打开,可以点击“外围设备菜单下的‘I/O-Ports’选项”,该选项会指示出Port 0~Port 3也就是单片机的P0口~P3口,具体如图5.1所示。由于本题只使用P2和P3口,因此用左键点击Port 2和Port 3就会显示P2和P3口的当前状态,如图5.2所示。从图中可以看出,P2和P3口的初始默认值都为0xff。这里有个小技巧,每个并行口都有8个特殊功能位,例如P2口的8位是P2.0~P2.7,它们在图中用小方格依次从右向左排列,其中最右侧的小方格代表P2.0,最左侧的小方格代表P2.7,8个二进制位的值就是整个P2口的值,而每个二进制位的值可以通过它们各自小方格的状态看到。当小方格的下面画的是“对号”时,代表相应的二进制位为1,由于4个并行口初始状态时,8个小方格都是“对号”,所以每个并口的初始值都是0xff;当相应二进制位下的小方格状态为“空白”时,那么这个小方格对应的二进制位就是0,如果8个小方格的状态都为空白,则整个并口的值为00。

当从图5.2中看到P2和P3口的初始状态都为0xff时,接下来可以按快捷键F10来单步执行程序,边按F10快捷键时,要边看P2和P3口的状态是否按照程序的设计要求进行了相应的改变。一直按F10键,直到程序单步执行完毕,这时执行的结果如图5.3所示。从图中可以看出,P2口的8个小方格都是“空白”状态,因此P2口的值为0x00,而从下面的P3口也可以看到P3.2、P3.3以及P3.6的小方格状态都是空白的,所以它们的值是0,其他各个二进制位的状态是1。综上所述,从图5.3中可以看出此时P2=0x00,P3.2=0,P3.3=0,P3.6=0,满足题目的要求。至此,已经将Keil软件下如何仿真四个并行口的方法介绍完毕,希望大家多练习,全面掌握。

图2.1 并行口P0~P3在Keil软件中的打开方式

图2.2 并行口P2和P3的初始默认值

图2.3 并行口P2和P3的执行结果图

2. 分支结构的C51语言程序设计(要求:编程实现,用软件进行仿真并检查)

将ASCII码转换成16进制数。已知,一个16进制数的ASCII码,存放在片内RAM的30H单元,请把这个数的16进制表示方式存于片内RAM的31H单元中,软件流程如图5.4所示。具体程序的调试要求如下:

(1)在Keil μVision2环境中,掌握查看各并行口数据的方法。

(2)在Keil μVision2环境中,如何对并行口的各个二进制位进行赋值和观察。 (3)使用单步调试的方式来执行程序。在调试过程中,配合观察并口寄存器的窗口,检验程序的运行结果是否正确。

(4)连续执行程序,在执行的过程中,配合观察并口寄存器窗口,检验程序运行结果。

【实验提示】:

本题主要是对ASCII码与16进制数之间进行转换,同时加强C51语言的分支结构程序设计。对于16进制数中0~9的ASCII码值比16进制数本身大30H,而16进制数中A~F的ASCII码值比16进制数本身大37H,只要掌握好这些对应关系,使用if-else语句这道题目就很容易完成。

开 始在片内RAM的30H单元设置ASCII码ASCII码比0x39大?否是将ASCII码减0x37将ASCII码减0x30赋给片内RAM的31H单元

图2.4 ASCII码与16进制数转换的软件流程图

3. 循环结构的C51语言程序设计(要求:编程实现,用软件进行仿真并检查)

片内及片外RAM中的块数据传送。请使用C51语言,将片内RAM的20H~29H单元中的数据,传送给片外RAM的ABC0H~ABC9H单元,软件流程如图2.5所示。具体程序的调试要求如下:

(1)在Keil μVision2环境中,打开片内RAM和片外RAM的存储器窗口。 (2)在Keil μVision2环境中,如何给片内RAM的20H~29H单元同时赋值。 (3)使用单步调试的方式执行程序,配合观察存储器窗口,检验程序运行结果是否正确。 (4)连续执行程序,在执行的过程中,配合观察存储器窗口,检验程序运行结果。 【实验提示】:

此题主要练习对片内和片外RAM单元的理解,以及如何查询、修改片内外RAM单元中所存储的数据,同时用于加强C51语言的循环结构程序设计。这里需要注意循环变量的

数据类型,当控制循环次数的变量类型为无符号字符型即unsigned char类型时,它的大小范围在0~255之间,因此这时不要在for循环中使循环变量的值小于等于256,否则会产生无限循环,导致程序无法正常的运行。

开 始定义片内RAM和片外RAM的首地址定义循环控制变量ii < 10 ?否是将片内一个RAM单元的数值赋给相应的片外RAM单元变量的值 i+1程序结束

图2.5 片内和片外存储单元中块数据的传送流程图

4. 选做题(要求:时间充足可以思考做法,不做要求)

(1)存储单元数据的相互传送。请使用C51语言,将单片机片内RAM的32H单元的数据与片外RAM的6DH单元的数据相加,结果保存在片外RAM的50H单元,然后再将片外ROM的1234H单元的数据与片内RAM的66H单元的数据相减,结果保存在片内RAM的36H单元中。 (2)有符号数比较大小。假设在片内RAM的3AH单元中,存储的有符号数据是m,在片外RAM的 9ABDH单元中存储的有符号数据是n,试比较这两个数的大小,并将大数保存在片内RAM的6FH单元中。

(3)对片外RAM单元进行数据传输。请先将片外RAM的8000H~80FFH单元中的数据清零,然后再把数值00H~FFH,赋给上面的256个外存单元。

六. 实验报告

1. 通过本次实验,总结C51语言不同结构的程序设计方法与调试步骤。

2. 写出C51程序的源代码,给每行语句加上详细的注释,并画出程序的流程图。 3. 掌握如何在Keil软件中观察程序、变量以及存储单元的数据变化情况。

4. 叙述程序调试过程中遇到的困难以及解决方法,写出本次实验的收获和心得体会。

本文来源:https://www.bwwdw.com/article/hki7.html

Top