《计算机组织结构》实验报告
实验序号:03 实验项目名称: 进位控制实验
第二篇:单片机实验报告
实验一 LED流水灯
一、实验目的
1. 学习单片机并口的使用方法。
2. 学习延时子程序的编写和使用。
3. 学习集成开发环境MedWin的安装与使用。
4. 学习STC单片机在线下载软件STC-ISP的使用。
二、实验内容
所谓流水灯就是8个发光二极管(LED)轮流点亮,周而复始。实验板上以P0口作输出口,经74LS244驱动,接8只发光二极管LED0-LED7。当单片机的引脚输出为低电平时发光二极管点亮,为高电平时息灭。编写程序,使8个发光二极管循环点亮,时间间隔约0.5秒。
三、试验器具
STC89C51, 74LS244,8个限流电阻接8个LED发光管。
四、实验内容
1、74LS244驱动输出串联8个限流电阻接8个LED发光管,以防止其电流过大而烧坏。单片机的主时钟为11.0592MHz。JMP0和JMP1都短接1-2脚。
P0口作为通用接口时是一准双向口,它作为输出口时与一般的双向口使用方法相同。由准双向口结构可知当P0口用作输入口时必须先对它置“1”。若不先对它置“1”,读入的数据是不正确的。输出时需要接上拉电阻,P0口内部没有上拉电阻,若将外围电路设计为低有效,高无效,则无需再外接上拉电阻。
编写一个软件延时子程序,延时时间约0.5秒,采用三重循环实现,汇编语言程序如下:
DELAY: MOV R7, #198
DEL1: MOV R6, #50
DEL2: MOV R5, #23
DJNZ R5, $
DJNZ R6, DEL2
DJNZ R7, DEL1
RET
查指令表可知执行MOV指令需用1个机器周期,DJNZ指令需用2个机器周期,在11.0592MHz晶振时,一个机器周期时间长度为1.085μs,所以该段程序执行时间为:
[1+(1+2×23)×50]×198×1.085μs ≈ 500mS
流水灯的主程序(汇编语言)为:
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: CLR P1.5=0 ; P1.5=0,关闭蜂鸣器。
MOV A,#0FEH
LOP: MOV P0,A
LCALL DELAY
RL A
SJMP LOP
END
2、代码
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: CLR P1.5=0
MOV A,#0FEH
LOP: MOV P0,A
LCALL DELAY
RL A
SJMP LOP
DELAY: MOV R7,#198
DEL1: MOV R6,#50
DEL2: MOV R5,#23
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
END
五、创新
要求实现从左到右先一个LED灯点亮,经过四个LED灯后,再从左到右两个LED灯点亮。一次循环下去。
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: CLR P1.5=0
MOV A,#0EEH
LOP: MOV P0,A
LCALL DELAY
RL A
SJMP LOP
DELAY: MOV R7,#198
DEL1: MOV R6,#50
DEL2: MOV R5,#23
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
END
六、思考题
从中间向两边
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: CLR P1.5=0
MOV A,#0EEH
LOP: MOV P0,A
LCALL DELAY
MOV A,R1
RL A
MOV R1,A
MOV A,R2
RR A
MOV R2,A
MOV A,R1
SWAP A
ADD R2
CPL A
SJMP LOP
DELAY: MOV R7,#198
DEL1: MOV R6,#50
DEL2: MOV R5,#23
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
END
六、实验心得
1. 学会了单片机并口的使用方法。
2. 学会了延时子程序的编写和使用。
3. 学会了集成开发环境MedWin的安装与使用。
4. 学会了STC单片机在线下载软件STC-ISP的使用。
5. 利用51单片机控制LED的亮灭,并且学会了流水灯不同花样的实现
6. 对mov指令的记忆加强,学会运用。
7. 学习对延迟语句的应用。
实验二 用一位数码管循环显示数字0~9
一、实验目的
1. 学习单片机并口的使用方法。
2. 学习延时子程序的编写和使用。
3. 学习LED数码管的驱动、编码。
二、实验内容
实验板上有8个LED数码管,编写程序,使最右边的一个LED数码管循环显示0~9十个数字。时间间隔约0.5秒,其余LED数码管关闭。
三、实验电路连线
实验板上与本实验有关的硬件如下图所示。8个共阳的LED数码管(S0-S7)上同名的引脚连接在一起,由单片机P0口通过74HC244驱动(段控制),R12-R19为限流电阻。单片机P2口的8个引脚分别通过三极管Q0-Q7控制8个LED数码管的公共端(位控制)。单片机的主时钟为11.0592MHz。JMP0短接2-3脚,JMP1短接1-2脚。
四、实验说明
1、P0口和P2都是准双向口,输出时需要接上拉电阻。P0内部没有上拉电阻,P2口内部有弱上拉。
2、下表为驱动LED数码管的段代码表,1--代表对应的笔段亮,0--代表对应的笔段不亮。若需要在最右边(S0)显示数字“5”,只要将从表中查得的段代码2CH写入P0口,再将P2.0置高,P2.1-P2.7置低即可。
4、实现最右边的一个LED数码管循环显示0~9十个数字的汇编语言程序如下:
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV P1,#0FFH
MOV P2,#01H
MOV R1,#00H
LOOP: MOV A,R1
MOV DPTR,#TAB
MOVC A,@A+DPTR
MOV P0,A
LCALL DELAY
INC R1
五、创新思考题
1、分别写出 ABCDEF 六个字母(用于显示十六进制数)的段代码,编写程序,在最右边数码管上实现0-F的循环显示。
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV P1,#0DFH
MOV P2,#01H
MOV R1,#00H
LOOP: MOV A,R1
MOV DPTR,#TAB
MOVC A,@A+DPTR
MOV P0,A
LCALL DELAY
INC R1
MOV A,R1
CJNE A,#7,LOOP
CLR A
MOV R1,A
SJMP LOOP
DELAY: MOV R7,#198
DEL1: MOV R6,#50
DEL2: MOV R5,#23
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
TAB: DB 48H,0C0H,45H,5CH,43H,54H,0D4H
END
2. 能否交替点亮点8个LED数码管?
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN: MOV P1,#0FFH
MOV P2,#01H
MOV R1,#00H
LOOP: MOV A,R1
MOV DPTR,#TAB
MOVC A,@A+DPTR
MOV P0,A
LCALL DELAY
INC R1
MOV A,P2
RL A
MOV P2,A
MOV A,R1
CJNE A,#10,LOOP
CLR A
MOV R1,A
SJMP LOOP
DELAY: MOV R7,#198
DEL1: MOV R6,#50
DEL2: MOV R5,#23
DJNZ R5,$
DJNZ R6,DEL2
DJNZ R7,DEL1
RET
TAB: DB 48H,0EBH,52H,62H,0E1H,64H,44H,0EAH,40H,60H
END
六、实验心得
1. 学会了延时子程序的编写和使用
2. 学会了通过语句使数码管循环点亮。
2、学会了每个数码管上每一个数字8上笔画所代表的含义以及它的代码。
3、学习了利用语句实现数码管上灯的左移、右移、延迟。
实验三 LED数码管的动态驱动
一、实验目的
1. 学习LED数码管的动态驱动编程。
2. 学习使用定时/计数器、中断。
3.学习汇编语言的有关运算。
二、实验内容
编写程序,使实验板上的8个LED数码管稳定显示8个不同的数字,并使这四位数从00000000开始,每0.5秒钟加1。
三、实验电路连线
四、实验说明
1. 在实验二中,我们已经能够让某一个LED数码管显示需要的数字,比如选让第一个LED显示“1”,隔一较短的时间(如2.5毫秒)后关闭第一个LED,让第二个LED显示“2”,如此周而复始,让8个LED依次显1、2、3、4、5、6、7、8,我们就能看到8个LED上稳定地显示8个不同的数字。当然,每个瞬间只有一个LED被点亮,大家亮的时间相同,均为2.5毫秒,8个LED数码管点亮一遍需要20毫秒,一秒钟各亮50次,所以看上去不会有闪烁感,但亮度只是实验二中LED亮度的八分之一。
要实现每隔再隔2.5毫秒变换一个LED,最好的方法是使用定时器中断。
2. 汇编语言参考程序为:
LED_PORT EQU P0 ;笔划输出,低有效
SCN_PORT EQU P2 ;段扫描输出,低有效(P2.4-P2.7)
DSEG
ORG 10H
DISP_BUF: DS 8 ;显示缓冲区
SCN_INX: DS 1 ;扫描指针
SCN_COD: DS 1 ;扫描码
CNT: DS 1 ;中断计数,每2.5ms加1
CSEG
ORG 00H
LJMP MAIN ;主程序入口,转初始化程序
ORG 0BH ;定时中断0入口
LJMP INTP0 ;每2.5ms中断一次,用于刷新显示
;-----------初------始-----化---------------------------------
ORG 30H
MAIN: MOV SP,#50H ;初始化堆栈指针
CLR RS0 ;选用第0组通用寄存器
CLR RS1
CLR P1.5
CLR A
MOV CNT,A
MOV R1,#8
MOV R0,#DISP_BUF
LOOP1: MOV @R0,A ;显示缓冲区清零
INC R0
DJNZ R1,LOOP1
MOV SCN_INX,A ;扫描指针置0
MOV SCN_COD,#80H ;右边LED先点亮
MOV TMOD,#01H ;定时器0,方式1
MOV TH0,#0F7H ;计数初值,每次2.5ms(11.0592MHz晶振)
MOV TL0,#000H ;65536-(2.5ms/1.085us)=65536-2304=63232=0F700H
SETB TR0 ;启动定时器0
SETB EA ;中断总允许
SETB ET0 ;允许定时器0中断
SJMP $ ;主程序在此循环
;-----------定时器0中断服务程序,间隔2.5ms--------------
INTP0: PUSH ACC
PUSH PSW
MOV TH0,#0F7H ;置计数初值
MOV TL0,#00H
SETB RS0 ;选用第1组通用寄存器
CLR RS1
MOV A,SCN_INX ;取扫描指针
ANL A,#07H ;清除高5位
ADD A,#DISP_BUF ;加显示缓冲区首地址
MOV R1,A
MOV A,@R1
MOV DPTR,#CODE_TAB ;DPTR指向笔划代码表
ANL A,#0FH
MOVC A,@A+DPTR ;取笔划代码
MOV LED_PORT,A ;笔划代码送LED口
MOV A,SCN_COD ;取扫描段代码
MOV P2,A
MOV A,SCN_COD
RR A ;扫描段代码循环右移一位
MOV SCN_COD,A
INC SCN_INX ;扫描指针+1
INC CNT
MOV A,CNT
CJNE A,#200,EN
MOV CNT,#0
INC DISP_BUF+7 ;个位加一
MOV A,DISP_BUF+7
CJNE A,#10,EN ;不进位转移
MOV DISP_BUF+7,#0 ;进位则个位清零
INC DISP_BUF+6 ;十位加一
MOV A,DISP_BUF+6
CJNE A,#10,EN
MOV DISP_BUF+6,#0 ;进位则十位清零
INC DISP_BUF+5 ;百位加一
MOV A,DISP_BUF+5
CJNE A,#10,EN
MOV DISP_BUF+5,#0 ;进位则百位清零
INC DISP_BUF+4 ;千位加一
MOV A,DISP_BUF+4
CJNE A,#10,EN
MOV DISP_BUF+4,#0 ;进位则千位清零
INC DISP_BUF+3 ;万位加一
MOV A,DISP_BUF+3
CJNE A,#10,EN
MOV DISP_BUF+3,#0 ;进位则万位清零
INC DISP_BUF+2 ;十万位加一
MOV A,DISP_BUF+2
CJNE A,#10,EN
MOV DISP_BUF+2,#0 ;进位则十万位清零
INC DISP_BUF+1 ;百万位加一
MOV A,DISP_BUF+1
CJNE A,#10,EN
MOV DISP_BUF+1,#0 ;进位则百万位清零
INC DISP_BUF+0 ;千万位加一
MOV A,DISP_BUF+0
CJNE A,#10,EN
MOV DISP_BUF+0,#0 ;进位则千万位清零
EN: POP PSW
POP ACC
RETI
;----------笔划代码表-------------------------
CODE_TAB: DB 48H,0EBH,52H,62H,0E1H,64H,44H,0EAH,40H,60H
END
五、创新
实现时钟的功能。让8个LED数码管从00-00-00开始,每秒钟自动加1,前两位代表时,中间两位代表分,后两位代表秒。
LED_PORT EQU P0 ;笔划输出,低有效
SCN_PORT EQU P2 ;段扫描输出,低有效(P2.4-P2.7)
DSEG
ORG 10H
DISP_BUF: DS 8 ;显示缓冲区
SCN_INX: DS 1 ;扫描指针
SCN_COD: DS 1 ;扫描码
CNT: DS 1 ;中断计数,每2.5ms加1
CSEG
ORG 00H
LJMP MAIN ;主程序入口,转初始化程序
ORG 0BH ;定时中断0入口
LJMP INTP0 ;每2.5ms中断一次,用于刷新显示
;-----------初------始-----化---------------------------------
ORG 30H
MAIN: MOV SP,#50H ;初始化堆栈指针
CLR RS0 ;选用第0组通用寄存器
CLR RS1
CLR P1.5
CLR A
MOV CNT,A
MOV R1,#8
MOV R0,#DISP_BUF
LOOP1: MOV @R0,A ;显示缓冲区清零
INC R0
DJNZ R1,LOOP
MOV SCN_INX,A ;扫描指针置0
MOV SCN_COD,#80H ;右边LED先点亮
MOV DISP_BUF+5,#10
MOV DISP_BUF+2,#10 MOV TMOD,#01H ;定时器0,方式1
MOV TH0,#0F7H ;计数初值,每次2.5ms(11.0592MHz晶振)
MOV TL0,#000H ;65536-(2.5ms/1.085us)=65536-2304=63232=0F700H
SETB TR0 ;启动定时器0
SETB EA ;中断总允许
SETB ET0 ;允许定时器0中断
SJMP $ ;主程序在此循环
;-----------定时器0中断服务程序,间隔2.5ms--------------
INTP0: PUSH ACC
PUSH PSW
MOV TH0,#0F7H ;置计数初值
MOV TL0,#00H
SETB RS0 ;选用第1组通用寄存器
CLR RS1
MOV A,SCN_INX ;取扫描指针
ANL A,#07H ;清除高5位
ADD A,#DISP_BUF ;加显示缓冲区首地址
MOV R1,A
MOV A,@R1
MOV DPTR,#CODE_TAB ;DPTR指向笔划代码表
ANL A,#0FH
MOVC A,@A+DPTR ;取笔划代码
MOV LED_PORT,A ;笔划代码送LED口
MOV A,SCN_COD ;取扫描段代码
MOV P2,A
MOV A,SCN_COD
RR A ;扫描段代码循环右移一位
MOV SCN_COD,A
INC SCN_INX ;扫描指针+1
INC CNT
MOV A,CNT
CJNE A,#200,EN
MOV CNT,#0
INC DISP_BUF+7 ;个位加一
MOV A,DISP_BUF+7
CJNE A,#10,EN ;不进位转移
MOV DISP_BUF+7,#0 ;进位则个位清零
INC DISP_BUF+6 ;十位加一
MOV A,DISP_BUF+6
CJNE A,#6,EN
MOV DISP_BUF+6,#0 ;进位则十位清零
INC DISP_BUF+4 ;千位加一
MOV A,DISP_BUF+4
CJNE A,#10,EN
MOV DISP_BUF+4,#0 ;进位则千位清零
INC DISP_BUF+3 ;万位加一
MOV A,DISP_BUF+3
CJNE A,#6,EN
MOV DISP_BUF+3,#0 ;进位则万位清零
INC DISP_BUF+1 ;百万位加一
MOV A,DISP_BUF+1
CJNE A,#4,EN
MOV DISP_BUF+1,#0 ;进位则百万位清零
INC DISP_BUF+0 ;千万位加一
MOV A,DISP_BUF+0
CJNE A,#2,EN
MOV DISP_BUF+0,#0 ;进位则千万位清零
EN: POP PSW
POP ACC
RETI
;----------笔划代码表-------------------------
CODE_TAB: DB 48H,0EBH,52H,62H,0E1H,64H,44H,0EAH,40H,60H,0F7H
END
六、实验心得
1. 学习了利用51单片机和数码管进行编码,然后实现时钟的控制。
2. 学习了定时器,中断的语句设计和运用。
3. 学习LED数码管的动态驱动编程。
5.学习汇编语言的有关运算。
实验四 用单片机自动演奏乐曲
一、实验目的
(1)进一步熟悉89C51定时器/计数器的功能及应用;
(2)掌握其初始化与中断服务程序的编程方法;
(3)掌握用定时器/计数器发出不同音调的编程方法。
二、实验内容
用单片机的定时器/计数器0作定时器使用,工作于模式1,中断产生方波发声,根据各个的频率,计算对应的定时时间常数,定时器中断后按此常数赋初值,从而发出对应的音调。将歌曲的音调和节拍编成一个表,用音调作为定时器的初值,用节拍控制发音时间, 就可以实现自动演奏。
三、实验电路连线
本实验有关的硬件如右图所示。
四、实验说明
声单定时初值常数计算方法:
根据下表的音阶频率,计算对应的音阶周期T,用T/2计算定时周期数(晶振11.0592MHz),填入下表中。定时器的计数初值为65536-定时周期数,在程序计算产生。定时周期数增加1倍,音阶降低八度,定时周期数降低1倍,音阶升高八度。
自动演奏《东方红》乐曲的C语言程序为:
#include <REG51.h>
#define uchar unsigned char
#define uint unsigned int
sbit P15=P1^5;
code uint cyc[]={3600,3200,2880,2702,2400,2158,1920};//音阶1-7对应的计数周期数
code uchar tone[]={15,15,16,12,11,11,06,12,15,15,16,21,16,15,11,11,
06,12,15,12,11, 7, 6, 5,15,12,13,12,11,11, 6,12,
13,12,11,12,11, 7, 6, 5, 0};//乐曲《东方红》的简谱表
code uchar time[]={ 8, 4, 4,16, 8, 4, 4,16, 8, 8, 4, 4, 4, 4, 8, 4,
4,16, 8, 8, 8, 4, 4, 8, 8, 8, 4, 4, 8, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4,16, 0};//节拍表(8为1拍,约570mS)
uchar H0,L0,cnt;
void cntint0(void) interrupt 1 //定时器0中断用于产生音调
{ TH0=H0;
TL0=L0;
P15=~P15; //P1.5是音乐信号输出脚
}
void cntint1(void) interrupt 3 //定时器1中断用于产生节拍
{ cnt++; //定时器的计数初值为0,所以不用赋值
}
void main(void)
{ uchar i,a,t;
uint b;
next:
TMOD=0x11;
EA=1;
ET0=1;
ET1=1;
cnt=0;
TR1=1;
i=0;
while(1)
{ t=tone[i]; //读音调
if(t==0) break; //是0,则结束
b=cyc[t%10-1];
if(t<10) b=b*2;
if(t>20) b=b/2;
b=b/2;
H0=(65536-b)/256;
L0=(65536-b)%256;
cnt=0;
a=time[i]; //读节拍
if(a!=255) TR0=1; //255是休止符
while(a>cnt);
TR0=0;
i++;
for(b=0;b<1000;b++);
}
P15=1; //关闭喇叭
goto next; //重放一遍
}
五、创新
自动演奏乐曲《八月桂花启遍地开》的汇编语言参考程序。
ORG 0000H
LJMP START
ORG 000BH
INC 20H ;中断服务,中断计数器加1
MOV TH0,#0DCH
MOV TL0,#00H ;11.0592MHz晶振,形成10毫秒中断
RETI
START: MOV SP,#50H
MOV TH0,#0DCH
MOV TL0,#00H
MOV TMOD,#01H
MOV IE,#82H
MUSIC0: NOP
MOV DPTR,#DAT ;表头地址送DPTR
MOV 20H,#00H ;中断计数器清0
MUSIC1: NOP
CLR A ;ACC清零
MOVC A,@A+DPTR ;查表取代码
JZ END0 ;是00H,则结束
CJNE A,#0FFH,MUSIC5 ;如果是休止符,往下执行
LJMP MUSIC3
MUSIC5: NOP
MOV R6,A ;R6=18H音符的频率
INC DPTR ;DPTR加一
MOV A,#0
MOVC A,@A+DPTR ;取节拍代码送R7
MOV R7,A ;R7=30H音符发音的时间
SETB TR0 ;启动计数
MUSIC2: NOP
CPL P1.5 ;P1.5是音乐输出引脚
MOV A,R6
MOV R3,A ;R3=R6=18H
LCALL DEL
MOV A,R7
CJNE A,20H,MUSIC2 ;中断计数器(20H)=R7否? ;不等,则继续循环
MOV 20H,#00H ;等于,则取下一代码
INC DPTR
LJMP MUSIC1
MUSIC3: NOP ;休止100毫秒
CLR TR0
MOV R2,#0DH ;R2=13
MUSIC4: NOP
MOV R3,#0FFH ;R3=255
LCALL DEL
DJNZ R2,MUSIC4
INC DPTR
LJMP MUSIC1
END0: NOP
MOV R2,#0FFH ;歌曲结束,延时1秒后继续
MUSIC6: MOV R3,#00H
LCALL DEL
DJNZ R2,MUSIC6
LJMP MUSIC0
DEL: NOP
DEL3: MOV R4,#02H
DEL4: NOP
DJNZ R4,DEL4
NOP
DJNZ R3,DEL3
RET
DAT: DB 18H,30H,1CH,10H,20H,40H,1CH,10H,18H,10H,20H,10H,1CH,10H,18H,40H
DB 1CH,20H,20H,20H,1CH,20H,18H,20H,20H,80H,0FFH,20H,30H,1CH,10H,18H
DB 20H,15H,20H,1CH,20H,20H,20H,26H,40H,20H,20H,2BH,20H,26H,20H,20H
DB 20H,30H,80H,0FFH,20H,20H,1CH,10H,18H,10H,20H,20H,26H,20H,2BH,20H
DB 30H,20H,2BH,40H,20H,20H,1CH,10H,18H,10H,20H,20H,26H,20H,2BH,20H
DB 30H,20H,2BH,40H,20H,30H,1CH,10H,18H,20H,15H,20H,1CH,20H,20H,20H
DB 26H,40H,20H,20H,2BH,20H,26H,20H,20H,20H,30H,80H,20H,30H,1CH,10H
DB 20H,10H,1CH,10H,20H,20H,26H,20H,2BH,20H,30H,20H,2BH,40H,20H,15H
DB 1FH,05H,20H,10H,1CH,10H,20H,20H,26H,20H,2BH,20H,30H,20H,2BH,40H
DB 20H,30H,1CH,10H,18H,20H,15H,20H,1CH,20H,20H,20H,26H,40H,20H,20H
DB 2BH,20H,26H,20H,20H,20H,30H,30H,20H,30H,1CH,10H,18H,40H,1CH,20H
DB 20H,20H,26H,40H,13H,60H,18H,20H,15H,40H,13H,40H,18H,80H,00H
END
自动演奏《康定情歌》乐曲的C语言程序为:
#include <REG51.h>
#define uchar unsigned char
#define uint unsigned int
sbit P15=P1^5;
code uint cyc[]={3600,3200,2880,2702,2400,2158,1920};//音阶1-7对应的计数周期数
code uchar tone[]={13,15,16,16,15,16,13,12,12, 13,15,16,16,15,16, 13, 13, 13,15,16,16,15,16, 13, 12, 12, 15,13,12,13,12,11, 12, 6, 6, 12,15,13, 12, 6, 16,15,13,12,13,12,11,12, 6, 5, 6 };//乐曲《东方红》的简谱表
code uchar time[]={ 8, 8, 8, 4, 4, 8, 8,12, 4, 8, 8, 8, 4, 4, 8, 16, 8, 8, 8, 8, 4, 4, 8, 8, 12, 4, 8, 8, 4, 4, 4, 4, 8, 24, 8, 24,8,24, 8,16, 8, 8, 8, 4, 4, 4, 4, 8,16, 8, 32};//节拍表(8为1拍,约570mS)
uchar H0,L0,cnt;
void cntint0(void) interrupt 1 //定时器0中断用于产生音调
{ TH0=H0;
TL0=L0;
P15=~P15; //P1.5是音乐信号输出脚
}
void cntint1(void) interrupt 3 //定时器1中断用于产生节拍
{ cnt++; //定时器的计数初值为0,所以不用赋值
}
void main(void)
{ uchar i,a,t;
uint b;
next:
TMOD=0x11;
EA=1;
ET0=1;
ET1=1;
cnt=0;
TR1=1;
i=0;
while(1)
{ t=tone[i]; //读音调
if(t==0) break; //是0,则结束
b=cyc[t%10-1];
if(t<10) b=b*2;
if(t>20) b=b/2;
b=b/2;
H0=(65536-b)/256;
L0=(65536-b)%256;
cnt=0;
a=time[i]; //读节拍
if(a!=255) TR0=1; //255是休止符
while(a>cnt);
TR0=0;
i++;
for(b=0;b<1000;b++);
}
P15=1; //关闭喇叭
goto next; //重放一遍
}
六、实验心得
1. 通过这次实验,我们学习并且设计一些歌曲,然后利用单片机进行实现播放。
2. 通过这次实验,我们学习了计时器的使用方法和原理。
3. 进一步熟悉89C51定时器/计数器的功能及应用。
4. 掌握其初始化与中断服务程序的编程方法。
5. 掌握用定时器/计数器发出不同音调的编程方法。