at89s51.c

来自「35个51单片机使用的c51程序」· C语言 代码 · 共 3,134 行 · 第 1/5 页

C
3,134
字号
t02s=0; 
flag=~flag; 
} 
if(flag==0) 
{ 
P1_0=~P1_0; 
} 
} 
19 nK…J 
U O *―
' GSP1¨AT89S51)({*ó n~ P1.00^ Eg LM386¨4 E E 9[
`~ 
U *dC )5-
4.19.1 
U 2*4fi9- %E3 
~ ^)(2ˇ4 ,XP1.00^ *ü―4 E yM Ne + ,XSPK IN0^ × 
~ üM Ne + ,XSPK OUT0^ y 8 5 16 ,X[`×
~ ^)(2ˇ4 ,XP3.7/RD0^ *ü―4 E y( 0 K, ,XSP10^ ×
U /: @í@― "
~ *ü)(rn /AuD5. 程序框图 
开 始 
计数单元清零 
TH0,TL0装入初值
开中断,并允许T0中断
秒按键识别成功否 
SECOND加1 
SECOND=60吗 
SECOND=0 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 93 - 
显示数据处理 
分按键识别成功否 
MINITE加1 
MINITE=60吗 
MINITE=0 
显示数据处理 
时按键识别成功否 
HOUR加1 
HOUR=24吗 
HOUR=0 
显示数据处理 
T0中断入口 
通过查表方式显示数据 
数码位选加1 
位选数值=8吗 
位选数值=0 
秒计数=500吗 
秒计数加1 
秒计数=0 
SECOND加1 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 94 - 
6. 汇编源程序 
SECOND EQU 30H 
MINITE EQU 31H 
HOUR EQU 32H 
HOURK BIT P0.0 
MINITEK BIT P0.1 
SECONDK BIT P0.2 
DISPBUF EQU 40H 
DISPBIT EQU 48H 
T2SCNTA EQU 49H 
T2SCNTB EQU 4AH 
TEMP EQU 4BH 
ORG 00H 
LJMP START 
ORG 0BH 
LJMP INT_T0 
START: MOV SECOND,#00H 
MOV MINITE,#00H 
MOV HOUR,#12 
MOV DISPBIT,#00H 
MOV T2SCNTA,#00H 
MOV T2SCNTB,#00H 
MOV TEMP,#0FEH 
LCALL DISP 
MOV TMOD,#01H 
MOV TH0,#(65536-2000) / 256 
MOV TL0,#(65536-2000) MOD 256 
SETB TR0 
SETB ET0 
SETB EA 
WT: JB SECONDK,NK1 
LCALL DELY10MS 
JB SECONDK,NK1 
INC SECOND 
MOV A,SECOND 
CJNE A,#60,NS60 
MOV SECOND,#00H 
NS60: LCALL DISP 
SECOND=60吗 
SECOND=0,并MINITE加1
MINITE=60吗 
MINITE=0,并HOUR加1
HOUR=24吗 
HOUR=0 
显示数据处理 
中断返回 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 95 - 
JNB SECONDK,$ 
NK1: JB MINITEK,NK2 
LCALL DELY10MS 
JB MINITEK,NK2 
INC MINITE 
MOV A,MINITE 
CJNE A,#60,NM60 
MOV MINITE,#00H 
NM60: LCALL DISP 
JNB MINITEK,$ 
NK2: JB HOURK,NK3 
LCALL DELY10MS 
JB HOURK,NK3 
INC HOUR 
MOV A,HOUR 
CJNE A,#24,NH24 
MOV HOUR,#00H 
NH24: LCALL DISP 
JNB HOURK,$ 
NK3: LJMP WT 
DELY10MS: 
MOV R6,#10 
D1: MOV R7,#248 
DJNZ R7,$ 
DJNZ R6,D1 
RET 
DISP: 
MOV A,#DISPBUF 
ADD A,#8 
DEC A 
MOV R1,A 
MOV A,HOUR 
MOV B,#10 
DIV AB 
MOV @R1,A 
DEC R1 
MOV A,B 
MOV @R1,A 
DEC R1 
MOV A,#10 
MOV@R1,A 
DEC R1 
MOV A,MINITE 
MOV B,#10 
DIV AB 
MOV @R1,A 
DEC R1 
MOV A,B 
MOV @R1,A 
DEC R1 
MOV A,#10 
MOV@R1,A 
DEC R1 
MOV A,SECOND 
MOV B,#10 
DIV AB 
MOV @R1,A 
DEC R1 
MOV A,B 
MOV @R1,A 
DEC R1 
RET 
INT_T0: 
MOV TH0,#(65536-2000) / 256 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 96 - 
MOV TL0,#(65536-2000) MOD 256 
MOV A,#DISPBUF 
ADD A,DISPBIT 
MOV R0,A 
MOV A,@R0 
MOV DPTR,#TABLE 
MOVC A,@A+DPTR 
MOV P1,A 
MOV A,DISPBIT 
MOV DPTR,#TAB 
MOVC A,@A+DPTR 
MOV P3,A 
INC DISPBIT 
MOV A,DISPBIT 
CJNE A,#08H,KNA 
MOV DISPBIT,#00H 
KNA: INC T2SCNTA 
MOV A,T2SCNTA 
CJNE A,#100,DONE 
MOV T2SCNTA,#00H 
INC T2SCNTB 
MOV A,T2SCNTB 
CJNE A,#05H,DONE 
MOV T2SCNTB,#00H 
INC SECOND 
MOV A,SECOND 
CJNE A,#60,NEXT 
MOV SECOND,#00H 
INC MINITE 
MOV A,MINITE 
CJNE A,#60,NEXT 
MOV MINITE,#00H 
INC HOUR 
MOV A,HOUR 
CJNE A,#24,NEXT 
MOV HOUR,#00H 
NEXT: LCALL DISP 
DONE: RETI 
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40H 
TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH 
END 
7. C语言源程序 
#include 
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 
0x66,0x6d,0x7d,0x07, 
0x7f,0x6f,0x77,0x7c, 
0x39,0x5e,0x79,0x71,0x00}; 
unsigned char dispbitcode[]={0xfe,0xfd,0xfb,0xf7, 
0xef,0xdf,0xbf,0x7f}; 
unsigned char dispbuf[8]={0,0,16,0,0,16,0,0}; 
unsigned char dispbitcnt; 
unsigned char second; 
unsigned char minite; 
unsigned char hour; 
unsigned int tcnt; 
unsigned char mstcnt; 
unsigned char i,j; 
void main(void) 
{ 
TMOD=0x02; 
TH0=0x06; 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 97 - 
TL0=0x06; 
TR0=1; 
ET0=1; 
EA=1; 
while(1) 
{ 
if(P0_0==0) 
{ 
for(i=5;i>0;i--) 
for(j=248;j>0;j--); 
if(P0_0==0) 
{ 
second++; 
if(second==60) 
{ 
second=0; 
} 
dispbuf[0]=second%10; 
dispbuf[1]=second/10; 
while(P0_0==0); 
} 
} 
if(P0_1==0) 
{ 
for(i=5;i>0;i--) 
for(j=248;j>0;j--); 
if(P0_1==0) 
{ 
minite++; 
if(minite==60) 
{ 
minite=0; 
} 
dispbuf[3]=minite%10; 
dispbuf[4]=minite/10; 
while(P0_1==0); 
} 
} 
if(P0_2==0) 
{ 
for(i=5;i>0;i--) 
for(j=248;j>0;j--); 
if(P0_2==0) 
{ 
hour++; 
if(hour==24) 
{ 
hour=0; 
} 
dispbuf[6]=hour%10; 
dispbuf[7]=hour/10; 
while(P0_2==0); 
} 
} 
} 
} 
void t0(void) interrupt 1 using 0 
{ 
mstcnt++; 
if(mstcnt==8) 
{ 
mstcnt=0; 
P1=dispcode[dispbuf[dispbitcnt]]; 
P3=dispbitcode[dispbitcnt]; 
dispbitcnt++; 
if(dispbitcnt==8) 
{ 
dispbitcnt=0; 
} 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 98 - 
} 
tcnt++; 
if(tcnt==4000) 
{ 
tcnt=0; 
second++; 
if(second==60) 
{ 
second=0; 
minite++; 
if(minite==60) 
{ 
minite=0; 
hour++; 
if(hour==24) 
{ 
hour=0; 
} 
} 
} 
dispbuf[0]=second%10; 
dispbuf[1]=second/10; 
dispbuf[3]=minite%10; 
dispbuf[4]=minite/10; 
dispbuf[6]=hour%10; 
dispbuf[7]=hour/10; 
} 
} 
21. 拉幕式数码显示技术 
1. 实验任务 
用AT89S51单片机的P0.0/AD0-P0.7/AD7端口接数码管的a-h端,8位数码管的S1-S8通过74LS138
译码器的Y0-Y7来控制选通每个数码管的位选端.AT 8 9 S 5 1单片机的P1.0-P1.2控制74LS138的A,
B,C端子.在8位数码管上从右向左循环显示"12345678".能够比较平滑地看到拉幕的效果. 
2. 电路原理图 
AT89S51I /'? ZZZVXSHUPFXFRP
- 99 - 
4.21.1 
U 2*4fi9- %E3 
~1 ^)(2ˇ4 ,XP0.0/AD0 P0.7/AD7*ü88 f4 E y| D- / ,Xa
h0^ × 
~2 ^ A - + ,XY0 Y7*ü88 f4 E y| D- / ,XS1 S80^ 
× 
~3 ^)(2ˇ4 ,XP1.0 P1.20^ *ü3―4 E y A - + ,XA^B^
C0^ × 
4 /: @í@― "
~1 | D- /T×V)E > | ¨+b 6 A} D- 1u/¨?!8¨ U/8
!,XDB¨ NO4 E A}D- 1u EB#/!^ ¨à ! D- 1u/,X K¨ 4zü
1ms4msK¨¨ Z-A !7.B/¨ NO! Lh1ms¨k D- 1u~5àE 
K¨ G *ü)(,Xn /AuD D- /,X í¨ U /) Es8 /4 ¨! /4 > /,XAE
àDBG^~ 
U /: u-
/ c 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 100 - 
中断服务程序框图 
开 始 
显示缓冲区初始化 
必要参数初始化 
T0初始化,TH0,TL0装入初值
T0工作并开中断 
等待中断 
T0中断入口 
通过查表方式,获得显示代码送入P0
位选数据送P1
位选数据=8吗 
位选数据加1 
位选数据=0 
CNT加1
0.4秒定时到了吗 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 101 - 
图4.21.2 
6. 汇编源程序 
DISPBUF EQU 30H 
DISPCNT EQU 38H 
DISPBIT EQU 39H 
T1CNTA EQU 3AH 
T1CNTB EQU 3BH 
CNT EQU 3CH 
ORG 00H 
LJMP START 
ORG 0BH 
LJMP INT_T0 
START: MOV DISPCNT,#8 
MOV A,#10 
MOV R1,#DISPBUF 
LP: MOV @R1,A 
INC R1 
DJNZ DISPCNT,LP 
MOV DISPBIT,#00H 
MOV T1CNTA,#00H 
MOV T1CNTB,#00H 
MOV CNT,#00H 
MOV TMOD,#01H 
MOV TH0,#(65536-1000) / 256 
MOV TL0,#(65536-1000) MOD 256 
SETB TR0 
SETB ET0 
SETB EA 
SJMP $ 
INT_T0: 
MOV TH0,#(65536-1000) / 256 
MOV TL0,#(65536-1000) MOD 256 
MOV A,DISPBIT 
ADD A,#DISPBUF 
MOV R0,A 
MOV A,@R0 
MOV DPTR,#TABLE 
CNT=9吗 
CNT=0
根据CNT来决定显示几位数据 
中断返回 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 102 - 
MOVC A,@A+DPTR 
MOV P0,A 
MOV A,P1 
ANL A,#0F8H 
ADD A,DISPBIT 
MOV P1,A 
INC DISPBIT 
MOV A,DISPBIT 
CJNE A,#08H,NEXT 
MOV DISPBIT,#00H 
NEXT: INC T1CNTA 
MOV A,T1CNTA 
CJNE A,#50,LL1 
MOV T1CNTA,#00H 
INC T1CNTB 
MOV A,T1CNTB 
CJNE A,#8,LL1 
MOV T1CNTB,#00H 
INC CNT 
MOV A,CNT 
CJNE A,#9,LLX 
MOV CNT,#00H 
MOV A,CNT 
LLX: CJNE A,#01H,NEX1 
MOV 30H,#8 
LL1: LJMP DONE 
NEX1: CJNE A,#02H,NEX2 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX2: CJNE A,#03H,NEX3 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX3: CJNE A,#04H,NEX4 
MOV 33H,#8 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX4: CJNE A,#05H,NEX5 
MOV 34H,#8 
MOV 33H,#8 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX5: CJNE A,#06H,NEX6 
MOV 35H,#8 
MOV 34H,#8 
MOV 33H,#8 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX6: CJNE A,#07H,NEX7 
MOV 36H,#8 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 103 - 
MOV 35H,#8 
MOV 34H,#8 
MOV 33H,#8 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX7: CJNE A,#08H,NEX8 
MOV 37H,#8 
MOV 36H,#8 
MOV 35H,#8 
MOV 34H,#8 
MOV 33H,#8 
MOV 32H,#8 
MOV 31H,#8 
MOV 30H,#8 
LJMP DONE 
NEX8: CJNE A,#00H,DONE 
MOV 37H,#10 
MOV 36H,#10 
MOV 35H,#10 
MOV 34H,#10 
MOV 33H,#10 
MOV 32H,#10 
MOV 31H,#10 
MOV 30H,#10 
LL: LJMP DONE 
DONE: RETI 
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,00H 
END 
7. C语言源程序 
#include 
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 
0x66,0x6d,0x7d,0x07, 
0x7f,0x6f,0x77,0x7c, 
0x39,0x5e,0x79,0x71,0x00}; 
unsigned char dispbitcode[]={0xf8,0xf9,0xfa,0xfb, 
0xfc,0xfd,0xfe,0xff}; 
unsigned char dispbuf[8]={16,16,16,16,16,16,16,16}; 
unsigned char dispbitcnt; 
unsigned int t02scnt; 
unsigned char t5mscnt; 
unsigned char u; 
unsigned char i; 
void main(void) 
{ 
TMOD=0x02; 
TH0=0x06; 
TL0=0x06; 
TR0=1; 
ET0=1; 
EA=1; 
while(1); 
} 
void t0(void) interrupt 1 using 0 
{ 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 104 - 
t5mscnt++; 
if(t5mscnt==4) 
{ 
t5mscnt=0; 
P0=dispcode[dispbuf[dispbitcnt]]; 
P1=dispbitcode[dispbitcnt]; 
dispbitcnt++; 
if(dispbitcnt==8) 
{ 
dispbitcnt=0; 
} 
} 
t02scnt++; 
if(t02scnt==1600) 
{ 
t02scnt=0; 
u++; 
if(u==9) 
{ 
u=0; 
} 
for(i=0;i<8;i++) 
{ 
dispbuf[i]=16; 
} 
for(i=0;i K, ,XC1 
C4R1 R40^ × 
4 , G/ cY 
~1 4X4> K, A × 
~2 M ${*ó,X "'× 
OjM $A AEà,XM L4 ,X¨5à! M L h-AEà,XNe)[¨E ^ *üAEà,XNe)[
,X4 ¨G^X U,XM $Z¨'' b)(9{*óAEà,XNe)[M2 ¨ ^ *ü)(
,Xn /AuDM 0oe Ne)[~HZ 1TB- ~T M 0oe Ne)[~HZ 1TB- ~T 
"1DO 262 63628 # 4 FA# 740 64860 
#1DO# 277 63731 5 SO 784 64898 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 106 - 
低2 RE 294 63835 # 5 SO# 831 64934 
#2 RE# 311 63928 中 6 LA 880 64968 
低 3 M 330 64021 # 6 932 64994 
低 4 FA 349 64103 中 7 SI 988 65030 
# 4 FA# 370 64185 高 1 DO 1046 65058 
低 5 SO 392 64260 # 1 DO# 1109 65085 
# 5 SO# 415 64331 高 2 RE 1175 65110 
低 6 LA 440 64400 # 2 RE# 1245 65134 
# 6 466 64463 高 3 M 1318 65157 
低 7 SI 494 64524 高 4 FA 1397 65178 
中 1 DO 523 64580 # 4 FA# 1480 65198 
# 1 DO# 554 64633 高 5 SO 1568 65217 
中 2 RE 587 64684 # 5 SO# 1661 65235 
# 2 RE# 622 64732 高 6 LA 1760 65252 
中 3 M 659 64777 # 6 1865 65268 
中 4 FA 698 64820 高 7 SI 1967 65283 
下面我们要为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据 
低音0-19之间,中音在20-39之间,高音在40-59之间 
TABLE: DW 0,63628,63835,64021,64103,64260,64400,64524,0,0 
DW 0,63731,63928,0,64185,64331,64463,0,0,0 
DW 0,64580,64684,64777,64820,64898,64968,65030,0,0 
DW 0,64633,64732,0,64860,64934,64994,0,0,0 
DW 0,65058,65110,65157,65178,65217,65252,65283,0,0 
DW 0,65085,65134,0,65198,65235,65268,0,0,0 
DW 0 
2,音乐的音拍,一个节拍为单位(C调) 
曲调值 DELAY 曲调值 DELAY 
调4/4 125ms 调4/4 62ms 
调3/4 187ms 调3/4 94ms 
调2/4 250ms 调2/4 125ms 
对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成. 
下面就用AT89S51单片机产生一首"生日快乐"歌曲来说明单片机如何产生的. 
在这个程序中用到了两个定时/计数器来完成的.其中T0用来产生音符频率,T1用来产生音拍. 
5. 程序框图 
AT89S51单片机实验及实践教程 www.supermcu.com 
- 107 - 
图4.22.2 
6. 汇编源程序 
KEYBUF EQU 30H 
STH0 EQU 31H 
STL0 EQU 32H 
TEMP EQU 33H 
ORG 00H 
LJMP START 
ORG 0BH 
LJMP INT_T0 
START: MOV TMOD,#01H 
SETB ET0 
SETB EA 
T0中断入口 
重装TH0,TL0初值
P1.0取反 
中断返回 
开 始 
行列式键盘按键按下成功否 
识别按键功能 
根据按键功能,装入

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?