单片机原理与接口技术实验指导(c语言版)

更新时间:2023-09-16 18:40:01 阅读量: 高中教育 文档下载

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

实验1 Keil软件的使用

1.1 创建一个Keil C51应用程序

开发单片机的第一步就是用Keil C51软件编写程序,并形成最终的“*.hex”目标文件,然后用编程器将该文件烧写到单片机中,最后将烧写好的单片机插到电路板上,接通电源就可以工作了。

在 Keil C51集成开发环境下使用工程的方法来管理文件的,而不是单一文件的模式。所有的文件包括源程序(包括 C 程序,汇编程序)、头文件、甚至说明性的技术文档都可以放在工程项目文件里统一管理。在使用 Keil C51 前,用户应该习惯这种工程的管理方式。对于使用 Keil C51 的用户来讲,一般可以按照下面的步骤来创建一个自己的 Keil C51 应用程序。

1.新建一个工程项目文件;

2.为工程选择目标器件(例如选择SST的SST89C58); 3.为工程项目设置软硬件调试环境; 4.创建源程序文件并输入程序代码; 5.保存创建的源程序项目文件; 6.把源程序文件添加到项目中。

下面以创建一个新的工程文件 Led_Light.μV2 为例,详细介绍如何建立一个Keil C51的应用程序。 (1) 双击桌面的 Keil C51 快捷图标,进入如图1.1所示的 Keil C51 集成开发环境。或许打开

Keil C51 界面有所不同,这是因为启动μVision2 后,μVision2 总是打开用户前一次正确处理的工程,可以点击工具栏的 Project 选项中的 Close Project 命令关闭该工程。

图 1.1 Keil C51 集成开发界面 (2)点击工具栏的 Project 选项,在弹出如图1.2 所示的下拉菜单中选择New Project命令,建立一个新的μVision2 工程,这时可以看到如图 2.10 所示的项目文件保存对话框。

图 1.2 新建工程项目下拉菜单

在这里需要完成下列事情:

①为工程取一个名称,工程名应便于记忆且文件名不宜太长; ②选择工程存放的路径,建议为每个工程单独建立一个目录,并且工程中需要的所有 文件都放在这个目录下; ③选择工程目录 F:\\示范程序\\Led_Light 和输入项目名 Led_Light 后,点击保存返回。

点击选择工程存放路径

填写新建工程的名称 图1.3 新建工程项目对话窗口

在工程建立完毕以后,μVision2 会立即弹出如图1.4 所示的器件选择窗口。器件选择的目的是告诉μVision2 最终使用的 80C51 芯片的型号是哪一个公司的哪一个型号, 因为不同型号的 51 芯片内部的资源是不同的。,μVision2 可以根据选择进行 SFR 的预定义, 在软硬件仿真中提供易于操作的外设浮动窗口等。

图1.4 器件选择窗口

由图1.4可以看出,μVision2 支持的所有 CPU 器件的型号根据生产厂家形成器件组,用户可以根据需要选择相应的器件组并选择相应的器件型号,如 Philips 器件组内的 P80/P87C52X2 CPU。另外,如果用户在选择完目标器件后想重新改变目标器件,可点击工具栏project选项,在弹出的如图 1.5 所示的下拉菜单中选择是select device for target ‘target 1’命令。也将出现如图 1.4所示的对话窗口后重新加以选择。由于不同厂家的许多型号性能相同或相近,因此如果用户的目标器件型号在μVision2 中找不到, 用户可以选择其它公司的相近型号。

图1.5 器件选择命令下拉菜单

(4)到现在用户已经建立了一个空白的工程项目文件,并为工程选择好了目标器件,但是这个工程里没有任何程序文件。程序文件的添加必须人工进行,但如果程序文件在添加前还没有建立,用户还必须建立它。点击工具栏的File选项,在弹出的如图 1.6所示的下拉菜单中选择New命令。这时在文件窗口会出现如图1.7所示的新文件窗口Text1,如果多次执行New命令则会出现 Text2,Text3.等多个新文件窗口。

图 1.6 新建源程序下拉菜单

图 1.7 源程序编辑窗口

(5)现在 Led_Light.μV2 项目中有了一个名为 Text1 新文件框架,在这个源程序编辑 框内输入自己的源程序 Led_Light.asm。下面是完整的 Led_Light.asm 源程序代码,用户可以输入。 ORG 0000H JMP MAIN ORG 0100H MAIN: MOV A,#0FEH ;流水灯向左移动 LEFT_MOV: MOV P1,A CALL DELAY RL A CJNE A,#0FEH,LEFT_MOV MOV A,#7FH ;流水灯向右移动 RIGHT_MOV: MOV P1,A CALL DELAY RR A CJNE A,#7FH,RIGHT_MOV JMP MAIN

;-----------------------延时子程序---------------------- DELAY: MOV R2,#250 DEL: MOV R3,#250

NOP DJNZ R3,$ DJNZ R2,DEL RET END

(6) 输入完毕后点击工具栏的File选项,在弹出的下拉菜单中选择是save命令存盘源程序文件。这时会弹出如图1.8所示的存盘源程序文件画面,在文件名栏内输入源程序的文件名,在此示范中把Text1 保存成 Led_Light.asm。注意文件的扩展名不能省略,而且必须是.asm(如果是C则保存为*.c)。保存完毕后请注意观察,保存前后源程序有哪些不同,关键字变成蓝颜色了吗?这也是用户检查程序命令行的好方法。

图1.8 源程序存盘对话框

(7) 需要特别提出的是,这个程序文件仅仅是建立了而已,Led_Light.asm 文件到现在为止跟 Led_Light.μV2 工程还没有建立起任何关系。此时用户应该把 Led_Light.asm源程序填加到Led_Ligh. μV2工程中,构成一个完整的工程项目。在project window窗口内,选中source group1后点击鼠标右键,弹出如图1.9所示的快捷菜单中选择Add Files to Group‘Source Group1’(向工程中加入源程序)命令。

图1.9添加源程序快捷菜单

此时会出现如图1.10所示的添加源程序文件窗口,选择刚才创建编辑的源程序文件Led_Light.asm。单击Add命令即可把源程序文件添加到项目中。由于添加源程序文件窗口中的默认文件类型是C Source File(*.c),这样在搜索显示区中则不会显示刚才创建的源程序文件( 由于它的文件类型是 *.asm) 。改变搜索文件类型为 All File(*.*),选择 Led_Light.asm 源程序文件后点击Add命令将弹出如图1.11所示的文件类型确认窗口,在type下拉菜单中选择assembly language file后确认返回图1.10添加源程序文件窗口,此时点Add命令即可将源程序添加进项目工程中。

图1.10 添加源程序文件窗口

图1.11 文件类型确认窗口

1.2 程序文件的编译、连接

(1) 编译环境的设置

工程建立好后,还要对工程进行进一步的设置,以满足要求。 首先单击左边窗口的‘Target’,然后选择options for Target‘Target1’ 参考图1.12。这时即出现如图1.13所示的调试环境设置窗口。

图1.12 调试环境设置窗口下拉菜单

点击 Output 选项卡在出现的窗口中选中 Create Hex File 选项,在编译时系统将自动生成目标代码文件*.HEX。选择 Debug 选项会出现如图1.14所示的工作模式选择窗口,在此窗口中我们可以设置不同的仿真模式。

图1.13 Keil C51 调试环境设置窗口

图1.14 Debug 设置窗口

从图1.14可以看出,μVision2 的 2 种工作模式分别是:Use Simulator(软件模拟) 和 Use(硬件仿真)。其中 Use Simlator 选项是将μVision2 调试器设置成软件模拟仿真模式,在此模式下不需要实际的目标硬件就可以模拟 80C51 微控制器的很多功能,在准备 硬件之前就可以测试您的应用程序,这是很有用的。

(2)程序的编译、连接、运行

完成以上的工作就可以编译程序了。点击如图1.15所示的Rebuild All Target Files 命令,对所有的工程文件进行重新编译,此时会在“Output windows”信息输出窗口输出一些相关信息,如图1.16所示。

图1.15 编译命令菜单

图1.16 输出提示信息

其中第二行 assembling Led_Light.asm 表示此时正在编译 Led_Light.asm 源程序,第三行 linking..表示此时正在连接工程项目文件,第五行 Creating hex file from‘Led_Light’说明已生成目标文件 Led_Light.hex,最后一行说明 Led_Light.μV2 项目 在编译过程中不存在错误和警告,编译链接成功。若在编译过程中出现错误,系统会给出错 误所在的行和该错误提示信息,用户应根据这些提示信息,更正程序中出现的错误,重新编译直至完全正确为止。

对源程序进行编译之后,还需要实际的运行来验证程序的正确性。点击如图1.17所示的start/stop debug session命令,将程序与硬件进行连接,如果与硬件连接正确,会在Output windows窗口出现如图1.18所示的提示信息,如果连接不正确,会出现如图1.19

所示的信息,此时请复位硬件,然后重新编译、连接。

图1.17 start/stop debug session命令窗口

图1.18 与硬件连接正确提示信息

图1.19 与硬件连接不正确提示信息

完成以上步骤,与硬件连接正确之后,用户就可以按图1.20所示的运行命令进行在线仿真了。

图 1.20 运行命令窗口

以下与实验内容无关,作为了解,可以跳过。 ① 在调试环境设置窗口的target页面下,(参考图1.13),xtal后面的数值是晶振频率值,默认值是所选目标CPU的最高频率值。一般将其设置成为实际所使用的晶振频率值。

Memory Model用于设置RAM使用情况,有3个选择项。

I. small :是所有变量都在单片机的内部RAM中,如果内部RAM空间不够,才会存到外部RAM中。这种数据存储方式的好处在于运算速度最快,也是我们一般常选择的方式。

II. Compact :变量存储在外部RAM里,使用8位间接寻址。即将变量放在外部RAM的前256个字节里。

III.Large: 变量放在外部RAM里,使用16位间接寻址。 Code Rom size用于设置ROM空间的使用,也有3个选项。

I. Small:只用低于2K的程序空间,适用于AT89C2051这些芯片。

II.Compact:单个函数的代码量不能超过2KB,整个程序可以使用64KB的程序空间。 III.Large:可用全部64KB的空间,表示程序和子函数代码都可以大到64KB。 Operating项是操作系统选择项,Keil C51提供了两种操作系统:Rtx tiny和Rtx full。通常不使用任何操作系统,用该项的默认值:None(不使用任何操作系统)。

Use on-chip ROM(0x0-0xfff)选择项,表示使用片上的ROM。该选项取决于单片机应用系统,如果单片机的EA接高电平,则选中,表示使用内部的ROM,如果单片机的EA接低电平,则不选中该选项,表示使用外部的ROM。

Off-chip Code memory:表示片外ROM的开始地址和大小。如果没有外接程序存储器,那么不需要填任何数据。

Off-chip Xdata memory:用于确定系统扩展RAM的地址范围,可以填上外接Xdata外部 数据存储器的起始地址和大小。这些选择项必须根据所用硬件来决定。

② 在Output页面下,见图1.21。

select Folder for objects:用来选择最终的目标文件所在的文件夹,默认则表示与工程文件在同一个文件夹中。

Name of Executable:设置生成的目标文件的名字,默认情况下与项目的名字一样。 Creat Executable:creat hex用于生成可执行代码文件,默认情况下该项未选中,如果要烧录芯片做硬件实验,就必须选中该项。

图1.21 output设置窗口

(3) 本实验当中编译环境的设置说明

1.在调试环境设置窗口的Device选项卡中器件选择SST89C58。(参考图1.4) 2. 在调试环境设置窗口的Target选项卡中xtal(Mhz)项填写12。选中Use on-chip ROM。其它项不必改动,具体设置参考图1.13。

3 在调试环境设置窗口的debug设置窗口中选择keil monitor-51 drive仿真设置。(参考图1.14)用鼠标点击keil monitor-51 drive后的setting,将弹出1.22所示的窗口。在实验当中根据与计算机连接情况选择串口,波特率固定选择38400。

图1.22 串口设置窗口

实验2 C语言基本指令及程序设计

1 实验目的

(1)熟悉C语言基础知识

(2)掌握单片机的C语言的编程方法 2实验原理

(1)C语言中的数据

1.数据类型

1)char:字符型数据,占一个字节,分为有符号数和无符号数,有符号数的表示范

围为-128~ +127,采用二进制补码的表示形式,无符号数的表示范围为0~255 2)int:整型数据,占两个字节。分为有符号数和无符号数,有符号数表示范围为

-32768~+32767,采用补码表示,无符号数表示范围为0~65535

3)long:长整型,4个字节,分为有符号数和无符号数 4)float:浮点型,f占用4个字节,符合IEEE标准 5)bit:位变量,用于进行位操作 6)sbit:定义位变量

7)sfr:单字节变量,范围为0~255 8)sfr16:双字节变量,范围为0~65535 9)*:对象指针,1~3字节

2.数据的存储类型 1)片内数据存储器

片内RAM最大可达到256字节,可分为3个区域 Data:片内直接寻址区,位于片内RAM低128字节 Bdata:片内位寻址区,位于片内RAM位寻址区 Idata:片内间接寻址区,片内RAM所有字节 2)片外数据存储器

Xdata:外部存储器,为片外RAM的64KB空间 Pdata:外部存储器,片外RAM中的一页,为156字节

在程序中定义变量类型是编程中首先遇到的问题。一个程序中肯定会有数据,首先要选择数据类型,一个变量可能有最大的数据,到底有几个字节才可以存下,这就要根据情况分析而定。在够用的情况下,尽量选则8位即一个字节的char类型。

数据的存储类型是一个值得深讨的话题,只要条件满足尽量选择内部直接寻址的存储器类型data,然后选择idata即内部间接寻址,对于经常使用的变量要使用内部寻址。在内部寄存器数量有限或不能满足要求的情况下才使用外部存储器,选择外部存储器时可先选择pdata类型,最后选择xdata类型。存储器的选择关系到程序的执行效率问题,在选择时要多加考虑。

(2) C语言中的函数 函数是指程序中的一个模块,c语言就是由一个个的模块化函数构成的,main()

函数为程序的主函数,其他若干函数可以理解为一些子程序。Main()函数是程序运行的起点,程序员的任务就是编写一些列函数模块,并且在适当那个时候调用这些函数,实现程序所要实现的功能。 1. 函数

在C语言中编写的函数包括函数声明和函数体。 (1)函数声明格式为: 函数返回值类型 函数名(形式参数1,形式参数2,??); (2)函数体格式为:

函数返回类型 函数名(形式参数1,形式参数2,??) { }

对于无返回值的函数,函数返回类型就是void,否则就根据返回值的类型确定函数返回类型,例如int型、char型。如果函数没有参数,在函数声明中参数写为void。下面是两个函数声明示例:

bit busychk(char busybuf ) 函数返回值类型是bit型,参数类型为char void keyin(void) 函数无返回值,也没有参数

2. 函数调用 (1)简单调用

调用格式:函数名(实际参数1,实际参数2,??) (2)嵌套式调用

嵌套式调用就是调用的函数中又调用其它函数的语句。 (3)递归调用

函数的递归调用就是一个函数在其函数体内又调用自身,递归调用是一种特殊

的循环结构。

注:在调用一个函数时要保持与该函数声明和函数体格式的一致:包括函数返

回值类型、参数类型和个数。

(3) C语言中的运算操作 1.赋值、指针、取指运算符

运算符的类型可以分为:单目,双目,多目。单目运算符只有一个操作数,双目运算符有两个操作数,多目运算符则有多个操作数。

符号 = * & 运算符类型 双目 单目 单目 运算符注解 赋值 取指针 取地址 关于赋值、指针、取指运算可以举如下的例子供用户参考学习:

#include void main() { int data nvar1,nvar2,*pvar,nresult; nvar1=5; nvar2=3; pvar=&nresult; //除法运算 *pvar=nvar1*nvar2; //取模运算 while(1);

}

运行结果如下:

2. 算术运算符

符号 + - * / %

运算符类型 双目 双目 双目 双目 双目 运算符注解 加法运算 减法运算 乘法运算 除法运算 取模运算 以上的运算符,对于+,-,*的操作比较熟悉,但是对于除法和取模运算就比较陌生,下面就一个例子来对这两种运算进行解释: #include

void main() { char data nvar1,nvar2,nresult1,nresult2; nvar1=5; nvar2=3; nresult1=nvar1/nvar2; //除法运算 nresult2=nvar1%nvar2; //取模运算 while(1);

}

运行后的结果是:

“/”为除法运算,“%”为取模运算,运算符左侧为被除数,右侧为除数。5/3结果为1,而5%3结果为2,其实这两种运算可以理解为,“/”为取商,“%”为取余。 3. 关系运算符

符号 > < >= <= == !=

运算符类型 双目 双目 双目 双目 双目 双目 运算符注解 大于 小于 大于或等于 小于或等于 等于 不等于 关系运算符,顾名思义是判断两个数之间的关系,有大、小、等和不等几种关系。这几种运算看似简单,但有几个细节地方需要读者的注意。

对于关系运算结果的问题,在C语言中如果关系成立则结果为真,对应非0值,

一般为1,如果关系不成立则结果为假,对应值为0。

例如下面的运算测试,5>3显然是成立的,结果为真,返回值为1,而3>3不成

立,结果为假,返回值为0.最应该注意的是>=和<=,它们是大于或等于、小于或等于的意思,所以程序中3>=3在关系上是对的,这些细节读者应该多多注意。

void main()

{

int data nvar1,nvar2,nvar3,nvar4,nvar5,nvar6;

nvar1=(5>3); nvar2=(3>3); nvar3=(5>=3); nvar4=(3>=3); nvar5=(5= =3); nvar6=(3= =3); while(1); }

运行结果如下:

4. 逻辑运算符

符号 && || ! 运算符类型 双目 双目 双目 运算符注解 逻辑与 逻辑或 逻辑非 在逻辑运算中,最基本的是二值逻辑即真和假,而逻辑运算是以真假逻辑为对象的运算。

①对于与运算,只有二者都为真时,结论才为真 ②对于或运算,只有二者都为假时,结论才为假 ③对于非运算,取反,真的非即为假,假的非即为真 具体的例子不再在这陈述,读者可仿照上面的例子,自行设计程序对逻辑运算进

行测试。

5. 位运算

符号 & | ^ ~ << >> 运算符类型 双目 双目 双目 双目 双目 双目 运算符注解 按位与 按位或 按位异或 按位取反 按位左移 按位右移 这里的位指的是二进制位,计算机中的数据都是以二进制存放的,对于数据的操作也是按位进行的。

6. 复合运算符

符号 += -= *= /= %=

运算符类型 双目 双目 双目 双目 双目 运算符类型 加 减 乘 除 模

&= |= ^= ~= <<= >>= ?: 双目 双目 双目 双目 双目 双目 双目 与 或 非 取反 左移 右移 问号运算 为了方便书写,C语言中有符合运算,使得语句的书写更加简洁,符号左边的变量既为源操作数也为目的操作数。 复合运算测试程序如下: void main() { int xdata nvar1=1,nvar2=2,nvar3=3,nvar4=4,nvar5=5,nvar6=6,nvar7=7,nvar8=8; nvar1*=3; //nvar1乘以3再放到nvar1中去 nvar2*=nvar1; //nvar2乘以nvar1再放到nvar1中去 nvar3<<=2; //nvar3左移2位再放到nvar3中去 nvar4<<=nvar1; //nvar4左移nvar1位再放到nvar4中去 nvar5&=0x0f; //nvar5和0x0f与后的结果放到nvar5中去 nvar6&=nvar5; //nvar6和nvar5与后的结果放到nvar6中去 nvar7=3>5? nvar5:nvar6; //3>5为假,故nvar6放到nvar7中去 nvar8=5>3? nvar5:nvar6; //5>3为真,故nvar5放到nvar8中去 while(1); }

运行结果是:

这段程序选择的变量存储类型为xdata,即变量存储在外部数据存储区,这与运行结果无关,只是在程序内部变量的操作上可能比较费时。 其它的复合运算符应该比较好理解,在此只对问号运算符做一解释:如果问号关系式是真的,那么就将“:”前的数据放入目的操作数,如果问号关系式为假,则将“:”后的放入目的操作数。 (4) 基本的程序设计结构

在结构上,可以吧程序分为三类:顺序、分支、循环结构。顺序结构是程序的基本

结构,程序自上而下,从main()函数开始一致运行到结束;分支结构,相对顺序结构有较多的分支结构可以选择,满足某个条件时就执行对应的一段程序;程序需要反复执行某一个操作时,循环语句为程序设计提供方便。 1. 顺序结构程序设计

大多数的程序体现了明显的顺序性,先做什么,再作什么,正如流程图中的先后顺序,依次向下执行,这个读者应该容易理解,就不再赘述。 2. 分支结构程序设计

1) 只有两只分支的时候用

if(条件){分支1}

else {分支2}

当条件为真时执行分支1,否则,执行分支2 2) 在多分支的时候用

在分支比较多的情况下使用switch语句,格式如下: Switch(表达式) {

Case(常量表达式1):

语句1;

Break; Case(常量表达式2):

语句2;

Break; ???????

Case(常量表达式n):

语句n;

Break; Default:语句n+1; Break; }

Switch语句又称开关语句,switch语句的执行流程是:首先计算switch后面圆括号中表达式的值,然后用此值依次与各个case的常量表达式比较,若圆括号中表达式的值与某个case后面的常量表达式的值相等,就执行此case后面的语句,直到遇break语句就退出switch语句;若圆括号中表达式的值与所有case后面的常量表达式都不等,则执行default后面的语句n+1,然后退出switch语句,程序流程转向开关语句的下一个语句。 需要注意的是:

①default总是放在最后,这时default后可以不要break语句.并且,default部分也不是必须的,如果没有这一部分,当switch后面圆括号中表达式的值与所有case后面的常量表达式的值都不相等时,则不执行任何一个分支直接退出switch语句.此时,switch语句相当于一个空语句 。

②每一个分支语句后的break语句是必不可少的,否则程序并不能跳出switch,会继续执行case后面的case语句。

3. 循环结构程序设计

1)for循环

格式:for(循环体初始化;循环体执行条件;循环体执行后的操作) {

循环体; }

2)while循环

格式:while(循环体) { 循环体;

}

3)do while循环

格式:do{循环体内容} While(循环体执行条件) 需要注意的是:前两种循环是先进行条件是否满足的判断,才决定循环体是否执行;

而do while循环是先执行循环体,再判断条件是否满足,再决定循环体是否再继续执行。

(5)子程序设计

当一段代码需要经常被调用或是在不同的地方使用时,通常将该段代码编制成子

函数的形式以方便调用。

程序执行过程往往要调用其它函数以实现一些特定的功能,在程序中函数调用的

执行流程图如下所示:

正在执行程序调用其它函数处继续执行程序进入执行被调用函数返回

通常在进行函数调用时,调用函数与被调用函数之间有数据的传递,这种数据

的传递是通过函数的参数实现的。在定义一个子函数时,位于函数名括号内的变量是形式参数,而在调用函数的语句中函数名后的括号里的变量实际参数,参数传递中只能由实际参数传递给形式参数,而不能由形式参数传递给实际参数。

需要读者注意的是,当程序代码比较多的时候,通常主程序和子函数是分别在

不同的文件中的,同时子程序也是按照功能分别存放在不同的文件中的,方便查阅。这时,如果要调用子程序,如果该子程序不在此文件中,就要事先声明将被调用的子函数。为了方便使用,也可以对每个文件做一个.h文件,.h文件包括对端口的定义、变量的定义、常量的定义、子函数的声明等。每次需要调用相关子函数时,只要直接调用这个.h文件就可以了。

例如,在后面按键的程序设计中,可以将按键扫描分为三个子函数,读按键、

按键去抖、键值转换,保存在一个文件中,方便以后其它代码中的调用。一种主程序设计格式为:

#include void Keyin (void) ; //调用函数 void Keychk(void); void Keycvt(void);

void main() // 主函数 { While(1) {

Keyin();

Keychk(); Keycvt(); }

}

另外一种设计方法就是事先设计好key.h文件,在主程序中包含就好了: key.h文件格式:

#include 端口定义; 变量定义; 常量定义;

void Keyin (void) ; //函数声明 void Keychk(void); void Keycvt(void);

完成key.h文件设计后,主程序为:

#include #include “key.h”

void main() // 主函数 { While(1) {

Keyin();

Keychk(); Keycvt(); }

} 从上面的对比可以明显的看出,定义.h文件,简化了程序的书写,也减少

了编程中错误的出现。

2实验内容

(1)掌握C中的运算符、分支语句 (2)熟悉C语言中的关键词及相关函数 (3)学习C语言程序设计的格式和方法 4 实验参考程序

#include #include

unsigned int getnumber(void); void output(unsigned int); void main(void) {

unsigned int number1,number2; bit operation; SCON=0x52; TMOD=0x20; TCON=0x69; TH1=0xf3;

printf(\ while(1) { number1=getnumber(); number2=getnumber(); printf(\ operation=(getchar()=='+'); output(operation? (number1+number2):(number1-number2)); } }

实验板电路介绍

1. 电源电路介绍

电源电路如图所示,它采用三端稳压器7805及外围电路组成的稳压电路,,从J输入一个8—12V的直流电压,在输出端产生5V的稳压输出。其中发光二极管作为电源指示灯,二极管D12是防止电源接反,保护电路。

VCCU9780531+5VVinC15C12C13C14D124007R16104104100uF/16VJ7100uF/24V1KGNDD112 2. 复位电路

RSTGNDC24.7uFS1D14001

10KVCCR5 图中RST接单片机的复位引脚RST,形成复位电路。平时RST端口是高电平,当按键按下后,RST端口为低电平,实现低电平复位。

3. 流水灯电路 RP11KVCC123456789D3D4D5D6D7D2D8D9LED1LED2LED3LED4LED5LED6LED7LED8

J11J11 J12J12 J13J13 J14J14 321J15321LED5P14ELED1P10A321J16321LED6P15FLED2P11B321J17321LED7P16GLED3P12C321J18321LED8P17DPLED4P13D

如图示,8个发光二极管接P1[0:7]口,组成一个流水灯电路。实验板中P1口是流水灯和数码管显示的复用端口,通过跳线J11、J12、J13、J14、J15、J16、J17、J18进行选择。在流水灯实验中,将J11—J18跳线的2、3短接,二极管LED1—LED8就与P1口导通,当P1口有低电平时,二极管点亮。

4. 数码管显示电路

12345678RP21K161514131211101110742195faABCDEFGPDDPY1afegdbcdpfeagdbcdpfegdpbdace3afegdbcdpgdbcdpcom4com3com21298com16COM1Q1COM29012Q2COM39012Q3COM49012Q49012VCC

数码管显示电路如图所示,段选端口接到复用端口P1上,在数码管显示电路中,将J11—J18跳线的2、3短接,就可以进行段选。数码管的公共端COM1—COM4是经PNP三极管9012接单片机的P0.0—P0.3口上的,属于共阳极的接法,当COM端有低电平时,选中数码管的某个位。

5. 键盘电路

本次采用的是独立式键盘,8个按键一端分别接P2[0:7]口,并通过10K的电阻上拉,另一端地。没有按键状态下,P2口为高电平,当有按键按下时,为低电平状态。

{ Th0Buf=0xf9; Tl0Buf=0xb9; LightPort=0xfb; //指示灯3点亮 Buz_en=1; break; } case(0x08): //key4键按下,(Fa) { Th0Buf=0xfa; Tl0Buf=0x68; LightPort=0xf7; //指示灯4点亮 Buz_en=1; break; } case(0x10): //key5键按下,(So) { Th0Buf=0xfb; Tl0Buf=0x05; LightPort=0xef; //指示灯5点亮 Buz_en=1; break; } case(0x20): //key6键按下,(La) { Th0Buf=0xfb; Tl0Buf=0x90; LightPort=0xdf; //指示灯6点亮 Buz_en=1; break; } case(0x40): //key7键按下,(Si) { Th0Buf=0xfc; Tl0Buf=0x0c; LightPort=0xbf; //指示灯7点亮,高音 Buz_en=1; break; } case(0x80): //key7键按下,(Si) { Th0Buf=0xfc; Tl0Buf=0x7a; LightPort=0x7f; //指示灯7点亮,高音 Buz_en=1; break; } default: { Buz_en=0; BuzBit=1; //关蜂鸣器 LightPort=0xff; //关指示灯 break; } } }

//====================================================== //文件名称: 按键扫描

//功能说明: 直入式8键键盘 //硬件描述: 低电平有效 //资源说明: 12M晶体

//====================================================== #include #define uchar unsigned char #define uint unsigned int

//===================常量================================ #define KeyPort P2 //按键端口 #define KeyNomber 8 //按键数目 #define KeyTime 8 //防抖定时时间

//===================变量================================ uchar data KeyInBuff; uchar data KeyChkBuff; uchar data KeyTimeBuff; uchar data KeyCvtBuff; uchar data KeyOldBuff; uchar data KeyBuff; bit bdata KeyInFlag;

//===================调用函数============================ void KeyIn(void); void KeyChk(void); void KeyCvt(void); void DeKeyTime(void);

//====================================================== //函 数 名: MnKey() //功能描述: 按键 //输入参数: 无 //输出参数: 无

//====================================================== void MnKey(void) {

KeyIn(); KeyChk(); KeyCvt(); }

//===================================================== //函 数 名: KeyIn()

//功能描述: 读入按键,并取反 //输入参数: Keyport //输出参数: KeyInBuff

//======================================================= void KeyIn(void) {

KeyInBuff = KeyPort; KeyInBuff ^=0xff; }

//======================================================= //函 数 名: KeyChk() //功能描述: 按键防抖 //输入参数: KeyInBuff //输出参数: KeyCvtBuff

//====================================================== void KeyChk(void) {

if(KeyInBuff==KeyChkBuff) { if(KeyInFlag==0) return; else { DeKeyTime(); if(KeyTimeBuff!=0) return; else { KeyInFlag = 0; KeyCvtBuff = KeyChkBuff; } } } else

{ KeyChkBuff = KeyInBuff; KeyTimeBuff = KeyTime; KeyInFlag = 1; } }

//======================================================= //函 数 名: KeyCvt() //功能描述: 键值转换 //输入参数: KeyCvtBuff //输出参数: EventFIFO

//======================================================= void KeyCvt(void) {

if(KeyCvtBuff==KeyOldBuff) return; else { KeyOldBuff = KeyCvtBuff; KeyBuff=KeyCvtBuff; } }

//======================================================= //函 数 名: DeKeyTime()

//功能描述: 按键防抖时间处理函数 //输入参数: 无 //输出参数: 无

//====================================================== void DeKeyTime(void) { uchar i; i=50000; while(i--) {

if(KeyTimeBuff!=0)

KeyTimeBuff--;//调整键盘按下有效判定时间 } }

/****************************************************** 文件名称:Int_Deal

功能描述:处理系统的中断事件 注意事项:无

*******************************************************/ #include

#define uchar unsigned char #define uint unsigned int

//===========常量定义============================== //===========变量定义============================== extern uchar data Th0Buf; extern uchar data Tl0Buf; extern bit data Buz_en; sbit BuzBit=P0^4;

//================================================= //函 数 名: SysInit()

//功能描述: 初始化子程序 //输入参数: //输出参数:

//================================================== void Init() {

TMOD=0x01; //T0定时器工作方式1 TH0=0xf8; TL0=0x17; //20MS中断

ET0=1; //开定时器T0中断

EA=1; TR0=1; }

//开总中断 //启动定时器T0

//==================================================== //函 数 名: ISR_T0() //功能描述: T0中断函数 //输入参数: 无 //输出参数: 无

//==================================================== void ISR_T0(void) interrupt 1 {

TH0=Th0Buf; TL0=Tl0Buf; //重装20MS中断 if(Buz_en==1) BuzBit=~BuzBit; }

思考题:

在蜂鸣器发音时,将相应的音乐符显示在LED上如何实现请同学们思考并完成相应的程序设计。

实验14 I2C总线实验(at24c02)

1.实验内容

加深对I2C总线的理解,学会使用I2C 器件at24c02完成数据的读写操作。 2.实验原理 I2C是用两根线实现完善的全双工同步数据传送,可以极为方便的构成多机系统和外围器件扩展系统。系统中所有的单片机、外围器件都将数据线SDA和时钟线SCL的同名端连接在一起,总线上的所有节点都由器件的引脚给定地址。总线在备用时SDA和SCL都必须保持高电平状态,只有关闭I2C总线时才使SCL嵌在低电平。对其间具体的操作时序查看课本的相应章节。

VCCU21234A0VCCA1WPA2SCLGNDSDAAT24C028765P05R6P06R710K10K

At24c02 的硬件电路图如上图所示,它是一种调电数据不丢失的EEPROM,其各个引脚的功能如下所示:

SCL, 串行时钟端 SDA, 串行数据端 WP, 写保护,当WP为高电平时,存储器只读,当WP为低电平时,存储器可读可写。

A0,A1,A2,片选或块选

3.实验内容 查看相应的at24c02的时序,完成at24c02的数据读写操作的程序设计 4. 参考程序

//=========================================================== //文件名称: I2C

//功能说明: 包括主循环,系统应用函数,时基处理和定时器中断服务函数 //硬件描述:

//资源说明: 12M晶体

//============================================================ //使用说明:

//1.适用于单字节读写和多字节读写

//2.写入EEPROM的数据读出来后通过LED显示

//3.写入数据暂停,然后再读,否则EEPROM读不出来

//============================================================ #include

#include \

//=======================常量定义============================= #define uchar unsigned char

RP310KVCCS2S3P20P21S4P22S5P23S6P24S7P25S8P26S9P271234567896. 蜂鸣器

VCCR15P04R1410K R13200100KQ69012SP1

如图为蜂鸣器驱动电路,蜂鸣器一端接VCC,另一端通过三极管9012接P0.4口,当P0.4口有低电平时,三极管导通,驱动蜂鸣器工作。

7. 继电器电路 DT1FLA21P07R1210K3FLB2J6VCCQ5901325FLA2FLB2D1040011234

如图是继电器电路,当P0.7为高电平时,三极管导通,2端为低电平,继电器吸合。其中二极管的作用是放电保护电路。 U87. 温度传感器电路 DS18B20GNDDQCVC

VCCP34123

如图所示,温度传感器DS18B20有三个端口,P3.4是数据线,实现温度的采集。

8. I2C总线接口电路

U21234A0A1A2GNDVCCWPSCLSDA8765P05R6P06R7VCC10K10KAT24C02

如图是具有串行接口的EEPROM存储器AT24C02接口的电路,A0、A1、A2是三条地址线,是接地的。WP是写保护端,当高电平时存储器只能读,低电平时存储器可读可写。SCL、SDA分别为串行时钟线和串行数据线,需要和VCC之间接10K的上拉电阻,完成串行通信。

9. LCD电路 J8R171KGNDVCCP35P36P37P10P11P12P13P14P15P16P17GND12345678910111213141516J9VCC12 如图示LCD的接口电路。由于P1口同时复用在流水灯和数码管电路中,在用到LCD显示时,要先断开跳线J11—J18,实验中用到的是LCD1602,对应的接口状态是:1、2脚为电源,3、4、5、6脚分别为VL、RS、RW、E控制端口,7—14脚为8位双向数据线,15脚为背光电源正极,通过跳线J9与电源相接,16脚为背光电源负极。

10. 实时时钟

VCCC515pFY232.768KU312P3334OSC1VCCOSC2COUTINTSCLGNDSDAPCF8563876P055P06

如图是实时时钟电路,采用的是PCF8563时钟芯片。32.768KHz的晶振为PCF8563提供外部晶振,INT中断输出口与单片机的外部中断1P3.3口连接,当INT有低电平输出时,单片机进入外部中断,COUT是时钟输出端口,串行时钟线SCL与串行数据线与P0.5和P0.6连接,实现实时时钟功能。

11. UART

C6VCCU41C71uF34C81uF5TXD11GND10RXD129C1+VS+C1-C2+VS-C2-T1INT2INR1OUTR2OUTGNDC921uFC1061uF147138GND594837261DB1T1OUTT2OUTR1INR2IN RS-232接口电路如图所示,通过MAX232芯片完成TTL电平到RS-232电平的转换。根据串行通信协议,利用TXD、RXD端口实现串行通信。DB1是串行接口,与外部设备连接。

CMAX232

实验6 单片机的中断系统

1、实验目的

1.全面了解单片机的中断系统,熟悉各个中断源及其中断控制的相关寄存器 2.理解中断响应的过程,掌握中断的程序设计 2、实验原理

在CPU和外设交换信息时,存在着快速CUP与慢速外设间的矛盾,机器内部有时也可能出现突发事件,为此,就要用到中断技术。

中断即在CUP和外设并行工作时,当外设数据准备好(或是某种突发事件发生)时向CPU提出请求,CPU暂停正在执行的程序,转而为外设服务(或是处理紧急事务),处理完毕后再回到断点继续执行原程序。执行过程如下:

主程序求应中断请继续执行主程序中断服务程序主程序响返回 中断的主要功能有:

A. 实现CPU与外设的速度匹配; B. 实现实时控制;

C. 实现故障的及时发现和处理。 下面就中断的相关概念做以介绍。 1. 中断源

基本型8XX51单片机有5个中断源,增强型8XX52单片机增加了1个定时/计数器2,他们在程序存储器中各有固定的中断服务入口地址,当CPU响应中断时,硬件自动形成各自的入口地址,由此进入中断服务程序,从而实现正确的转移。 终端符中断服务程名称 中断引起原因 号 序入口地址 INT0 INT1 T0 T1 T2 TI/RI 外部中断0 外部中断1 定时器0中断 定时器1中断 定时器2中断 串行口中断 P3.2引脚的低电平或下降沿信号 P3.3引脚的低电平或下降沿信号 定时/计数器0计数回零溢出 定时/计数器1计数回零溢出 定时/计数器2计数回零溢出 串行通信完成一帧数据发送或接收 0003H 0013H 000BH 001BH 002BH 0023H

2. 中断系统的控制寄存器 (1) 中断允许控制寄存器IE

IE寄存器有中断屏蔽作用。在中断源与CPU之间有一级控制,类似开关,其中第一级为一个总开关,第二级为五个分开关,由IE控制。在MCS-51中断系统中,中断的允许或禁止是由片内可进行位寻址的8位中断允

许寄存器IE来控制的。见下表

EA

其中EA是总开关,如果它等于0,则所有中断都不允许。

ES-串行口中断允许 ET2-定时器2中断允许 ET1-定时器1中断允许 EX1-外中断1中断允许。 ET0-定时器0中断允许 EX0-外中断0中断允许。

例如:

如果我们要设置允许外中断1,定时器1中断允许,其它不允许,则IE可以是:

EA ES ET1 EX1 ET0 EX0 — — 1 0 0 0 1 1 0 0 即8CH,当然,我们也可以用位操作指令: SETB EA SETB ET1 SETB EX1

(2) 中断请求标志及外部中断凡是选择寄存器TCON TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

IT0和IT1——外部中断请求触发方式控制位,

IT0(IT1)=1脉冲触发方式,下降沿有效 IT0(IT1)=0电平触发方式,低电平有效 IE0和IE1——外部中断请求标志位 IE0(IE1)=1外部中断0(1)置位 IE0(IE1)=0外部中断0(1)复位 TR0和TR1——定时器运行控制位

TR0(TR1)=0定时器/计数器不允许工作 TR0(TR1)=1定时器/计数器允许工作 TF0和TF1——计数器溢出标志位

当计数器产生计数溢出时,相应的溢出标志位由硬件置 1 (3) 中断优先级管理寄存器IP CPU同一时间只能响应一个中断请求。若同时来了两个或两个以上中断

请求,就必须有先有后。为此将5个中断源分成高级、低级两个级别,高级优先,由IP控制。

在MCS-中断优先级中由中断优先级寄存器IP来高置的,IP中某位设为1,相应的中断就是高优先级,否则就是低优先级。

-

- PT2 PS PT1 PX1 PT0 PX0 ET2 ES ET1 EX1 ET0 EX0 IP优先级别寄存器各位介绍如下: PS:串行口中断优先级控制位。 PT2:T2中断优先级控制位。

PT1:T1中断优先级控制位。 PX1:外部中断1优先级控制位。 PT0:T0中断优先级控制位。 PX0:外部中断0优先级控制位。

当某几个中断源在IP寄存器相应位同时为1或0,有内部查询确定优先级,优先级先响应先查询的中断请求。CPU查询的顺序是:

INT0—>T0—>INT1—>T1—>TI/RI—>T2

中断优先原则:(概括为四句话) 1)、低级不打断高级 2)、高级不睬低级 3)、同级不能打断 4)、同级、同时中断,事先约定。

例:设有如下要求,将T0、外中断1设为高优先级,其它为低优先级,求IP的值。

IP的首3位没用,可任意取值,设为000,后面根据要求写就可以了 PS PT1 PX1 PT0 PX0 — — — 0 0 0 0 0 1 1 0 因此,最终,IP的值就是06H。

例:在上例中,如果5个中断请求同时发生,求中断响应的次序。

响应次序:定时器0->外中断1->外中断0->实时器1->串行中断

3. 中断处理过程

(1) 中断请求

中断请求是由是有硬件完成的,当又中断请求时,中断请求标志位会硬件自动置1,系统就会检测到这个请求信息。

(2) 中断响应

1) 中断响应的条件:

中断响应是CPU对中断请求响应的过程,包括保护断点和将程序转向中断服务的入口地址。必须满足的条件是: ①中断源发出中断请求 ②终端总允许位EA=1 ③申请中断的中断源允许 2) 中断响应过程:

首先,中断系统通过硬件自动生成长调用指令,该指令将自动把断点地址压入堆栈保护。然后,将对应的中断入口地址装入程序计数器PC(有硬件自动执行),使程序转向该中断的入口地址,执行中断服务程序。

MCS-51系列单片机各中断源的入口地址由硬件事先设定,使用时,通

常在者些中断入口地址存放一条绝对调转指令,使程序跳转到用户安排的中断服务程序的其实地址中。

(3) 中断处理

中断处理就是执行中断服务程序。中断服务程序从中断入口地址开始执行,到返回指令RETI为止,一般包括两个部分:一是保护现场,二是完成中断源请求的服务。 需要注意的问题:

1) 各个中断源的入口地址之间只相隔8个字节,不可能放得下中断服

务程序,故在中断入口地址单元通常存放一条无条件转移指令,可将中断服务程序存放在存储器的其它空间。

2) 若要在只执行当前中断服务程序是禁止其它更高优先级中断,需要

软件禁止相应优先级高的中断,在中断返回后再开放中断。 3) 中断服务程序中用到的寄存器要进行保护。

(4) 中断返回

中断返回是指中断服务完成之后,计算机返回原来的断开位置(即断点),

继续执行原来的程序。中断返回由返回指令RETI来实现。该指令的功能是把断点地址从堆栈中弹出,送回到程序计数器PC,此外,还要通知通知中断系统已经完成中断处理,并同时清楚优先级状态触发器。

需要注意的是不能用“RET”来代替“RETI”。

总结起来,整个中断处理的过程就是四个阶段:中断请求、中断响应、中断处理、中断返回。CPU相应中断后,在3—8个机器周期内就会执行用户的中断服务程序,程序员在中断服务程序中实现所需要的中断处理,处理完成后返回到原程序继续执行。

实验7 定时器实验

1、实验目的

1.全面掌握定时器及中断的运用 2.了解时钟的工作原理和编程方法 2、实验原理

在工业检测、控制中,很多场合都要用到计数或者定时功能。例如对外部脉冲进行计数、产生精确的定时时间、作串行口的波特率发声器等。MCS-51 单片机内部有两个可编程的定时器/计数器,以满足这方面的需要。

它们具有两种工作模数(计数器模式、 定时器模式)和四种工作方式(方式0、方式1、方式2、方式3),其控制字均在相应的特殊功能寄存器(SFR)中,通过对它的SFR 的编程,可以方便的选择工作模数和工作方式。

80C51 单片机内部设有两个16 位的可编程定时器/计数器。可编程的意思是指其功能(如工作方式、定时时间、量程、启动方式等)均可由指令来确定和改变。在定时器/计数器中除了有两个16 位的计数器之外,还有两个特殊功能寄存器(控制寄存器和方式寄存器)。

1) 定时/计数器T0、T1工作原理

定时/计数器实质上是一个加1计数器,它可以工作在定时方式,也可以工作在计数方式,两种工作方式实际上都是对脉冲计数,只不过所计脉冲的来源不一样。

·定时方式

定时方式,计数器的计数脉冲来自自振荡器的12分频后的脉冲(Fosc/12),及对系统机器周期计数。每过一个机器周期,计数器TH0、TL0、(TH1、TL1)加1,直至计满预设的个数,TH0、TL0、(TH1、TL1)回零,定时/计数器溢出中断标志位TF0(TF1)被置位,产生溢出中断。

·计数方式

计数器T0、T1的计数脉冲分别来自引脚T0(P3.4)或引脚T1(P3.5)上的外部脉冲。计数器对外部能充的下降沿进行加1计数,直至计满,则回零,定时/计数器的中断标志位置1,产生中断。由于检测一个人由1到0的跳变需要2个机器周期,故计数脉冲的频率不能超过Fosc/24。

2)定时器/计数器的方式寄存器TMOD

定时器方式控制寄存器TMOD 在特殊功能寄存器中,字节地址为89H,无位地址。TMOD 的格式如下图所示。

D7 D6 D5 D4 D3 D2 D1 D0 GATE C/T M1 M0 GATE C/T M1 M0

由图可见,TMOD 的高4 位用于T1,低4 使用于T0。4 种符号的含义如下:

GATE:门控制位。GATE 和软件控制位TR、外部引脚信号INT 的状态,共同控制定时器/计数器的打开或关闭。

GATE=1 时,T0、T1 是否计数要受到外部引脚输入电平的控制,INT0 引脚控制T0、INT1 引脚控制T1。可用于测量在INT0 和INT1 引脚出现的正脉冲的宽度。若GATE=0,即不使能门控功能,定时计数器的运行不受外部输入引脚INT0、INT1 的控制。

C/T:定时器/计数器选择位。C/T=1,为计数器方式;C/T=0,为定时器方式。 当为定时器模式时,内部计数器对晶振脉冲12 分频后的脉冲计数,该脉冲周期等于机器周期,所以可以理解为对机器周期进行计数。从计数值可以求得计数的时间,所以称为定时器模式。在计数器模式时,计数器对外部输入引脚T0(P3.4)或T1(P3.5)的外部脉冲(负跳变)计数,允许的最高计数频率为晶振频率的1/24。

M1M0:工作方式选择位,定时器/计数器的4 种工作方式由M1M0 设定。 M1/M0 工作方式 0 0 工作方式0(13位方式) 0 1 工作方式1(16位方式) 1 0 工作方式2(8位自动装入计数初值方式) 1 1 工作方式3(T0为2 个8位方式)

例如:设置T0工作于定时、自启动、方式2,设置语句为:MOV TMOD,#02H 3)定时器/计数器控制寄存器TCON

TCON 在特殊功能寄存器中,字节地址为88H,位地址(由低位到高位)为88H~8FH,由于有位地址,十分便于进行位操作。

TCON 的作用是控制定时器的启停,标志定时器溢出和中断情况。TCON 的格式如下图所示。

D7 D6 D5 D4 D3 D2 D1 D0 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

其中,TFl、TRl、TF0 和TR0 位用于定时器/计数器;IE、ITl、IE0 和IT0 位用于中断系统。

各位定义如下:

TF1:定时器1 溢出标志位。当计时器1 计满溢出时,由硬件使TF1 置“1”,并且申请中断。进入中断服务程序后,由硬件自动清“0”,在查询方式下用软件清“0”。

TR1: 定时器1 运行控制位。由软件清“0”关闭定时器1。当GATE=1,且INT1 为高电平时,TR1 置“1”启动定时器1;当GATE=0,TR1 置“1”启动定时器1。

TF0: 定时器0 溢出标志。其功能及操作情况同TF1。 TR0: 定时器0 运行控制位。其功能及操作情况同TR1。 IE1: 外部中断1 请求标志。

IT1: 外部中断1 触发方式选择位。 IE0: 外部中断0 请求标志。

IT0: 外部中断0 触发方式选择位。 4)定时器/计数器的初始化

由于定时器/计数器的功能是由软件编程确定的,所以一般在使用定时/计数器前都要对其进行初始化,使其按设定的功能工作。初始化的步骤一般如下:

1、确定工作方式( 即对TMOD 赋值); 2、预置定时或计数的初值;

定时/计数器的工作方式不同,其最大计数值也不同,即其模值不同,由于采样加1

计数,为了是计数满后回零,计数初值应该为负。计算机中的负值用补码表示,求补码的方法是用模减去该负数的绝对值。

·计数器初值求法

计数负数:计数初值=模—X(其中X为要计的脉冲的个数)

定时方式:计数初值=【t/MC】补=模—[t/MC] (其中t为预定时间,MC为单片机

的机器周期,MC=12/Fosc)

例如:要计50个脉冲的计数初值

方式0:C=(32H)补=2000H—32H=1FCEH

方式1:C=(32H)补=10000H—32H=1F9CH 方式2:C=(32H)补=100H—32H=CEH

·初值装入方法

方式0是13位的,计数初值的高8位装入TH0(TH1),低5位装入TL0(TL1)

的低5位。对于上面的例子按如下方式进行:

1FCEH=00011111110 01110 TH0 TL0 (其中高三位无效)

方式1为16位,只需将初值的低8位给TL0(TL1),高8位给TH0(TH1)。

方式2为8位自动装入初值方式,初值既要装入TH0(TH1),也要装入TL0(TL1)。但是当计数溢出产生中断之后,在终端服务程序中,用户不需要在人为的软件装入初值,它会自动装入初值。

3、根据需要开放定时器/计数器的中断(直接对IE位赋值);

4、启动定时器/计数器(若已规定用软件启动,则可把TR0或TR1置“1”;若已规定由外中断引脚电平启动,则需给外引脚加启动电平。)当实现了启动要求后,定时器即按规定的工作方式和初值开始计数或定时。

3、实验内容

使用定时器T0,控制一个LED灯的亮灭。灯的闪烁频率为40ms。 4 实验步骤

(1)新建工程timer

(2)在keil集成开发环境下,编写并输入程序,保存为timer.asm(timer.c); (3)在工程源文件中添加文件light.asm(timer.c); (3)编译、连接并生成目标文件;

(4)进入调试状态,单步运行程序,查看片内片外存储器对应单元的数据变化情况。 (5)全速运行程序,观察运行结果。 4 实验参考程序 //端口定义

sbit ledport=P1^0; //============================================

//函 数 名: main()

//功能描述: 利用定时器T0实现时钟功能 //输入参数: 无 //输出参数: 无

//=========================================== void main(void) { TMOD=0x01; //T0定时器工作方式1 TH0=0x63; TL0=0xC0; //40MS中断

ET0=1; //开定时器T0中断 EA=1; //开总中断 TR0=1; //启动定时器T0 while(1);

}

//============================================== //函 数 名: ISR_T0() //功能描述: T0中断函数

//输入参数: 无 //输出参数: 无

//============================================== void ISR_T0(void) interrupt 1 {

TH0=0x63; TL0=0xC0; //重装20MS中断 if(ledport==1)ledport=0; else ledport=1; }

实验8 流水灯控制实验

1 实验目的

(1)熟悉并行接口P0~P3的内部结构 (2)掌握I/O口的基本控制。 2实验原理

(1)8051单片机有4个并行双向I/O口P0、P1、P2、P3,外设可以直接连接在这几个接口

上,每个端口可以按字节输入输出,也可以按位进行输入输出。下面对P0~P3接口的功能进行描述。

P0口:①可以作输入输出口,外接输入输出设备。

需要用户注意的是在作为输入口时,应先对该口写“1”,再进行读操作。 ②在有外接存储器和I/O接口时常作为低8位地址/数据总线,即低8位地址与

数据线分时使用P0口。此时低8位地址由ALE信号的下跳沿使它锁存到外部地址锁存器中,然后,P0口出现数据信息。

P1口:只有单一的输入输出接口功能。和P0口相同,P1口在作为输入口的时候,也

要先进行写“1”,操作,才能读。具体的操作与P0口相同,不再赘述。

P2口:①可作为输入输出口使用。

②在有外接存储器和I/O接口时,作为高8位的地址总线,与P0口低8位地址

一起组成16位地址总线。对于片内无程序存储器的单片机来说,P2口只作为地址总线使用,而不作为I/O口。

P3口:①可作为输入输出口,其操作方法和P2口相同 ②据用第二功能。每一位功能定义如表4.1: 端口引脚 P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7 第二功能 RXD(串行输入线) TXD (串行输出线) INT0(外部中断0输入线) INT1(外部中断1输入线) T0(定时器0外部计数脉冲输入) T1(定时器1外部计数脉冲输入) WR(外部数据存储器写选通信号输出) RD(外部数据存储器读选通信号输出) 由LED电路可看出要使该灯亮,就必须将其对应的发光二极管负端拉低。而由跳线电路可见发光二极管的负端是与P1口对应的,如要是LED1亮,则需P1.0置“0”,即完成给

P1.0端口写“0”操作。但是由于发光二极管的控制端与A,B……DP复用P1口,所以要用跳线帽短接LED端与P1口。 3 实验内容 编写程序实现8个二极管的轮流点亮。 4 实验参考程序

采用软件延时是可以达到延时的目的,但是在延时的这段时间内,单片机实际上处于等待状态,不能进行其他的工作,这样一来,就大大的降低了单片机的工作效率,延长了工作时间,浪费了资源。如果采用定时器实现延时,就可以解决这个问题。定时器定时130ms,在等待130ms到来的这段时间内,单片机可能进行其它的工作,当130ms到来时,进入中断,处理该时段的事务。处理完成退出中断,继续进入中断前的工作。这样,单片机一直处于工作状态,不需要空转,提高了工作效率,特别是对一个任务繁重的大系统来说,这一点尤为重要。程序设计如下:

#include

#define uchar unsigned char #define uint unsigned int

//============常量========= #define ledport P1 //============变量========= bit TSMB; bit LSMB; uchar data TCNT;

//======================================== //函 数 名: main()

//功能描述: 利用定时器T0实现LED闪动功能 //输入参数: 无 //输出参数: 无

//======================================== void main(void) { TMOD=0x01; //T0定时器工作方式1 TH0=0x02; TL0=0x18; //20MS中断 ET0=1; //开定时器T0中断 EA=1; //开总中断 TR0=1; //启动定时器T0 while(1) { if(TSMB!=1) ; //定时时间未到返回 else { TSMB=0; //定时时间到,标志清零 if(TCNT==1) { TCNT=0; //130ms定时时间到,计数缓冲区清零 if(LSMB==1) { LSMB=0; ledport=0x55; } else { LSMB=1; ledport=0xaa; } } else { TCNT++; //计数缓冲区加1 }

} } }

//============================== //函 数 名: ISR_T0() //功能描述: T0中断函数 //输入参数: 无 //输出参数: 无

//=============================== void ISR_T0(void) interrupt 1 { TH0=0x02; TL0=0x18; //重装65MS中断 TSMB=1 ; }

4 实验步骤

(1)在keil集成开发环境下,编写并输入程序,保存为light.asm(light.c); (2)新建工程LIGHT,并添加文件light.asm(light.c); (3)编译、连接并生成目标文件;

(4)进入调试状态,单步运行程序,查看片内片外存储器对应单元的数据变化情况。 (5)全速运行程序,观察运行结果。 5 思考题 1.在实验1的范例程序也是一个流水灯控制的程序,它是一个点亮的灯从左向右,再从右向左的循环,那么还有其他的循环方式,请同学们自己练习。 2.上面的延时程序的作用是什么,将255改成300可以吗,为什么?

实验9 数码管显示实验

1 实验目的

(1)熟悉数码管的工作原理和硬件接口电路 (2)掌握数码管的编程方法 2 实验原理

(1)数码管的显示原理

LED数码管由于结构简单,价格低廉,而得到广泛的应用。外形结构如图所示。

数码管可分为共阳极和共阴极两种类型,共阳极数码管是将8个发光二级管的阳极连接在一起作为公共端,而共阴极是将8个发光二级管的阴极连接在一起作为公共端。8个发光二级管的编号一次为:a,b,c,d,e,f,g和dp,除了与公共端相连接之外的8个引脚分别与数码管的同名引脚相连。公共端作为位选线,而其他位为段选线。

g abfcomaabCOMabcdefgdpCOMfgbcdeecdpfgdpd

数码管结构图 共阴极数码管 共阳极数码管

数码管的显示原理很简单,是通过同名管脚上所加电平的高低来控制发光二极

管是否点亮从而显示不同的字形,假定共阳数码管DP,g,f,e,d,c,b和a分别对应一个字节数据中的bit7,bit6,bit5,bit4,bit3,bit2,bit1和bit0,则数据为“1”的位(TTL高电平)对应段不亮,数据为“0”的位(TTL低电平)对应段点亮,如果将这个字节数据用16进制表示,每一个字形将对应唯一的数值,该数值被称为字形码,8段共阳数码管能显示的常用字符及相应的字形码如下表所示,该表一般存放在程序存储器中,各地址的偏移量为相应字形码对表起始的项数。当然也可以根据需要来设计特殊的字形码,只需要修改码表即可。

共阴数码管的操作方法与共阳数码管基本相同,但是因为公用阴极,数据为“1”的位(TTL高电平)对应段点亮,数据为“0”的位(TTL低电平)对应段不亮,因此共阴数码管与共阳数码管字形码正好相反。

常用的数字和字符共阴极和共阳级的字段码

共阴极 共阳极 显示 D7 D6 D5 D4 D3 D2 D1 D0 字形码 D7 D6 D5 D4 D3 D2 D1 D0 字形码 字符 Dp g f e d c b a Dp g f e d c b a 0 0 0 1 1 1 1 1 1 3FH 1 1 0 0 0 0 0 0 C0H 1 0 0 0 0 0 1 1 0 06H 1 1 1 1 1 0 0 1 F9H 2 0 1 0 1 1 0 1 1 5BH 1 0 1 0 0 1 0 0 A4H 3 0 1 0 0 1 1 1 1 4FH 1 0 1 1 0 0 0 0 B0H 4 0 1 1 0 0 1 1 0 66H 1 0 0 1 1 0 0 1 99H 5 0 1 1 0 1 1 0 1 6DH 1 0 0 1 0 0 1 0 92H 6 0 1 1 1 1 1 0 1 7DH 1 0 0 0 0 0 1 0 82H 7 0 0 0 0 0 1 1 1 07H 1 1 1 1 1 0 0 0 F8H 8 0 1 1 1 1 1 1 1 7FH 1 0 0 0 0 0 0 0 80H 9 0 1 1 0 1 1 1 1 6FH 1 0 0 0 0 0 0 0 90H A 0 1 1 1 0 1 1 1 77H 1 0 0 0 1 0 0 0 88H b 0 1 1 1 1 1 0 0 7CH 1 0 0 0 0 0 1 1 83h C 0 0 1 1 1 0 0 1 39H 1 1 0 0 0 1 1 0 C6H D 0 1 0 1 1 1 1 0 5EH 1 0 1 0 0 0 0 1 A1H E 0 1 1 1 1 0 0 1 79H 1 0 0 0 0 1 1 0 86H F 0 1 1 1 0 0 0 1 71H 1 0 0 0 1 1 1 0 8EH 1 1 1 1 1 1 1 1 FFH 空格 0 0 0 0 0 0 0 0 00H P 0 1 1 1 0 0 1 1 73H 1 0 0 0 1 1 0 0 8CH H 0 1 1 1 0 1 1 0 76H 1 0 0 0 1 0 0 1 89H . 1 0 0 0 0 0 0 0 80H 0 1 1 1 1 1 1 1 7FH - 0 1 0 0 0 0 0 0 40H 1 0 1 1 1 1 1 1 BFH (2) 硬件电路 显示电路采用动态显示方法,可以节约硬件资源,降低系统的设计成本。使用P0

edcomcdp

口低4位作为位选码控制端,P1口作为段选码控制端。

12345678RP21K161514131211101110742195faABCDEFGPDDPY1afegdbcdpfeagdbcdpfegdpbdace3afegdbcdpgdbcdpcom4com3com21298com16COM1Q1COM29012Q2COM39012Q3COM49012Q49012VCC

图1 显示电路图

3 实验原理

在四位数码管上显示1234. 4 实验参考程序

为了便于在本实验中程序的通用性,实验中所有程序均采用模块化设计,即将程序设计成子程序形式,方便各模块间子程序的调用。为此,我们定义了一个显示数据缓冲区displaydata,地址范围从40H~43H。程序中即将把该显示缓冲区中的数据显示到数码管上。

另外程序中要注意的是:

I. 该缓冲区范围内地址不能被其它的资源占用,只能是显示程序或改变显示数据的程序

可以访问。

II. 显示缓冲区中不能存在LED显示码表中显示段码不能表示的非法字符。

III.由于人眼的视觉惰性,当选中某个数码管并送上显示段码,在选择下一个数码管之

前,必须要让显示数据在选择的数码管上停顿一定的时间。这正是本程序在显示程序当中加入了一段延时程序的原因。

//====================================================== //文件名称: 数码管动态扫描

//功能说明: 4位数码管动态扫描,根据LedNum可配置为低于8位 //硬件描述: 段口P1,位口P0.0-P0.3 //使用晶体: 12M晶体

//====================================================== #include

#define uchar unsigned char #define uint unsigned int

//=====================常量============================= #define LedNum 4 //数码管个数6 #define ScanTime 10 //扫描时间,根据实际情况调整 #define DataPort P1 //段口 #define ComPort P0 //位口(4 bit)

//=====================变量============================== uchar data LedDispBuff[LedNum] //数点缓冲区

uchar data ComPortBuf; uchar data ScanBitCnt; uchar data ScanTimeCnt;

//===============数码管码表(共阳极)====================== uchar data CODE[]={ 0xc0,0xf9,0xa4,0xb0, // 0-0 1-1 2-2 3-3 0x99,0x92,0x82,0xf8, // 4-4 5-5 6-6 7-7 0x80,0x90,0xff,0x88, // 8-8 9-9 10-空11-A 0x83,0xc6,0xa1,0x86, // 12-b 13-C 14-D 15-E 0x8e,0x8c,0xc1,0x89, // 16-F 17-P 18-U 19-H 0xc7,0xbf,0x91,0x92, // 20-L 21-- 22-y 23-S 0xf7,0x8b,0xc2,0xa3 // 24-_ 25-h 26-G 27-o };

//========================================================= //函 数 名: MnLed()

//功能描述: LED数码管动态扫描扫描函数 //输入参数: 无 //输出参数: 无

//========================================================= void MnLed(void) {

ComPortBuf = 0xfe;

for(ScanBitCnt=0;ScanBitCnt<=3;ScanBitCnt++) { DataPort=CODE[LedDispBuff[ScanBitCnt]]; //段选 ComPort=ComPortBuf; //位选 ScanTimeCnt=ScanTime; while(ScanTimeCnt--); //扫描延时 ComPort=0xff; ComPortBuf<<=1; ComPortBuf++; } }

//======================================================= //函 数 名: Led6Disp()

//功能描述: LED数码管显示内容修改函数 //输入参数: i,j,m,n,k,h //输出参数: 无

//======================================================= void LedDisp(uchar i,uchar j,uchar m,uchar n) {

LedDispBuff[0] = i; LedDispBuff[1] = j; LedDispBuff[2] = m; LedDispBuff[3] = n; }

实验10 键盘实验

1 实验目的

(1)熟悉键盘的工作原理和硬件接口电路 (2)掌握按键扫描的编程方法 2 实验原理

键盘实现人机交互的主要设备,是应用系统不可缺少的部件。在微机系统应用中,操作人员可以通过键盘输入指令或数据,实现人机对话。键盘可以分为独立式和行列(矩阵)式两类,每一类又可以根据对按键的译码方式分为编码键盘和非编码是键盘两种类型。 (1)工作原理

键盘电路如图所示,P2口8位分别用来检测8个键的状态,当有键按下对应的该I/O

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

Top