实验四定时计数器实验电子音响精品文档14页.docx
《实验四定时计数器实验电子音响精品文档14页.docx》由会员分享,可在线阅读,更多相关《实验四定时计数器实验电子音响精品文档14页.docx(20页珍藏版)》请在冰点文库上搜索。
实验四定时计数器实验电子音响精品文档14页
实验四定时/计数器实验
其实,任何一门学科都离不开死记硬背,关键是记忆有技巧,“死记”之后会“活用”。
不记住那些基础知识,怎么会向高层次进军?
尤其是语文学科涉猎的范围很广,要真正提高学生的写作水平,单靠分析文章的写作技巧是远远不够的,必须从基础知识抓起,每天挤一点时间让学生“死记”名篇佳句、名言警句,以及丰富的词语、新颖的材料等。
这样,就会在有限的时间、空间里给学生的脑海里注入无限的内容。
日积月累,积少成多,从而收到水滴石穿,绳锯木断的功效。
一、实验内容
要练说,得练看。
看与说是统一的,看不准就难以说得好。
练看,就是训练幼儿的观察能力,扩大幼儿的认知范围,让幼儿在观察事物、观察生活、观察自然的活动中,积累词汇、理解词义、发展语言。
在运用观察法组织活动时,我着眼观察于观察对象的选择,着力于观察过程的指导,着重于幼儿观察能力和语言表达能力的提高。
1、由51内部定时器0,按方式1工作、即作为十六位定时器使用每0.l秒钟T1溢出中断一次。
P1口的P1.0接1个发光二极管。
要求编写程序模拟一时序控制装置。
开机以中断方式循环点亮,闪烁维持1s。
这个工作可让学生分组负责收集整理,登在小黑板上,每周一换。
要求学生抽空抄录并且阅读成诵。
其目的在于扩大学生的知识面,引导学生关注社会,热爱生活,所以内容要尽量广泛一些,可以分为人生、价值、理想、学习、成长、责任、友谊、爱心、探索、环保等多方面。
如此下去,除假期外,一年便可以积累40多则材料。
如果学生的脑海里有了众多的鲜活生动的材料,写起文章来还用乱翻参考书吗?
2、数码时钟程序,调用定时器中断来处理。
3、编制程序,利用P3口输出不同频率的脉冲通过扬声器发出不同频率音调。
了解计算机发声原理,学习使计算机发出不同音调声音的编程方法。
二、实验目的
1、学习89C51内部计数器的使用和编程方法。
2、进一步掌握中断处理程序的编程方法。
三、实验原理
1、定时常数的确定
定时器/计数器的输入脉冲周期与机器周期一样,为振荡器频率的1/l2。
本实验中时钟频率为12MHZ,现要采用中断方法来实现1秒延时,要在定时器1中设置一个时间常数,使其每隔10MS产生一次中断,CPU响应中断后将R0中计数值减一,令(R0)=100,即可实现1s延时。
时间常数可按下法确定:
机器周期=12÷晶振频率=12÷12×106=1×10-6S
N=t/Tcy=10×10-3/1×10-6=10000
需设初值为X,则(216-X)×1×10-6=0.1
X=65536-10000=55536=D8F0H
化为十六进制:
X=3800H,故初始值为了TH0=D8H,TL0=F0H
2、初始化程序
包括定时器初始化和中断系统初始化,主要是对IP、IE、TCON、TMOD的相应位进行正确的设置,并将时间常数送入定时器中、由于只有定时器中断,IP便不必设置。
如:
MOVTMOD,#01H;置T0工作于方式1
MOVTH0,#0D8H;装入计数初值
MOVTL0,#0F0H
SETBET0;T0开中断
SETBEA;CPU开中断
SETBTR0;启动T0
3、设计中断服务程序和主程序
中断服务程序要将时间常数重新送入定时器中,为下一次中断做准备。
主程序则用来控制发光二极管按要求闪烁。
4、音阶由不同频率的方波产生,音的节拍由延时子程来实现。
延时子程序实现基本延时时间,节拍值只能是它的整数倍。
音阶与频率的关系如下表所示。
方波的频率由定时器控制。
定时器计数溢出后,产生中断,将P1.7口取反即得周期方波。
每个音阶相应的定时器初值可按下法计算:
晶振为6.144MHZ时,音阶“1”相应的定时器初值为x,则
1÷262×2=(216-X)×12÷6.144×1016
可得X=64559D=FC2FH,其它音节可同样求得,见下表:
(单位:
HZ,X为16进制)
音调
4
5
6
7
1
2
3
4
频率
175*2
196*2
220*2
247*2
262*2
294*2
330*2
349*2
X
FA
FA
FB
FC
FC
FC
FC
FD
49
E6
7E
0C
2F
8F
F8
23
5
6
7
1
2
3
392*2
440*/2
494*2
523*2
587*2
659*2
FD
FD
FD
FE
FE
FE
73
BA
FA
18
4C
94
四、实验电路及连线
P1.0接发光二极管L1。
(其他电路参考学习板说明书蜂鸣器与时钟部分)
五、参考程序
程序一、
ORG0000h
AJMPmain
ORG000bh
AJMPint_timer
ORG0030h
main:
MOVtmod,#01h;设置定时器工作方式01
MOVth0,#high(65536-10000);
MOVtl0,#low(65536-10000);设10MS初始值。
MOVie,#82h;设置中断允许寄存器
MOV30h,#10;
MOV31h,#10;30H和31H是两个软件计数器。
SETBtr0;启动定时
AJMP$;等待中断
int_timer:
;定时器0中断服务程序。
MOVth0,#high(65536-10000);
MOVtl0,#low(65536-10000);重设10MS定时。
DJNZ30h,l1;
MOV30h,#10;
DJNZ31h,l1;
MOV31h,#10;软件计数
CPLp1.0;10*10*10MS=1S时间到,P1.0取反
l1:
RETI;中断返回
END
程序二、
/*
数码管精确时钟
*/
#include//包含头文件
sbitbuz=P1^4;
sbitled=P2^0;
#defineshumaP0
sbitLED_0=P2^0;
sbitLED_1=P2^1;
sbitLED_2=P2^2;
sbitLED_3=P2^3;
unsignedcharm,n;
unsignedintd;
unsignedintcodeton[7];
voiddisplay(unsignedchard1,unsignedchard2,unsignedchard3,unsignedchard4);
/*=====0-9=====A-G=====*/
unsignedchara[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0x86,0x8e,0x82};
//共阳极数码管的段码0123456789ABCDEF
//定时初值计算方法:
以5ms为例,5ms=5000us,0xffff-5000/1.085即为TH和TL的值
voidint1()interrupt3//T1中断,时间是5ms
{
unsignedchard1,d2,d3,d4;
TR1=0;//关中断
TH1=0xed;//装定时器初值实现5ms定时
TL1=0xff;
ET1=1;//开中断
TR1=1;
d4=(d%60)%10;//把时间拆分为分和秒
d3=(d%60)/10;
d2=(d/60)%10;
d1=(d/60)/10;
display(d1,d2,d3,d4);//显示分秒
n++;
if(n>=200)//5ms的中断,循环200次,d加一次,所以d是1秒跳1次
{
n=0;
d++;
}
}
voidmain(void)
{
unsignedinti;
d=0;
m=1;
TMOD=0x10;//设置为T1定时器
TH1=0xed;//装定时器初值
TL1=0xff;
TR1=1;//开中断
ET1=1;
EA=1;
while
(1)
{
}
}
//中断专用的显示函数
voiddisplay(unsignedchard1,unsignedchard2,unsignedchard3,unsignedchard4)
{
if(m==1)
{
LED_0=0;//使能该数码管控制位
LED_1=LED_2=LED_3=1;//其他控制位无效
shuma=a[d1];//按照数据点亮该数码管
}
if(m==2)
{
LED_1=0;
LED_0=LED_2=LED_3=1;
shuma=a[d2];
}
if(m==3)
{
LED_2=0;
LED_1=LED_0=LED_3=1;
shuma=a[d3];
}
if(m==4)
{
LED_3=0;
LED_1=LED_2=LED_0=1;
shuma=a[d4];
}
m++;//数码管位循环扫描
if(m>=5)
m=1;
}
程序三、
/*时钟程序,本程序采用外元件DS1302时钟IC,使用此IC不增加系统资源,要时钟时直接去读取就可以了本IC跟ADC0831一样以串口方式传送数据,不同的是协议,只要你读懂它的串口协议,就可以用P口来模拟协议进行
,这样更能使你对传送数据协议的了解,在看本程序之前,先看看芯片的串口协议*/
//---------------------------------------------------------------------------------------------------
//在学习本实验的时候,务必把J-LED的跳线帽,拔到OFF方向,关闭发光二极管
//--------------------------------------------------------------------------------------------------
#include
#include
sbitSCL2=P1^3;//SCL2定义为P1口的第3位脚,连接DS1302SCL和ADC0831SCL脚
sbitSDA2=P1^4;//SDA2定义为P1口的第4位脚,连接DS1302SCL和ADC0831SDA脚
//sbitCS2=P1^6;//CS2定义为P2口的第6位脚,连接ADC0831CS脚
sbitRST=P2^5;//DS1302片选脚
sbitwei1=P2^0;
sbitwei2=P2^1;
sbitwei3=P2^2;
sbitwei4=P2^3;
unsignedcharcodetable[]={0xC0,0xF9,0xA4,0xB0,
0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,
0xC6,0xA1,0x86,0x8E};//共阳数码管码表
//变量定义---------------------------------------------------------------------------------------
unsignedcharl_tmpdate[8]={0x00,0x00,0x0c,0x0d,0x04,0x09,0x01,0};//预设数据,秒分时,日月年,星期
unsignedcharl_tmpdisplay[4]={0,0,0,0};
codeunsignedcharwrite_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
codeunsignedcharread_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//函数声明-------------------------------------------------------------------------------------
voiddelay();//延时子函数,5个空指令
voidDelay_xuS(unsignedintx);
voidled_display(unsignedchar*temp);
voidWrite_Ds1302_byte(unsignedchartemp);
voidWrite_Ds1302(unsignedcharaddress,unsignedchardat);
unsignedcharRead_Ds1302(unsignedcharaddress);
voidRead_RTC(void);//readRTC
voidSet_RTC(void);//setRTC
voidmain(void)//入口函数
{
Set_RTC();//设定时间
Delay_xuS(5);
while
(1){
Read_RTC();
switch(l_tmpdate[0]/5)//设计每个5秒交替显示年月日时分秒
{
case0:
case2:
case4:
case6:
case8:
case10:
l_tmpdisplay[0]=l_tmpdate[1]/16;//数据的转换,因我们采用数码管0~9的显示,将数据分开
l_tmpdisplay[1]=l_tmpdate[1]&0x0f;
l_tmpdisplay[2]=l_tmpdate[0]/16;
l_tmpdisplay[3]=l_tmpdate[0]&0x0f;
break;
case1:
case3:
case5:
case7:
case9:
case11:
l_tmpdisplay[0]=l_tmpdate[4]/16;
l_tmpdisplay[1]=l_tmpdate[4]&0x0f;
l_tmpdisplay[2]=l_tmpdate[3]/16;
l_tmpdisplay[3]=l_tmpdate[3]&0x0f;
break;
default:
break;
}
led_display(l_tmpdisplay);
}
}
/*-------------------------------------------------
功能:
数码管显示子程序
-------------------------------------------------*/
voidled_display(unsignedchar*temp)
{
wei1=0;//点亮第一个数码管
P0=table[temp[0]];
Delay_xuS(5);
wei1=1;
wei2=0;//点亮第二个数码管
P0=table[temp[1]];
Delay_xuS(5);
wei2=1;
wei3=0;//点亮第三个数码管
P0=table[temp[2]];
Delay_xuS(5);
wei3=1;
wei4=0;//点亮第四个数码管
P0=table[temp[3]];
Delay_xuS(5);
wei4=1;
}
voiddelay(void)//空5个指令
{
unsignedchari=10;
while(i)
i--;
}
/*-------------------------------------------------
功能100uS延时子程序
-------------------------------------------------*/
voidDelay_xuS(unsignedintx)
{
unsignedinti,j;
for(i=0;i{
for(j=0;j<50;j++);
}
}
/****************************************************************************/
voidWrite_Ds1302_Byte(unsignedchartemp)
{
unsignedchari;
for(i=0;i<8;i++)//循环8次写入数据
{
SCL2=0;
SDA2=temp&0x01;//每次传输低字节
temp>>=1;//右移一位
SCL2=1;
}
}
/****************************************************************************/
voidWrite_Ds1302(unsignedcharaddress,unsignedchardat)
{
RST=0;
_nop_();
SCL2=0;
_nop_();
RST=1;
_nop_();//启动
Write_Ds1302_Byte(address);//发送地址
Write_Ds1302_Byte(dat);//发送数据
RST=0;//恢复
}
/****************************************************************************/
unsignedcharRead_Ds1302(unsignedcharaddress)
{
unsignedchari,temp=0x00;
RST=0;
_nop_();
SCL2=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
for(i=0;i<8;i++)//循环8次读取数据
{
SCL2=1;
_nop_();
if(SDA2)
temp|=0x80;//每次传输低字节
SCL2=0;
temp>>=1;//右移一位
}
RST=0;
_nop_();
SCL2=1;
SDA2=0;
return(temp);//返回
}
/****************************************************************************/
voidRead_RTC(void)//读取日历
{
unsignedchari,*p;
p=read_rtc_address;//地址传递
for(i=0;i<7;i++)//分7次读取年月日时分秒星期
{
l_tmpdate[i]=Read_Ds1302(*p);
p++;
}
}
/***********************************************************************/
voidSet_RTC(void)//设定日历
{
unsignedchari,*p,tmp;
for(i=0;i<7;i++){
tmp=l_tmpdate[i]/10;
l_tmpdate[i]=l_tmpdate[i]%10;
l_tmpdate[i]=l_tmpdate[i]+tmp*16;
}
Write_Ds1302(0x8E,0X00);
p=write_rtc_address;//传地址
for(i=0;i<7;i++)//依次写入秒时分,日月年,星期
{
Write_Ds1302(*p,l_tmpdate[i]);
p++;
}
Write_Ds1302(0x8E,0x80);
}
程序四、音乐程序八月桂花香
ORG0000H
LJMPSTART
ORG000BH
INC20H;中断服务,中断计数器加1
MOVTH0,#0DBH
MOVTL0,#0FEH;12M晶振,形成10毫秒中断
RETI
START:
CPLP3.4
MOVSP,#50H
MOVTH0,#0DBH
MOVTL0,#0FEH
MOVTMOD,#01H
MOVIE,#82H
MUSIC0:
NOP
MOVDPTR,#DAT;表头地址送DPTR
MOV20H,#00H;中断计数器清0
MOVB,#00H;表序号清0
MUSIC1:
NOP
CLRA
MOVCA,@A+DPTR;查表取代码
JZEND0;是00H,则结束
CJNEA,#0FFH,MUSIC5
LJMPMUSIC3
MUSIC5:
NOP
MOVR6,A
INCDPTR
MOVA,B
MOVCA,@A+DPTR;取节拍代码送R7
MOVR7,A
SETBTR0;启动计数
MUSIC2:
NOP
CPLP3.4
MOVA,R6
MOVR3,A
LCALLDEL
MOVA,R7
CJNEA,20H,MUSIC2;中断计数器(20H)=R7否?
;不等,则继续循环
MOV20H,#00H;等于,则取下一代码
INCDPTR
;INCB
LJMPMUSIC1
MUSIC3:
NOP
CLRTR0;休止100毫秒
MOVR2,#0DH
MUSIC4:
NOP
MOVR3,#0FFH
LCALLDEL
DJNZR2,MUSIC4
INCDPTR
LJMPMUSIC1
END0:
NOP
MOVR2,#64H;歌曲结束,延时1秒后继续
MUSIC6:
MOVR3