如何用IO口统计模拟及其r实现I2C来实现两个STC单片机之间的通讯,求C语言写法

热搜关键字:&
购买过本书的顾客还买过
浏览过本书的顾客还看过
根据浏览记录向您推荐
&&STC15增强型8051单片机C语言编程与应用(含CD光盘1张)&&
作&译&者:
出版时间:2014-10
千&字&数:678
版&&&&次:01-01
页&&&&数:424
开&&&&本:16(185*260)
装&&&&帧:
I&S&B&N :8
换&&&&版:
所属分类:&>>&&>>&
纸质书定价:¥69.0&&&会员价:¥55.20&&&折扣:80折&&&节省:¥13
送积分:69&&&&
&&&&库存:有
共有图书评论0 条&&&&&&
STC15增强型8051单片机C语言编程与应用(含CD光盘1张)
与此 件组合商品一同购买
总定价:¥
组合价:¥
本书详细介绍了宏晶科技有限公司研发的STC15系列新型Flash 8051单片机的基本组成、性能特点及应用方法,基于Flash存储器的ISP在系统中编程和IAP在应用中编程的相关技术,结合目前流行的Keil C51编译器环境,对STC15系列单片机采用C语言进行编程应用,充分发挥C51技术优势,全面地展现STC15系列单片机本身特色,如片内晶体振荡器时钟调整,将芯片配置成为具有仿真功能的单片机,Keil uVision4环境下在线仿真调试,1T单周期指令高速执行,I2C、SPI、ADC等片内资源,以及多种片外扩展应用,为读者快速上手提供方便。
电子工业出版社地址:北京市万寿路南口金家村288号 华信大厦&&&&&&服务电话:010-54114
&&Copyright &电子工业出版社&&All rights reserved
出版物经营许可证:当前位置: >>
51单片机c语言编程
11. 闪烁灯 1. 实验任务 如图4.1.1 所示:在P1.0 端口上接一个发光二极管L1,使L1 在不停地一亮一 灭,一亮一灭的时间间隔为0.2 秒。 2. 电路原理图 图4.1.1 3. 系统板上硬件连线 把“单片机系统”区域中的P1.0 端口用导线连接到“八路发光二极管指示模 块”区域中的L1 端口上。 4. 程序设计内容 (1). 延时程序的设计
方法 作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要 求的闪烁时间间隔为0.2 秒,相对于微秒来说,相差太大,所以我们在 执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程 序是如何设计呢?下面具体介绍其原理:2如图4.1.1 所示的石英晶体为12MHz,因此,1 个机器周期为1 微秒 机器周期微秒 MOV R6,#20 2 个机器周期2 D1: MOV R7,#248 2 个机器周期2 2+2×248=498 20× DJNZ R7,$ 2 个机器周期2×248 498 DJNZ R6,D1 2 个机器周期2×20=40 10002 因此,上面的延时程序时间为10.002ms。 由以上可知,当R6=10、R7=248 时,延时5ms,R6=20、R7=248 时, 延时10ms,以此为基本的计时单位。如本实验要求0.2 秒=200ms, 10ms×R5=200ms,则R5=20,延时子程序如下: DELAY: MOV R5,#20 D1: MOV R6,#20 D2: MOV R7,#248 DJNZ R7,$ DJNZ R6,D2 DJNZ R5,D1 RET (2). 输出控制 如图1 所示,当P1.0 端口输出高电平,即P1.0=1 时,根据发光二极管 的单向导电性可知,这时发光二极管L1 熄灭;当P1.0 端口输出低电平, 即P1.0=0 时,发光二极管L1 亮;我们可以使用SETB P1.0 指令使P1.0 端口输出高电平,使用CLR P1.0 指令使P1.0 端口输出低电平。 5. 程序框图 如图4.1.2 所示3图4.1.2 6. 汇编源程序 ORG 0 START: CLR P1.0 LCALL DELAY SETB P1.0 LCALL DELAY LJMP START DELAY: MOV R5,#20 ;延时子程序,延时0.2 秒 D1: MOV R6,#20 D2: MOV R7,#248 DJNZ R7,$ DJNZ R6,D2 DJNZ R5,D1 RET END 7. C 语言源程序 #include &AT89X51.H& sbit L1=P1^0; void delay02s(void) //延时0.2 秒子程序 { unsigned char i,j,k; for(i=20;i&0;i--) for(j=20;j&0;j--) for(k=248;k&0;k--); } void main(void) { while(1) { L1=0; delay02s();4L1=1; delay02s(); } } 2. 模拟开关灯 1. 实验任务 如图4.2.1 所示,监视开关K1(接在P3.0 端口上),用发光二极管L1(接 在单片机P1.0 端口上)显示开关状态,如果开关合上,L1 亮,开关打开, L1 熄灭。 2. 电路原理图 图4.2.1 3. 系统板上硬件连线 (1). 把“单片机系统”区域中的P1.0 端口用导线连接到“八路发光二极管 指示模块” 区域中的L1 端口上; (2). 把“单片机系统”区域中的P3.0 端口用导线连接到“四路拨动开关” 区域中的 K1 端口上; 4. 程序设计内容5(1). 开关状态的检测过程 单片机对开关状态的检测相对于单片机来说, 是从单片机的P3.0 端口输入信号, 而输入的信号只有高电平和低电平两种, 当拨开开关K1 拨上去, 即输入高电平, 相当开关断开,当拨动开关K1 拨下去,即输入低电平,相当开关闭合。单片机 可以采用JB BIT,REL 或者是JNB BIT,REL 指令来完成对开关状态的检测即 可。 (2). 输出控制 如图3 所示,当P1.0 端口输出高电平,即P1.0=1 时,根据发光二极管的单向 导电性可知,这时发光二极管L1 熄灭;当P1.0 端口输出低电平,即P1.0=0 时,发光二极管L1 亮;我们可以使用SETB P1.0 指令使P1.0 端口输出高电平, 使用CLR P1.0 指令使P1.0 端口输出低电平。 5. 程序框图 图4.2.2 6. 汇编源程序ORG 00H START: JB P3.0,LIG CLR P1.0 SJMP START LIG: SETB P1.0 SJMP START END 7. C 语言源程序 #include &AT89X51.H& sbit K1=P3^0; sbit L1=P1^0;6void main(void) { while(1) { if(K1==0) { L1=0; //灯亮 } else { L1=1; //灯灭 } } } 3. 多路开关状态指示 1. 实验任务 如图4.3.1 所示,AT89S51 单片机的P1.0-P1.3 接四个发光二极管L1-L4, P1.4-P1.7 接了四个开关K1-K4,编程将开关的状态反映到发光二极管上。 (开关闭合,对应的灯亮,开关断开,对应的灯灭)。 2. 电路原理图7图4.3.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P1.0-P1.3 用导线连接到“八路发光二 极管指示模块”区域中的L1-L4 端口上; (2. 把“单片机系统”区域中的P1.4-P1.7 用导线连接到“四路拨动开 关”区域中的K1-K4 端口上; 4. 程序设计内容 (1. 开关状态检测 对于开关状态检测,相对单片机来说,是输入关系,我们可轮流检测每个开关状 态,根据每个开关的状态让相应的发光二极管指示,可以采用JB P1.X,REL 或JNB P1.X,REL 指令来完成;也可以一次性检测四路开关状态,然后让其指 示,可以采用MOV A,P1 指令一次把P1 端口的状态全部读入,然后取高4 位的 状态来指示。8(2. 输出控制 根据开关的状态,由发光二极管L1-L4 来指示,我们可以用SETB P1.X 和CLR P1.X 指令来完成,也可以采用MOV P1,#1111XXXXB 方法一次指示。 5. 程序框图读P1 口数据到ACC 中 &![endif]--&图4.3.2 6. 方法一(汇编源程序) ORG 00H START: MOV A,P1 ANL A,#0F0H RR A RR A RR A RR A ORl A,#0F0H MOV P1,A SJMP STARTACC 内容右移4 次 ACC 内容与F0H 相或 ACC 内容送入P1 口9END 7. 方法一(C 语言源程序) #include &AT89X51.H& void main(void) { while(1) { temp=P1&&4; temp=temp | 0xf0; P1= } } 8. 方法二(汇编源程序) ORG 00H START: JB P1.4,NEXT1 CLR P1.0 SJMP NEX1 NEXT1: SETB P1.0 NEX1: JB P1.5,NEXT2 CLR P1.1 SJMP NEX2 NEXT2: SETB P1.1 NEX2: JB P1.6,NEXT3 CLR P1.2 SJMP NEX3 NEXT3: SETB P1.2 NEX3: JB P1.7,NEXT4 CLR P1.3 SJMP NEX4 NEXT4: SETB P1.3 NEX4: SJMP START END 9. 方法二(C 语言源程序) #include &AT89X51.H& void main(void) { while(1) { if(P1_4==0) { P1_0=0; 10} else { P1_0=1; } if(P1_5==0) { P1_1=0; } else { P1_1=1; } if(P1_6==0) { P1_2=0; } else { P1_2=1; } if(P1_7==0) { P1_3=0; } else { P1_3=1; } } } 4. 广告灯的左移右移 1. 实验任务 做单一灯的左移右移,硬件电路如图4.4.1 所示,八个发光二极管L1-L8 分别接在单片机的P1.0-P1.7 接口上,输出“0”时,发光二极管亮,开始 时P1.0→P1.1→P1.2→P1.3→┅→P1.7→P1.6→┅→P1.0 亮,重复循环。 2. 电路原理图11图4.4.1 3. 系统板上硬件连线 把“单片机系统”区域中的P1.0-P1.7 用8 芯排线连接到“八路发光二极管指 示模块” 区域中的L1-L8 端口上, 要求: P1.0 对应着L1, P1.1 对应着L2, ……, P1.7 对应着L8。 4. 程序设计内容 我们可以运用输出端口指令MOV P1,A 或MOV P1,#DATA,只要给累加器 值或常数值,然后执行上述的指令,即可达到输出控制的动作。 每次送出的数据是不同,具体的数据如下表1 所示: P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0 说明 L8 L7 L6 L5 L4 L3 L2 L1 1 1 1 1 1 1 1 0 L1 亮 1 1 1 1 1 1 0 1 L2 亮 1 1 1 1 1 0 1 1 L3 亮 1 1 1 1 0 1 1 1 L4 亮 1 1 1 0 1 1 1 1 L5 亮12表1 5. 程序框图 图4.4.2 6. 汇编源程序 ORG 0 START: MOV R2,#8 MOV A,#0FEH SETB C LOOP: MOV P1,A LCALL DELAY RLC A DJNZ R2,LOOP MOV R2,#8 LOOP1: MOV P1,A LCALL DELAY RRC A DJNZ R2,LOOP1 LJMP START DELAY: MOV R5,#20 ; D1: MOV R6,#20 D2: MOV R7,#248 DJNZ R7,$ DJNZ R6,D2 DJNZ R5,D1 1 1 0 1 1 1 1 1 L6 亮 1 0 1 1 1 1 1 1 L7 亮 0 1 1 1 1 1 1 1 L8 亮13RET END 7. C 语言源程序 #include &AT89X51.H&
unsigned char a,b; void delay(void) { unsigned char m,n,s; for(m=20;m&0;m--) for(n=20;n&0;n--) for(s=248;s&0;s--); } void main(void) { while(1) { temp=0 P1= delay(); for(i=1;i&8;i++) { a=temp&&i; b=temp&&(8-i); P1=a|b; delay(); } for(i=1;i&8;i++) { a=temp&&i; b=temp&&(8-i); P1=a|b; delay(); } } } 5. 广告灯(利用取表方式) 1. 实验任务14利用取表的方法,使端口P1 做单一灯的变化:左移2 次,右移2 次,闪烁2 次 (延时的时间0.2 秒)。 2. 电路原理图 图4.5.1 3. 系统板上硬件连线 把“单片机系统”区域中的P1.0-P1.7 用8 芯排线连接到“八路发光二极 管指示模块”区域中的L1-L8 端口上,要求:P1.0 对应着L1,P1.1 对应 着L2,……,P1.7 对应着L8。 4. 程序设计内容 在用表格进行程序设计的时候,要用以下的指令来完成 (1). 利用MOV DPTR,#DATA16 的指令来使数据指针寄存器指到表的开 头。 (2). 利用MOVC A,@A+DPTR 的指令,根据累加器的值再加上DPTR 的 值,就可以使程序计数器PC 指到表格内所要取出的数据。15因此,只要把控制码建成一个表,而利用MOVC A,@A+DPTR 做取码的操作, 就可方便地处理一些复杂的控制动作,取表过程如下图所示: 5. 程序框图 图4.5.2 6. 汇编源程序 ORG 0 START: MOV DPTR,#TABLE LOOP: CLR A MOVC A,@A+DPTR CJNE A,#01H,LOOP1 JMP START LOOP1: MOV P1,A MOV R3,#20 LCALL DELAY INC DPTR JMP LOOP DELAY: MOV R4,#20 D1: MOV R5,#248 DJNZ R5,$ DJNZ R4,D1 DJNZ R3,DELAY16RET TABLE: DB 0FEH,0FDH,0FBH,0F7H DB 0EFH,0DFH,0BFH,07FH DB 0FEH,0FDH,0FBH,0F7H DB 0EFH,0DFH,0BFH,07FH DB 07FH,0BFH,0DFH,0EFH DB 0F7H,0FBH,0FDH,0FEH DB 07FH,0BFH,0DFH,0EFH DB 0F7H,0FBH,0FDH,0FEH DB 00H, 0FFH,00H, 0FFH DB 01H END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x7f,0xbf,0xdf,0xef, 0xf7,0xfb,0xfd,0xfe, 0x00,0xff,0x00,0xff, 0x01}; void delay(void) { unsigned char m,n,s; for(m=20;m&0;m--) for(n=20;n&0;n--) for(s=248;s&0;s--); } void main(void) { while(1) { if(table[i]!=0x01) { P1=table[i]; i++; delay(); }17else { i=0; } } } 6. 报警产生器 1. 实验任务 用P1.0 输出1KHz 和500Hz 的音频信号驱动扬声器,作报警信号,要求1KHz 信号响100ms,500Hz 信号响200ms,交替进行,P1.7 接一开关进行控制,当 开关合上响报警信号,当开关断开告警信号停止,编出程序。 2. 电路原理图 图4.6.1 3. 系统板上硬件连线18(1. 把“单片机系统”区域中的P1.0 端口用导线连接到“音频放大模块” 区域中的SPK IN 端口上; (2. 在“音频放大模块”区域中的SPK OUT 端口上接上一个8 欧的或者是 16 欧的喇叭; (3. 把“单片机系统”区域中的P1.7/RD 端口用导线连接到“四路拨动开 关”区域中的K1 端口上; 4. 程序设计内容 (1. 信号产生的方法 500Hz 信号周期为2ms,信号电平为每1ms 变反1 次,1KHz 的信号周 期为1ms,信号电平每500us 变反1 次; 5. 程序框图 图4.6.2196. 汇编源程序 FLAG BIT 00H ORG 00H START: JB P1.7,START JNB FLAG,NEXT MOV R2,#200 DV: CPL P1.0 LCALL DELY500 LCALL DELY500 DJNZ R2,DV CPL FLAG NEXT: MOV R2,#200 DV1: CPL P1.0 LCALL DELY500 DJNZ R2,DV1 CPL FLAG SJMP START DELY500: MOV R7,#250 LOOP: NOP DJNZ R7,LOOP RET END 7. C 语言源程序 #include &AT89X51.H& #include &INTRINS.H& void dely500(void) { for(i=250;i&0;i--) { _nop_(); } } void main(void) { while(1) { if(P1_7==0) {20for(count=200;count&0;count--) { P1_0=~P1_0; dely500(); } for(count=200;count&0;count--) { P1_0=~P1_0; dely500(); dely500(); } } } 7. I/O 并行口直接驱动LED 显示 1. 实验任务 如图13 所示,利用AT89S51 单片机的P0 端口的P0.0-P0.7 连接到一个共阴数 码管的a-h 的笔段上,数码管的公共端接地。在数码管上循环显示0-9 数字, 时间间隔0.2 秒。 2. 电路原理图21图4.7.1 3. 系统板上硬件连线 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到“四路 静态数码显示模块”区域中的任一个数码管的a-h 端口上;要求:P0.0/AD0 与 a 相连, P0.1/AD1 与b 相连, P0.2/AD2 与c 相连, ……, P0.7/AD7 与h 相连。 4. 程序设计内容 (1. LED 数码显示原理 七段LED 显示器内部由七个条形发光二极管和一个小圆点发光二极管组成,根 据各管的极管的接线形式,可分成共阴极型和共阳极型。 LED 数码管的g~a 七个发光二极管因加正电压而发亮,因加零电压而不以发亮, 不同亮暗的组合就能形成不同的字形,这种组合称之为字形码,下面给出共阴极 的字形码见表2 “0” 3FH “8” 7FH “1” 06H “9” 6FH “2” 5BH “A” 77H22(2. 由于显示的数字0-9 的字形码没有规律可循,只能采用查表的方式来完 成我们所需的要求了。这样我们按着数字0-9 的顺序,把每个数字的笔段代码 按顺序排好!建立的表格如下所示:TABLE DB 3FH,06H,5BH,4FH,66H,6DH, 7DH, 07H,7FH,6FH 5.程序框图 图4.7.2 6. 汇编源程序 ORG 0 START: MOV R1,#00H NEXT: MOV A,R1 MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A LCALL DELAY INC R1 CJNE R1,#10,NEXT LJMP START DELAY: MOV R5,#20 D2: MOV R6,#20 D1: MOV R7,#248 “3” 4FH “b” 7CH “4” 66H “C” 39H “5” 6DH “d” 5EH “6” 7DH “E” 79H “7” 07H “F” 71H23DJNZ R7,$ DJNZ R6,D1 DJNZ R5,D2 RET TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f}; uns void delay02s(void) { unsigned char i,j,k; for(i=20;i&0;i--) for(j=20;j&0;j--) for(k=248;k&0;k--); } void main(void) { while(1) { for(dispcount=0;dispcount&10;dispcount++) { P0=table[dispcount]; delay02s(); } } } 8. 按键识别方法之一 1. 实验任务 每按下一次开关SP1,计数值加1,通过AT89S51 单片机的P1 端口的P1.0 到P1.3 显示出其的二进制计数值。 2. 电路原理图24图4.8.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P3.7/RD 端口连接到“独立式键盘”区域中的 SP1 端口上; (2. 把“单片机系统”区域中的P1.0-P1.4 端口用8 芯排线连接到“八路发 光二极管指示模块”区域中的“L1-L8”端口上;要求,P1.0 连接到L1, P1.1 连接到L2,P1.2 连接到L3,P1.3 连接到L4 上。 4. 程序设计方法 (1. 其实,作为一个按键从没有按下到按下以及释放是一个完整的过程, 也就是说,当我们按下一个按键时,总希望某个命令只执行一次,而 在按键按下的过程中,不要有干扰进来,因为,在按下的过程中, 一旦有干扰过来,可能造成误触发过程,这并不是我们所想要的。因 此在按键按下的时候,25图4.8.2 要把我们手上的干扰信号以及按键的机械接触等干扰信号给滤除掉,一般情况 下,我们可以采用电容来滤除掉这些干扰信号,但实际上,会增加硬件成本及硬 件电路的体积,这是我们不希望,总得有个办法解决这个问题,因此我们可以采 用软件滤波的方法去除这些干扰 信号,一般情况下,一个按键按下的时候,总是在按下的时刻存在着一定的干扰 信号,按下之后就基本上进入了稳定的状态。具体的一个按键从按下到释放的全 过程的信号图如上图所示: 从图中可以看出,我们在程序设计时,从按键被识别按下之后,延时5ms 以上, 从而避开了干扰信号区域,我们再来检测一次,看按键是否真得已经按下,若真 得已经按下,这时肯定输出为低电平,若这时检测到的是高电平,证明刚才是由 于干扰信号引起的误触发,CPU 就认为是误触发信号而舍弃这次的按键识别过 程。从而提高了系统的可靠性。 由于要求每按下一次,命令被执行一次,直到下一次再按下的时候,再执行一次 命令,因此从按键被识别出来之后,我们就可以执行这次的命令,所以要有一个 等待按键释放的过程,显然释放的过程,就是使其恢复成高电平状态。 (1. 对于按键识别的指令,我们依然选择如下指令JB BIT,REL 指令是用 来检测BIT 是否为高电平,若BIT=1,则程序转向REL 处执行程序, 否则就继续向下执行程序。或者是JNB BIT,REL 指令是用来检测 BIT 是否为低电平,若BIT=0,则程序转向REL 处执行程序,否则就 继续向下执行程序。26(2. 但对程序设计过程中按键识别过程的框图如右图所示: 图4.8.3 5. 程序框图 图4.8.4 6. 汇编源程序 ORG 0 START: MOV R1,#00H ;初始化R1 为0,表示从0 开始计数 MOV A,R1 ; CPL A ;取反指令 MOV P1,A ;送出P1 端口由发光二极管显示 REL: JNB P3.7,REL ;判断SP1 是否按下27LCALL DELAY10MS ;若按下,则延时10ms 左右 JNB P3.7,REL ;再判断SP1 是否真得按下 INC R1 ;若真得按下,则进行按键处理,使 MOV A,R1 ;计数内容加1,并送出P1 端口由 CPL A ;发光二极管显示 MOV P1,A ; JNB P3.7,$ ;等待SP1 释放 SJMP REL ;继续对K1 按键扫描 DELAY10MS: MOV R6,#20 ;延时10ms 子程序 L1: MOV R7,#248 DJNZ R7,$ DJNZ R6,L1 RET END 7. C 语言源程序 #include &AT89X51.H& void delay10ms(void) { unsigned char i,j; for(i=20;i&0;i--) for(j=248;j&0;j--); } void main(void) { while(1) { if(P3_7==0) { delay10ms(); if(P3_7==0) { count++; if(count==16) { count=0; }28P1=~ while(P3_7==0); } } } } 9. 一键多功能按键识别技术 1.实验任务 如图4.9.1 所示,开关SP1 接在P3.7/RD 管脚上,在AT89S51 单片机的P1 端口 接有四个发光二极管,上电的时候,L1 接在P1.0 管脚上的发光二极管在闪烁, 当每一次按下开关SP1 的时候,L2 接在P1.1 管脚上的发光二极管在闪烁,再按 下开关SP1 的时候,L3 接在P1.2 管脚上的发光二极管在闪烁,再按下开关SP1 的时候,L4 接在P1.3 管脚上的发光二极管在闪烁,再按下开关SP1 的时候,又 轮到L1 在闪烁了,如此轮流下去。 2.电路原理图 图4.9.1293.系统板上硬件连线 (1. 把“单片机系统”区域中的P3.7/RD 端口连接到“独立式键盘” 区域中的SP1 端口上; (2. 把“单片机系统”区域中的P1.0-P1.4 端口用8 芯排线连接到“八 路发光二极管指示模块”区域中的“L1-L8”端口上;要求,P1.0 连接到L1,P1.1 连接到L2,P1.2 连接到L3,P1.3 连接到L4 上。 4.程序设计方法 (1. 设计思想由来 在我们生活中,我们很容易通过这个叫张三,那个叫李四,另外一个是王五;那 是因为每个人有不同的名子,我们就很快认出,同样,对于要通过一个按键来识 别每种不同的功能,我们给每个不同的功能模块用不同的ID 号标识,这样,每 按下一次按键,ID 的值是不相同的,所以单片机就很容易识别不同功能的身份 了。 (2. 设计方法 从上面的要求我们可以看出, 到L4 发光二极管在每个时刻的闪烁的时间是受 L1 开关SP1 来控制,我们给L1 到L4 闪烁的时段定义出不同的ID 号,当L1 在闪烁 时,ID=0;当L2 在闪烁时,ID=1;当L3 在闪烁时,ID=2;当L4 在闪烁时, ID=3;很显然,只要每次按下开关K1 时,分别给出不同的ID 号我们就能够完 成上面的任务了。下面给出有关程序设计的框图。 5.程序框图30图4.9.2 6. 汇编源程序 ID EQU 30H SP1 BIT P3.7 L1 BIT P1.0 L2 BIT P1.1 L3 BIT P1.2 L4 BIT P1.3 ORG 0 MOV ID,#00H START: JB K1,REL LCALL DELAY10MS JB K1,REL INC ID MOV A,ID CJNE A,#04,REL MOV ID,#00H REL: JNB K1,$ MOV A,ID31CJNE A,#00H,IS0 CPL L1 LCALL DELAY SJMP START IS0: CJNE A,#01H,IS1 CPL L2 LCALL DELAY SJMP START IS1: CJNE A,#02H,IS2 CPL L3 LCALL DELAY SJMP START IS2: CJNE A,#03H,IS3 CPL L4 LCALL DELAY SJMP START IS3: LJMP START DELAY10MS: MOV R6,#20 LOOP1: MOV R7,#248 DJNZ R7,$ DJNZ R6,LOOP1 RET DELAY: MOV R5,#20 LOOP2: LCALL DELAY10MS DJNZ R5,LOOP2 RET END 7. C 语言源程序 #include &AT89X51.H& unsigned char ID; void delay10ms(void) { unsigned char i,j; for(i=20;i&0;i--) for(j=248;j&0;j--); } void delay02s(void) { for(i=20;i&0;i--) {delay10ms(); } }32void main(void) { while(1) { if(P3_7==0) {delay10ms(); if(P3_7==0) { ID++; if(ID==4) { ID=0; } while(P3_7==0); } } switch(ID) { case 0: P1_0=~P1_0; delay02s(); case 1: P1_1=~P1_1; delay02s(); case 2: P1_2=~P1_2; delay02s(); case 3: P1_3=~P1_3; delay02s(); } } } 10. 00-99 计数器 1. 实验任务 利用AT89S51 单片机来制作一个手动计数器,在AT89S51 单片机的P3.7 管脚接 一个轻触开关,作为手动计数的按钮,用单片机的P2.0-P2.7 接一个共阴数码 管, 作为00-99 计数的个位数显示, 用单片机的P0.0-P0.7 接一个共阴数码管, 作为00-99 计数的十位数显示;硬件电路图如图19 所示。332. 电路原理图 图4.10.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到 “四路静态数码显示模块”区域中的任一个a-h 端口上;要求:P0.0/AD0 对应着a,P0.1/AD1 对应着b,……,P0.7/AD7 对应着h。 (2. 把 “单片机系统” 区域中的P2.0/A8-P2.7/A15 端口用8 芯排线连接到 “四 路静态数码显示模块”区域中的任一个数码管的a-h 端口上; (3. 把“单片机系统”区域中的P3.7/RD 端口用导线连接到“独立式键盘”区 域中的SP1 端口上; 4. 程序设计内容 (1. 单片机对按键的识别的过程处理 (2. 单片机对正确识别的按键进行计数,计数满时,又从零开始计数;34(3. 单片机对计的数值要进行数码显示, 计得的数是十进数, 含有十位和个位, 我们要把十位和个位拆开分别送出这样的十位和个位数值到对应的数码 管上显示。如何拆开十位和个位我们可以把所计得的数值对10 求余,即 可得个位数字,对10 整除,即可得到十位数字了。 (4. 通过查表方式,分别显示出个位和十位数字。 5. 程序框图 图4.10.2 6. 汇编源程序 Count EQU 30H SP1 BIT P3.7 ORG 0 START: MOV Count,#00H NEXT: MOV A,Count MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A WT: JNB SP1,WT WAIT: JB SP1,WAIT LCALL DELY10MS JB SP1,WAIT INC Count MOV A,Count CJNE A,#100,NEXT35LJMP START DELY10MS: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f}; unsigned char C void delay10ms(void) { unsigned char i,j; for(i=20;i&0;i--) for(j=248;j&0;j--); } void main(void) { Count=0; P0=table[Count/10]; P2=table[Count%10]; while(1) { if(P3_7==0) { delay10ms(); if(P3_7==0) { Count++; if(Count==100) { Count=0; } P0=table[Count/10]; P2=table[Count%10]; while(P3_7==0); } } }36} 11. 00-59 秒计时器(利用软件延时) 1. 实验任务 如下图所示,在AT89S51 单片机的P0 和P2 端口分别接有两个共阴数码管, P0 口驱动显示秒时间的十位,而P2 口驱动显示秒时间的个位。 2. 电路原理图 图4.11.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到 “四路静态数码显示模块”区域中的任一个a-h 端口上;要求:P0.0/AD0 对应着a,P0.1/AD1 对应着b,……,P0.7/AD7 对应着h。 (2. 把 “单片机系统” 区域中的P2.0/A8-P2.7/A15 端口用8 芯排线连接到 “四 路静态数码显示模块”区域中的任一个a-h 端口上;要求:P2.0/A8 对 应着a,P2.1/A9 对应着b,……,P2.7/A15 对应着h。 4. 程序设计内容37(1. 在设计过程中我们用一个存储单元作为秒计数单元,当一秒钟到来时,就 让秒计数单元加1,当秒计数达到60 时,就自动返回到0,重新秒计数。 (2. 对于秒计数单元中的数据要把它十位数和个数分开,方法仍采用对10 整 除和对10 求余。 (3. 在数码上显示,仍通过查表的方式完成。 (4. 一秒时间的产生在这里我们采用软件精确延时的方法来完成,经过精确计 算得到1 秒时间为1.002 秒。 DELY1S: MOV R5,#100 D2: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 DJNZ R5,D2 RET 5. 程序框图 图4.11.2386. 汇编源程序 Second EQU 30H ORG 0 START: MOV Second,#00H NEXT: MOV A,Second MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A LCALL DELY1S INC Second MOV A,Second CJNE A,#60,NEXT LJMP START DELY1S: MOV R5,#100 D2: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 DJNZ R5,D2 RET TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f}; unsigned char S void delay1s(void) { unsigned char i,j,k; for(k=100;k&0;k--) for(i=20;i&0;i--) for(j=248;j&0;j--); } void main(void) {39Second=0; P0=table[Second/10]; P2=table[Second%10]; while(1) { delay1s(); Second++; if(Second==60) { Second=0; } P0=table[Second/10]; P2=table[Second%10]; } } 12. 可预置可逆4 位计数器 1. 实验任务 利用AT89S51 单片机的P1.0-P1.3 接四个发光二极管L1-L4,用来指示当前计 数的数据;用P1.4-P1.7 作为预置数据的输入端,接四个拨动开关K1-K4,用 P3.6/WR 和P3.7/RD 端口接两个轻触开关,用来作加计数和减计数开关。具体的 电路原理图如下图所示 2. 电路原理图40图4.12.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P1.0-P1.3 端口用8 芯排线连接到“八路发 光二极管指示模块”区域中的L1-L4 上;要求:P1.0 对应着L1,P1.1 对应着L2,P1.2 对应着L3,P1.3 对应着L4; (2. 把“单片机系统”区域中的P3.0/RXD,P3.1/TXD,P3.2/INT0,P3.3/INT1 用导线连接到“四路拨动开关”区域中的K1-K4 上; (3. 把“单片机系统”区域中的P3.6/WR,P3.7/RD 用导线连接到“独立式键 盘”区域中的SP1 和SP2 上; 4. 程序设计内容 (1. 两个独立式按键识别的处理过程;41(2. 预置初值读取的问题 (3. LED 输出指示 5. 程序框图 图4.12.2 6. 汇编源程序 COUNT EQU 30H ORG 00H START: MOV A,P3 ANL A,#0FH MOV COUNT,A MOV P1,A SK2: JB P3.6,SK1 LCALL DELY10MS JB P3.6,SK1 INC COUNT MOV A,COUNT CJNE A,#16,NEXT MOV A,P342ANL A,#0FH MOV COUNT,A NEXT: MOV P1,A WAIT: JNB P3.6,WAIT LJMP SK2 SK1: JB P3.7,SK2 LCALL DELY10MS JB P3.7,SK2 DEC COUNT MOV A,COUNT CJNE A,#0FFH,NEX MOV A,P3 ANL A,#0FH MOV COUNT,A NEX: MOV P1,A WAIT2: JNB P3.7,WAIT2 LJMP SK2 DELY10MS: MOV R6,#20 MOV R7,#248 D1: DJNZ R7,$ DJNZ R6,D1 RET END 7. C 语言源程序 #include &AT89X51.H& un void delay10ms(void) { unsigned char i,j; for(i=20;i&0;i--) for(j=248;j&0;j--); } void main(void) { curcount=P3 & 0x0f; P1=~ while(1) { if(P3_6==0) {43delay10ms(); if(P3_6==0) { if(curcount&=15) { curcount=15; } else { curcount++; } P1=~ while(P3_6==0); } } if(P3_7==0) { delay10ms(); if(P3_7==0) { if(curcount&=0) { curcount=0; } else { curcount--; } P1=~ while(P3_7==0); } } } } 13. 动态数码显示技术 1. 实验任务 如图4.13.1 所示,P0 端口接动态数码管的字形码笔段,P2 端口接动态数码 管的数位选择端,P1.7 接一个开关,当开关接高电平时,显示“12345”字 样;当开关接低电平时,显示“HELLO”字样。 2. 电路原理图44图4.13.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 用8 芯排线连接到“动 态数码显示”区域中的a-h 端口上; (2. 把“单片机系统”区域中的P2.0/A8-P2.7/A15 用8 芯排线连接到“动态 数码显示”区域中的S1-S8 端口上; (3. 把“单片机系统”区域中的P1.7 端口用导线连接到“独立式键盘”区域 中的SP1 端口上; 4. 程序设计内容 (1. 动态扫描方法45动态接口采用各数码管循环轮流显示的方法,当循环显示频率较高时,利用人眼 的暂留特性, 看不出闪烁显示现象, 这种显示需要一个接口完成字形码的输出 (字 形选择),另一接口完成各数码管的轮流点亮(数位选择)。 (2. 在进行数码显示的时候,要对显示单元开辟8 个显示缓冲区,每个显示缓 冲区装有显示的不同数据即可。 (3. 对于显示的字形码数据我们采用查表方法来完成。 5. 程序框图 图4.13.2 6. 汇编源程序 ORG 00H START: JB P1.7,DIR1 MOV DPTR,#TABLE1 SJMP DIR DIR1: MOV DPTR,#TABLE2 DIR: MOV R0,#00H MOV R1,#01H NEXT: MOV A,R0 MOVC A,@A+DPTR46MOV P0,A MOV A,R1 MOV P2,A LCALL DAY INC R0 RL A MOV R1,A CJNE R1,#0DFH,NEXT SJMP START DAY: MOV R6,#4 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET TABLE1: DB 06H,5BH,4FH,66H,6DH TABLE2: DB 78H,79H,38H,38H,3FH END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table1[]={0x06,0x5b,0x4f,0x66,0x6d}; unsigned char code table2[]={0x78,0x79,0x38,0x38,0x3f}; unsigned char a,b; void main(void) { while(1) { temp=0 for(i=0;i&5;i++) { if(P1_7==1) { P0=table1[i]; } else { P0=table2[i]; } P2= a=temp&&(i+1); b=temp&&(7-i);47temp=a|b; for(a=4;a&0;a--) for(b=248;b&0;b--); } } 14. 4×4 矩阵式键盘识别技术 1. 实验任务 如图4.14.2 所示,用AT89S51 的并行口P1 接4×4 矩阵键盘,以P1.0-P1.3 作输入线,以P1.4-P1.7 作输出线;在数码管上显示每个按键的“0-F”序 号。对应的按键的序号排列如图4.14.1 所示 图4.14.1 2. 硬件电路原理图48图4.14.2 3. 系统板上硬件连线 (1. 把“单片机系统“区域中的P3.0-P3.7 端口用8 芯排线连接到“4X4 行 列式键盘”区域中的C1-C4 R1-R4 端口上; (2. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到 “四路静态数码显示模块”区域中的任一个a-h 端口上;要求:P0.0/AD0 对应着a,P0.1/AD1 对应着b,……,P0.7/AD7 对应着h。 4. 程序设计内容 (1. 4×4 矩阵键盘识别处理 (2. 每个按键有它的行值和列值,行值和列值的组合就是识别这个按键 的编码。矩阵的行线和列线分别通过两并行接口和CPU 通信。每个按 键的状态同样需变成数字量“0”和“1”,开关的一端(列线)通过 电阻接VCC,而接地是通过程序输出数字“0”实现的。键盘处理程序 的任务是:确定有无键按下,判断哪一个键按下,键的功能是什么; 还要消除按键在闭合或断开时的抖动。两个并行口中,一个输出扫描 码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值 和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的 功能。495. 程序框图 图4.14.3 6. 汇编源程序 KEYBUF EQU 30H ORG 00H START: MOV KEYBUF,#2 WAIT: MOV P3,#0FFH CLR P3.4 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 LCALL DELY10MS50MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK1 MOV KEYBUF,#0 LJMP DK1 NK1: CJNE A,#0DH,NK2 MOV KEYBUF,#1 LJMP DK1 NK2: CJNE A,#0BH,NK3 MOV KEYBUF,#2 LJMP DK1 NK3: CJNE A,#07H,NK4 MOV KEYBUF,#3 LJMP DK1 NK4: NOP DK1: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A DK1A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK1A NOKEY1: MOV P3,#0FFH CLR P3.5 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK551MOV KEYBUF,#4 LJMP DK2 NK5: CJNE A,#0DH,NK6 MOV KEYBUF,#5 LJMP DK2 NK6: CJNE A,#0BH,NK7 MOV KEYBUF,#6 LJMP DK2 NK7: CJNE A,#07H,NK8 MOV KEYBUF,#7 LJMP DK2 NK8: NOP DK2: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A DK2A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK2A NOKEY2: MOV P3,#0FFH CLR P3.6 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK9 MOV KEYBUF,#8 LJMP DK3 NK9: CJNE A,#0DH,NK10 MOV KEYBUF,#9 LJMP DK3 NK10: CJNE A,#0BH,NK11 MOV KEYBUF,#1052LJMP DK3 NK11: CJNE A,#07H,NK12 MOV KEYBUF,#11 LJMP DK3 NK12: NOP DK3: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A DK3A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK3A NOKEY3: MOV P3,#0FFH CLR P3.7 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK13 MOV KEYBUF,#12 LJMP DK4 NK13: CJNE A,#0DH,NK14 MOV KEYBUF,#13 LJMP DK4 NK14: CJNE A,#0BH,NK15 MOV KEYBUF,#14 LJMP DK4 NK15: CJNE A,#07H,NK16 MOV KEYBUF,#15 LJMP DK4 NK16: NOP DK4: MOV A,KEYBUF53MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A DK4A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK4A NOKEY4: LJMP WAIT DELY10MS: MOV R6,#10 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; unsigned char i,j; void main(void) { while(1) { P3=0 P3_4=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f;54if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=7; case 0x0d: key=8; case 0x0b: key=9; case 0x07: key=10; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } } P3=0 P3_5=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3;55temp=temp & 0x0f; switch(temp) { case 0x0e: key=4; case 0x0d: key=5; case 0x0b: key=6; case 0x07: key=11; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } } P3=0 P3_6=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) {56case 0x0e: key=1; case 0x0d: key=2; case 0x0b: key=3; case 0x07: key=12; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } } P3=0 P3_7=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=0;57case 0x0d: key=13; case 0x0b: key=14; case 0x07: key=15; } temp=P3; P1_0=~P1_0; P0=table[key]; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } } } } } 15. 定时计数器T0 作定时应用技术(一) 1. 实验任务 用AT89S51 单片机的定时/计数器T0 产生一秒的定时时间,作为秒计数时间,当 一秒产生时,秒计数加1,秒计数到60 时,自动从0 开始。硬件电路如下图所 示 2. 电路原理图58图4.15.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到 “四路静态数码显示模块”区域中的任一个a-h 端口上;要求:P0.0/AD0 对应着a,P0.1/AD1 对应着b,……,P0.7/AD7 对应着h。 (2. 把 “单片机系统” 区域中的P2.0/A8-P2.7/A15 端口用8 芯排线连接到 “四 路静态数码显示模块”区域中的任一个a-h 端口上;要求:P2.0/A8 对 应着a,P2.1/A9 对应着b,……,P2.7/A15 对应着h。 4. 程序设计内容 AT89S51 单片机的内部16 位定时/计数器是一个可编程定时/计数器,它既 可以工作在13 位定时方式,也可以工作在16 位定时方式和8 位定时方式。只要 通过设置特殊功能寄存器TMOD,即可完成。定时/计数器何时工作也是通过软件 来设定TCON 特殊功能寄存器来完成的。 现在我们选择16 位定时工作方式,对于T0 来说,最大定时也只有65536us, 即65.536ms,无法达到我们所需要的1 秒的定时,因此,我们必须通过软件来 处理这个问题,假设我们取T0 的最大定时为50ms,即要定时1 秒需要经过20 次的50ms 的定时。对于这20 次我们就可以采用软件的方法来统计了。59因此,我们设定TMOD=B,即TMOD=01H 下面我们要给T0 定时/计数器的TH0,TL0 装入预置初值,通过下面的公式 可以计算出 TH0=(216-50000) / 256 TL0=(216-50000) MOD 256 当T0 在工作的时候,我们如何得知50ms 的定时时间已到,这回我们通过检 测TCON 特殊功能寄存器中的TF0 标志位,如果TF0=1 表示定时时间已到。 5. 程序框图 图4.15.2 6. 汇编源程序(查询法) SECOND EQU 30H TCOUNT EQU 31H ORG 00H START: MOV SECOND,#00H MOV TCOUNT,#00H60MOV TMOD,#01H MOV TH0,#() MOV TL0,#() SETB TR0 DISP: MOV A,SECOND MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A WAIT: JNB TF0,WAIT CLR TF0 MOV TH0,#() MOV TL0,#() INC TCOUNT MOV A,TCOUNT CJNE A,#20,NEXT/ 256 MOD 256/ 256 MOD 256 MOV TCOUNT,#00H INC SECOND MOV A,SECOND CJNE A,#60,NEX MOV SECOND,#00H NEX: LJMP DISP NEXT: LJMP WAIT TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 7. C 语言源程序(查询法) #include &AT89X51.H& unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};
void main(void) { TMOD=0x01; TH0=()/256; TL0=()%256;61TR0=1; tcount=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; while(1) { if(TF0==1) { tcount++; if(tcount==20) { tcount=0; second++; if(second==60) { second=0; } P0=dispcode[second/10]; P2=dispcode[second%10]; } TF0=0; TH0=()/256; TL0=()%256; } } } 1. 汇编源程序(中断法) SECOND EQU 30H TCOUNT EQU 31H ORG 00H LJMP START ORG 0BH LJMP INT0X START: MOV SECOND,#00H MOV A,SECOND MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A62MOV TCOUNT,#00H MOV TMOD,#01H MOV TH0,#() MOV TL0,#() SETB TR0 SETB ET0 SETB EA SJMP $ INT0X: MOV TH0,#() MOV TL0,#() INC TCOUNT MOV A,TCOUNT CJNE A,#20,NEXT MOV TCOUNT,#00H INC SECOND MOV A,SECOND CJNE A,#60,NEX MOV SECOND,#00H NEX: MOV A,SECOND/ 256 MOD 256/ 256 MOD 256 MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOVC A,@A+DPTR MOV P2,A NEXT: RETI TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 2. C 语言源程序(中断法) #include &AT89X51.H& unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};
void main(void) {63TMOD=0x01; TH0=()/256; TL0=()%256; TR0=1; ET0=1; EA=1; tcount=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; while(1); } void t0(void) interrupt 1 using 0 { tcount++; if(tcount==20) { tcount=0; second++; if(second==60) { second=0; } P0=dispcode[second/10]; P2=dispcode[second%10]; } TH0=()/256; TL0=()%256; } 16. 定时计数器T0 作定时应用技术(二) 1. 实验任务 用AT89S51 的定时/计数器T0 产生2 秒钟的定时,每当2 秒定时到来时,更换指 示灯闪烁,每个指示闪烁的频率为0.2 秒,也就是说,开始L1 指示灯以0.2 秒 的速率闪烁,当2 秒定时到来之后,L2 开始以0.2 秒的速率闪烁,如此循环下 去。0.2 秒的闪烁速率也由定时/计数器T0 来完成。 2. 电路原理图64图4.16.1 3. 系统板硬件连线 (1. 把“单片机系统”区域中的P1.0-P1.3 用导线连接到“八路发光二极管 指示模块”区域中的L1-L4 上 4. 程序设计内容 (1. 由于采用中断方式来完成,因此,对于中断源必须它的中断入口地址, 对于定时/计数器T0 来说,中断入口地址为000BH,因此在中断入口 地方加入长跳转指令来执行中断服务程序。书写汇编源程序格式如下 所示: ORG 00H LJMP START ORG 0BH ;定时/计数器T0 中断入口地址 LJMP INT_T0 START: NOP ;主程序开始 .65. INT_T0: PUSH ACC ;定时/计数器T0 中断服务程序 PUSH PSW . . POP PSW POP ACC RETI ;中断服务程序返回 END (2. 定时2 秒,采用16 位定时50ms,共定时40 次才可达到2 秒,每50ms 产生一中断,定时的40 次数在中断服务程序中完成,同样0.2 秒的 定时,需要4 次才可达到0.2 秒。对于中断程序,在主程序中要对中 断开中断。 (3. 由于每次2 秒定时到时,L1-L4 要交替闪烁。采用ID 来号来识别。 当ID=0 时,L1 在闪烁,当ID=1 时,L2 在闪烁;当ID=2 时,L3 在闪烁;当ID=3 时,L4 在闪烁 5. 程序框图 T0 中断服务程序框图 主程序框图66图4.16.2 6. 汇编源程序 6. 汇编源程序 TCOUNT2S EQU 30H TCNT02S EQU 31H ID EQU 32H ORG 00H LJMP START ORG 0BH67LJMP INT_T0 START: MOV TCOUNT2S,#00H MOV TCNT02S,#00H MOV ID,#00H MOV TMOD,#01H MOV TH0,#() / 256 MOV TL0,#() MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ INT_T0: MOV TH0,#() / 256 MOV TL0,#() MOD 256 INC TCOUNT2S MOV A,TCOUNT2S CJNE A,#40,NEXT MOV TCOUNT2S,#00H INC ID MOV A,ID CJNE A,#04H,NEXT MOV ID,#00H NEXT: INC TCNT02S MOV A,TCNT02S CJNE A,#4,DONE MOV TCNT02S,#00H MOV A,ID CJNE A,#00H,SID1 CPL P1.0 SJMP DONE SID1: CJNE A,#01H,SID2 CPL P1.1 SJMP DONE SID2: CJNE A,#02H,SID3 CPL P1.2 SJMP DONE SID3: CJNE A,#03H,SID4 CPL P1.3 SID4: SJMP DONE DONE: RETI END 7. C 语言源程序 #include &AT89X51.H& unsigned char tcount2s;68unsigned char tcount02s; unsigned char ID; void main(void) { TMOD=0x01; TH0=()/256; TL0=()%256; TR0=1; ET0=1; EA=1; while(1); } void t0(void) interrupt 1 using 0 { tcount2s++; if(tcount2s==40) { tcount2s=0; ID++; if(ID==4) { ID=0; } } tcount02s++; if(tcount02s==4) { tcount02s=0; switch(ID) { case 0: P1_0=~P1_0; case 1: P1_1=~P1_1; case 2: P1_2=~P1_2; case 3: P1_3=~P1_3;69 } } } 17. 99 秒马表设计 1. 实验任务 (1. 开始时,显示“00”,第1 次按下SP1 后就开始计时。 (2. 第2 次按SP1 后,计时停止。 (3. 第3 次按SP1 后,计时归零。 2. 电路原理图 图4.17.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 端口用8 芯排线连接到 “四路静态数码显示模块”区域中的任一个a-h 端口上;要求:P0.0/AD0 对应着a,P0.1/AD1 对应着b,……,P0.7/AD7 对应着h。70(2. 把 “单片机系统” 区域中的P2.0/A8-P2.7/A15 端口用8 芯排线连接到 “四 路静态数码显示模块”区域中的任一个a-h 端口上;要求:P2.0/A8 对 应着a,P2.1/A9 对应着b,……,P2.7/A15 对应着h。 (3. 把“单片机系统“区域中的P3.5/T1 用导线连接到”独立式键盘“区域中 的SP1 端口上; 4. 程序框图 主程序框图 T0 中断服务程序框图71图4.17.2 5. 汇编源程序 TCNTA EQU 30H TCNTB EQU 31H SEC EQU 32H KEYCNT EQU 33H SP1 BIT P3.5 ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV KEYCNT,#00H MOV SEC,#00H MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE72MOVC A,@A+DPTR MOV P2,A MOV TMOD,#02H SETB ET0 SETB EA WT: JB SP1,WT LCALL DELY10MS JB SP1,WT INC KEYCNT MOV A,KEYCNT CJNE A,#01H,KN1 SETB TR0 MOV TH0,#06H MOV TL0,#06H MOV TCNTA,#00H MOV TCNTB,#00H LJMP DKN KN1: CJNE A,#02H,KN2 CLR TR0 LJMP DKN KN2: CJNE A,#03H,DKN MOV SEC,#00H MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P2,A MOV KEYCNT,#00H DKN: JNB SP1,$ LJMP WT DELY10MS: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET INT_T0: INC TCNTA MOV A,TCNTA73CJNE A,#100,NEXT MOV TCNTA,#00H INC TCNTB MOV A,TCNTB CJNE A,#4,NEXT MOV TCNTB,#00H INC SEC MOV A,SEC CJNE A,#100,DONE MOV SEC,#00H DONE: MOV A,SEC MOV B,#10 DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,B MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P2,A NEXT: RETI TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH END 6. C 语言源程序 #include &AT89X51.H& unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};
void main(void) { unsigned char i,j; TMOD=0x02; ET0=1; EA=1; second=0; P0=dispcode[second/10]; P2=dispcode[second%10];74while(1) { if(P3_5==0) { for(i=20;i&0;i--) for(j=248;j&0;j--); if(P3_5==0) { keycnt++; switch(keycnt) { case 1: TH0=0x06; TL0=0x06; TR0=1; case 2: TR0=0; case 3: keycnt=0; second=0; P0=dispcode[second/10]; P2=dispcode[second%10]; } while(P3_5==0); } } } } void t0(void) interrupt 1 using 0 { tcnt++; if(tcnt==400) { tcnt=0; second++; if(second==100) { second=0; } P0=dispcode[second/10];75P2=dispcode[second%10]; } } 18. “嘀、嘀、……”报警声 1. 实验任务 用AT89S51 单片机产生 “嘀、 …” 嘀、 报警声从P1.0 端口输出, 产生频率为1KHz, 根据上面图可知:1KHZ 方波从P1.0 输出0.2 秒,接着0.2 秒从P1.0 输出电平 信号,如此循环下去,就形成我们所需的报警声了。 2. 电路原理图 图4.18.1 3. 系统板硬件连线 (1. 把“单片机系统”区域中的P1.0 端口用导线连接到“音频放大模块”区 域中的SPK IN 端口上, (2. 在“音频放大模块”区域中的SPK OUT 端口上接上一个8 欧或者是16 欧 的喇叭;764. 程序设计方法 (1.生活中我们常常到各种各样的报警声,例如“嘀、嘀、…”就是常见 的一种声音报警声,但对于这种报警声,嘀0.2 秒钟,然后断0.2 秒钟,如此循 环下去,假设嘀声的频率为1KHz,则报警声时序图如下图所示: 上述波形信号如何用单片机来产生呢? (2. 由于要产生上面的信号,我们把上面的信号分成两部分,一部分为1KHZ 方波,占用时间为0.2 秒;另一部分为电平,也是占用0.2 秒;因此,我 们利用单片机的定时/计数器T0 作为定时,可以定时0.2 秒;同时,也要 用单片机产生1KHZ 的方波,对于1KHZ 的方波信号周期为1ms,高电平占 用0.5ms,低电平占用0.5ms,因此也采用定时器T0 来完成0.5ms 的定时; 最后,可以选定定时/计数器T0 的定时时间为0.5ms,而要定时0.2 秒则 是0.5ms 的400 倍,也就是说以0.5ms 定时400 次就达到0.2 秒的定时时 间了。 5. 程序框图 主程序框图 中断服务程序框图77图4.18.2 6. 汇编源程序 T02SA EQU 30H T02SB EQU 31H FLAG BIT 00H ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV T02SA,#00H MOV T02SB,#00H CLR FLAG MOV TMOD,#01H MOV TH0,#() / 256 MOV TL0,#() MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ INT_T0: MOV TH0,#() / 256 MOV TL0,#() MOD 256 INC T02SA78MOV A,T02SA CJNE A,#100,NEXT INC T02SB MOV A,T02SB CJNE A,#04H,NEXT MOV T02SA,#00H MOV T02SB,#00H CPL FLAG NEXT: JB FLAG,DONE CPL P1.0 DONE: RETI END 7. C 语言源程序 #include &AT89X51.H& unsigned int t02s; unsigned char t05 void main(void) { TMOD=0x01; TH0=()/256; TL0=()%256; TR0=1; ET0=1; EA=1; while(1); } void t0(void) interrupt 1 using 0 { TH0=()/256; TL0=()%256; t02s++; if(t02s==400) { t02s=0; flag=~ } if(flag==0) { P1_0=~P1_0; } }7919. “叮咚”门铃 1. 实验任务 当按下开关SP1,AT89S51 单片机产生“叮咚”声从P1.0 端口输出到LM386,经 过放大之后送入喇叭。 2. 电路原理图 图4.19.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P1.0 端口用导线连接到“音频放大模块”区 域中的SPK IN 端口上; (2. 在“音频放大模块”区域中的SPK OUT 端口上接上一个8 欧或者是16 欧 的喇叭; (3. 把“单片机系统”区域中的P3.7/RD 端口用导线连接到“独立式键盘”区 域中的SP1 端口上; 4. 程序设计方法80 (1. 我们用单片机实定时/计数器T0 来产生700HZ 和500HZ 的频率,根据定时 /计数器T0,我们取定时250us,因此,700HZ 的频率要经过3 次250us 的定时,而500HZ 的频率要经过4 次250us 的定时。 (2. 在设计过程, 只有当按下SP1 之后, 才启动T0 开始工作, 当T0 工作完毕, 回到最初状态。 (3. “叮”和“咚”声音各占用0.5 秒,因此定时/计数器T0 要完成0.5 秒的 定时,对于以250us 为基准定时2000 次才可以。 5. 程序框图 主程序框图 T0 中断服务程序框图81图4.19.2 6. 汇编源程序 T5HZ EQU 30H T7HZ EQU 31H T05SA EQU 32H T05SB EQU 33H FLAG BIT 00H STOP BIT 01H SP1 BIT P3.7 ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV TMOD,#02H MOV TH0,#06H MOV TL0,#06H SETB ET0 SETB EA NSP: JB SP1,NSP82LCALL DELY10MS JB SP1,NSP SETB TR0 MOV T5HZ,#00H MOV T7HZ,#00H MOV T05SA,#00H MOV T05SB,#00H CLR FLAG CLR STOP JNB STOP,$ LJMP NSP DELY10MS: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET INT_T0: INC T05SA MOV A,T05SA CJNE A,#100,NEXT MOV T05SA,#00H INC T05SB MOV A,T05SB CJNE A,#20,NEXT MOV T05SB,#00H JB FLAG,STP CPL FLAG LJMP NEXT STP: SETB STOP CLR TR0 LJMP DONE NEXT: JB FLAG,S5HZ INC T7HZ MOV A,T7HZ CJNE A,#03H,DONE MOV T7HZ,#00H CPL P1.0 LJMP DONE S5HZ: INC T5HZ MOV A,T5HZ CJNE A,#04H,DONE MOV T5HZ,#00H CPL P1.0 LJMP DONE DONE: RETI83END 7. C 语言源程序 #include &AT89X51.H& unsigned char t5 unsigned char t7 void main(void) { unsigned char i,j; TMOD=0x02; TH0=0x06; TL0=0x06; ET0=1; EA=1; while(1) { if(P3_7==0) { for(i=10;i&0;i--) for(j=248;j&0;j--); if(P3_7==0) { t5hz=0; t7hz=0; tcnt=0; flag=0; stop=0; TR0=1; while(stop==0); } } } } void t0(void) interrupt 1 using 0 { tcnt++;84if(tcnt==2000) { tcnt=0; if(flag==0) { flag=~ } else { stop=1; TR0=0; } } if(flag==0) { t7hz++; if(t7hz==3) { t7hz=0; P1_0=~P1_0; } } else { t5hz++; if(t5hz==4) { t5hz=0; P1_0=~P1_0; } } } 20. 数字钟z★{ 1. 实验任务 (1. 开机时,显示12:00:00 的时间开始计时; (2. P0.0/AD0 控制“秒”的调整,每按一次加1 秒; (3. P0.1/AD1 控制“分”的调整,每按一次加1 分; (4. P0.2/AD2 控制“时”的调整,每按一次加1 个小时;852. 电路原理图 图4.20.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P1.0-P1.7 端口用8 芯排线连接到“动态数 码显示”区域中的A-H 端口上; (2. 把“单片机系统:区域中的P3.0-P3.7 端口用8 芯排线连接到“动态数 码显示”区域中的S1-S8 端口上; (3. 把“单片机系统”区域中的P0.0/AD0、P0.1/AD1、P0.2/AD2 端口分别用 导线连接到“独立式键盘”区域中的SP3、SP2、SP1 端口上; 4. 相关基本知识86(1. 动态数码显示的方法 (2. 独立式按键识别过程 (3. “时”,“分”,“秒”数据送出显示处理方法 5. 程序框图87 886. 汇编源程序 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,#() / 256 MOV TL0,#() 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 JNB SECONDK,$ NK1: JB MINITEK,NK2 LCALL DELY10MS JB MINITEK,NK2 INC MINITE89MOV 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,A90DEC 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,#() / 256 MOV TL0,#() 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 MINITE91MOV 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 &AT89X51.H& 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}; unsi
unsigned char i,j; void main(void) { TMOD=0x02; TH0=0x06; TL0=0x06; TR0=1; ET0=1; EA=1; while(1) { if(P0_0==0)92{ 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;93while(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; } } 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;94} } 21. 拉幕式数码显示技术 1. 实验任务 用AT89S51 单片机的P0.0/AD0-P0.7/AD7 端口接数码管的a-h 端, 位数码管 8 的S1-S8 通过74LS138 译码器的Y0-Y7 来控制选通每个数码管的位选端。 AT89S51 单片机的P1.0-P1.2 控制74LS138 的A,B,C 端子。在8 位数码管上 从右向左循环显示“”。能够比较平滑地看到拉幕的效果。 2. 电路原理图 图4.21.1 3. 系统板上硬件连线95(1. 把“单片机系统”区域中的P0.0/AD0-P0.7/AD7 用8 芯排线连接到“动 态数码显示”区域中的a-h 端口上; (2. 把 “三八译码模块” 区域中的Y0-Y7 用8 芯排线连接到 “动态数码显示” 区域中的S1-S8 端口上; (3. 把“单片机系统”区域中的P1.0-P1.2 端口用3 根导线连接到“三八译 码模块”区域中的A、B、C“端口上; 4. 程序设计方法 (1. 动态数码显示技术;如何进行动态扫描,由于一次只能让一个数码管 显示,因此,要显示8 位的数据,必须经过让数码管一个一个轮流显 示才可以,同时每个数码管显示的时间大约在1ms 到4ms 之间,所以 为了保证正确显示,我必须每隔1ms,就得刷新一个数码管。而这刷 新时间我们采用单片机的定时/计数器T0 来控制,每定时1ms 对数码 管刷新一次,T0 采用方式2。 (2. 在进行数码显示的时候,要对显示单元开辟8 个显示缓冲区,每个显 示缓冲区装有显示的不同数据即可。 5. 程序框图 主程序框图 中断服务程序框图96图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_T097START: 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,#() MOV TL0,#() SETB TR0 SETB ET0 SETB EA SJMP $ INT_T0: MOV TH0,#() MOV TL0,#() MOV A,DISPBIT ADD A,#DISPBUF MOV R0,A MOV A,@R0 MOV DPTR,#TABLE 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,#00H98/ 256 MOD 256/ 256 MOD 256INC 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 MOV 35H,#8 MOV 34H,#8 MOV 33H,#8 MOV 32H,#899MOV 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 &AT89X51.H& 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}; unsi unsigned int t02 unsigned char t5 void main(void) { TMOD=0x02;100TH0=0x06; TL0=0x06; TR0=1; ET0=1; EA=1; while(1); } void t0(void) interrupt 1 using 0 { 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&u;i++) { dispbuf[i]=8; } } } 22. 电子琴1011. 实验任务 (1. 由4X4 组成16 个按钮矩阵,设计成16 个音。 (2. 可随意弹奏想要表达的音乐。 2. 电路原理图 图4.22.1 3. 系统板硬件连线 (1. 把“单片机系统”区域中的P1.0 端口用导线连接到“音频放大模块”区 域中的SPK IN 端口上;102(2. 把“单片机系统“区域中的P3.0-P3.7 端口用8 芯排线连接到“4X4 行 列式键盘”区域中的C1-C4 R1-R4 端口上; 4. 相关程序内容 (1. 4X4 行列式键盘识别; (2. 音乐产生的方法; 一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我 们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片 机来产生不同的频率非常方便, 我们可以利用单片机的定时/计数器T0 来产生这 样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。 现在以单片机12MHZ 晶振为例,例出高中低音符与单片机计数T0 相关的计数值 如下表所示 下面我们要为这个音符建立一个表格, 有助于单片机通过查表的方式来获得相应 的数据 低音0-19 之间,中音在20-39 之间,高音在40-59 之间 TABLE: DW 0,,,, DW 0,,0,,,0 音符频率(HZ) 简谱码( T 值) 音符频率(HZ) 简谱码( T 值) 低1 DO 262 63628 # 4 FA# 740 64860 #1 DO# 277 63731 中5 SO 784 64898 低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
低5 SO 392 64260 # 1 DO#
# 5 SO# 415 64331 高2 RE
低6 LA 440 64400 # 2 RE#
# 6 466 64463 高3 M
低7 SI 494 64524 高4 FA
中1 DO 523 64580 # 4 FA#
# 1 DO# 554 64633 高5 SO
中2 RE 587 64684 # 5 SO#
# 2 RE# 622 64732 高6 LA
中3 M 659 64777 # 6
中4 FA 698 64820 高7 SI 103DW DW DW DW DW0,,,, 0,,0,,,0 0,,,, 0,,0,,,0 0 2、音乐的音拍,一个节拍为单位(C 调) 对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成。 下面就用AT89S51 单片机产生一首“生日快乐”歌曲来说明单片机如何产生的。 在这个程序中用到了两个定时/计数器来完成的。其中T0 用来产生音符频率,T1 用来产生音拍。 5. 程序框图 图4.22.2 6. 汇编源程序 KEYBUF EQU 30H STH0 EQU 31H STL0 EQU 32H TEMP EQU 33H 曲调值DELAY 曲调值DELAY 调4/4 125ms 调4/4 62ms 调3/4 187ms 调3/4 94ms 调2/4 250ms 调2/4 125ms104ORG 00H LJMP START ORG 0BH LJMP INT_T0 START: MOV TMOD,#01H SETB ET0 SETB EA WAIT: MOV P3,#0FFH CLR P3.4 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY1 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK1 MOV KEYBUF,#0 LJMP DK1 NK1: CJNE A,#0DH,NK2 MOV KEYBUF,#1 LJMP DK1 NK2: CJNE A,#0BH,NK3 MOV KEYBUF,#2 LJMP DK1 NK3: CJNE A,#07H,NK4 MOV KEYBUF,#3 LJMP DK1 NK4: NOP DK1: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,KEYBUF MOV B,#2 MUL AB MOV TEMP,A MOV DPTR,#TABLE1105MOVC A,@A+DPTR MOV STH0,A MOV TH0,A INC TEMP MOV A,TEMP MOVC A,@A+DPTR MOV STL0,A MOV TL0,A SETB TR0 DK1A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK1A CLR TR0 NOKEY1: MOV P3,#0FFH CLR P3.5 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY2 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK5 MOV KEYBUF,#4 LJMP DK2 NK5: CJNE A,#0DH,NK6 MOV KEYBUF,#5 LJMP DK2 NK6: CJNE A,#0BH,NK7 MOV KEYBUF,#6 LJMP DK2 NK7: CJNE A,#07H,NK8 MOV KEYBUF,#7 LJMP DK2 NK8: NOP DK2: MOV A,KEYBUF106MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,KEYBUF MOV B,#2 MUL AB MOV TEMP,A MOV DPTR,#TABLE1 MOVC A,@A+DPTR MOV STH0,A MOV TH0,A INC TEMP MOV A,TEMP MOVC A,@A+DPTR MOV STL0,A MOV TL0,A SETB TR0 DK2A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK2A CLR TR0 NOKEY2: MOV P3,#0FFH CLR P3.6 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY3 MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK9 MOV KEYBUF,#8 LJMP DK3 NK9: CJNE A,#0DH,NK10 MOV KEYBUF,#9 LJMP DK3107NK10: CJNE A,#0BH,NK11 MOV KEYBUF,#10 LJMP DK3 NK11: CJNE A,#07H,NK12 MOV KEYBUF,#11 LJMP DK3 NK12: NOP DK3: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,KEYBUF MOV B,#2 MUL AB MOV TEMP,A MOV DPTR,#TABLE1 MOVC A,@A+DPTR MOV STH0,A MOV TH0,A INC TEMP MOV A,TEMP MOVC A,@A+DPTR MOV STL0,A MOV TL0,A SETB TR0 DK3A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK3A CLR TR0 NOKEY3: MOV P3,#0FFH CLR P3.7 MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4 LCALL DELY10MS MOV A,P3 ANL A,#0FH XRL A,#0FH JZ NOKEY4108MOV A,P3 ANL A,#0FH CJNE A,#0EH,NK13 MOV KEYBUF,#12 LJMP DK4 NK13: CJNE A,#0DH,NK14 MOV KEYBUF,#13 LJMP DK4 NK14: CJNE A,#0BH,NK15 MOV KEYBUF,#14 LJMP DK4 NK15: CJNE A,#07H,NK16 MOV KEYBUF,#15 LJMP DK4 NK16: NOP DK4: MOV A,KEYBUF MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A MOV A,KEYBUF MOV B,#2 MUL AB MOV TEMP,A MOV DPTR,#TABLE1 MOVC A,@A+DPTR MOV STH0,A MOV TH0,A INC TEMP MOV A,TEMP MOVC A,@A+DPTR MOV STL0,A MOV TL0,A SETB TR0 DK4A: MOV A,P3 ANL A,#0FH XRL A,#0FH JNZ DK4A CLR TR0 NOKEY4: LJMP WAIT DELY10MS: MOV R6,#10109D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 RET INT_T0: MOV TH0,STH0 MOV TL0,STL0 CPL P1.0 RETI TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H TABLE1: DW , DW , DW , DW , END 7. C 语言源程序 #include &AT89X51.H& unsigned char code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; unsigned char i,j; unsigned char STH0; unsigned char STL0; unsigned int code tab[]={,, ,, ,, ,}; void main(void) { TMOD=0x01; ET0=1; EA=1; while(1) { P3=0 P3_4=0; temp=P3;110temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=0; case 0x0d: key=1; case 0x0b: key=2; case 0x07: key=3; } temp=P3; P1_0=~P1_0; P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } TR0=0; } } P3=0 P3_5=0;111temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=4; case 0x0d: key=5; case 0x0b: key=6; case 0x07: key=7; } temp=P3; P1_0=~P1_0; P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } TR0=0; } } P3=0112P3_6=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=8; case 0x0d: key=9; case 0x0b: key=10; case 0x07: key=11; } temp=P3; P1_0=~P1_0; P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } TR0=0; } }113P3=0 P3_7=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=12; case 0x0d: key=13; case 0x0b: key=14; case 0x07: key=15; } temp=P3; P1_0=~P1_0; P0=table[key]; STH0=tab[key]/256; STL0=tab[key]%256; TR0=1; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } TR0=0; } }114} } void t0(void) interrupt 1 using 0 { TH0=STH0; TL0=STL0; P1_0=~P1_0; } 23. 模拟计算器数字输入及显示 1. 实验任务 (1. 开机时,显示“0” (2. 第一次按下时,显示“D1”;第二次按下时,显示“D1D2”;第三按下时, 显示“D1D2D3”,8 个全显示完毕,再按下按键下时,给出“嘀”提示音。 2. 电路原理图115图4.23.1 3. 系统板上硬件连线 (1. 把“单片机系统”区域中的P1.0 端口用导线连接到“音频放大模块”区 域中的SPK IN 端口上; (2. 把“单片机系统“区域中的P3.0-P3.7 端口用8 芯排线连接到“4X4 行 列式键盘”区域中的C1-C4 R1-R4 端口上; (3. 把“单片机系统”区域中的P0.0-P0.7 端口用8 芯排线连接到“动态数 码显示”区域中的A-H 端口上; (4. 把“单片机系统:区域中的P2.0-P2.7 端口用8 芯排线连接到“动态数 码显示”区域中的S1-S8 端口上; 4. 相关程序设计内容 (1. 行列式键盘输入及按键功能设定; (2. 动态数码显示; (3. 数码显示方式处理; 5. 汇编源程序 (略) 6. C 语言源程序 #include &AT89X51.H& unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; unsigned char code dispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsigned char dispbuf[8]={0,16,16,16,16,16,16,16}; unsign unsigned char i,j;
void change(unsigned char *p,unsigned char count) { while(count&0) {116*(p+count)=*(p+count-1); count--; } } void main(void) { TMOD=0x01; TH0=() / 256; TL0=() % 256; TR0=1; ET0=1; EA=1; while(1) { P3=0 P3_4=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=7; case 0x0d: key=8; case 0x0b: key=9; case 0x07: key=10;117} if ((key&=0) && (key&10)) { keypos++; if(keypos&8) { change(dispbuf,keypos); dispbuf[0]= } else { keypos=8; alarmflag=1; } } temp=P3; P1_0=~P1_0; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } alarmflag=0; } } P3=0 P3_5=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e:118key=4; case 0x0d: key=5; case 0x0b: key=6; case 0x07: key=11; } if ((key&=0) && (key&10)) { keypos++; if(keypos&8) { change(dispbuf,keypos); dispbuf[0]= } else { keypos=8; alarmflag=1; } } temp=P3; P1_0=~P1_0; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } alarmflag=0; } } P3=0 P3_6=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) {119for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=1; case 0x0d: key=2; case 0x0b: key=3; case 0x07: key=12; } if ((key&=0) && (key&10)) { keypos++; if(keypos&8) { change(dispbuf,keypos); dispbuf[0]= } else { keypos=8; alarmflag=1; } } temp=P3; P1_0=~P1_0; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f;120} alarmflag=0; } } P3=0 P3_7=0; temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { for(i=50;i&0;i--) for(j=200;j&0;j--); temp=P3; temp=temp & 0x0f; if (temp!=0x0f) { temp=P3; temp=temp & 0x0f; switch(temp) { case 0x0e: key=0;
case 0x0d: key=13; case 0x0b: key=14; case 0x07: key=15; } if ((key&=0) && (key&10)) { keypos++; if(keypos&8) { change(dispbuf,keypos); dispbuf[0]= } else {121keypos=8; alarmflag=1; } } temp=P3; P1_0=~P1_0; temp=temp & 0x0f; while(temp!=0x0f) { temp=P3; temp=temp & 0x0f; } alarmflag=0; } } } } void t0(void) interrupt 1 using 0 { TH0=() / 256; TL0=() % 256; P0=dispcode[dispbuf[dispbitcount]]; P2=dispbitcode[dispbitcount]; dispbitcount++; if (dispbitcount==8) { dispbitcount=0; } if (alarmflag==1) { P1_1=~P1_1; } } 24. 8X8 LED 点阵显示技术 1. 实验任务 在8X8 LED 点阵上显示柱形,让其先从左到右平滑移动三次,其次从右到左 平滑移动三次,再次从上到下平滑移动三次,最后从下到上平滑移动三次, 如此循环下去。 2. 电路原理图122图4.24.1 3. 硬件电路连线 (1). 把“单片机系统”区域中的P1 端口用8 芯排芯连接到“点阵模块” 区域中的“DR1-DR8”端口上; (2). 把“单片机系统”区域中的P3 端口用8 芯排芯连接到“点阵模块” 区域中的“DC1-DC8”端口上; 4. 程序设计内容 (1). 8X8 点阵LED 工作原理说明1238X8 点阵LED 结构如下图所示 图4.24.2 从图4.24.2 中可以看出,8X8 点阵共需要64 个发光二极管组成,且每个发光二 极管是放置在行线和列线的交叉点上,当对应的某一列置1 电平,某一行置0 电平,则相应的二极管就亮;因此要实现一根柱形的亮法,如图49 所示,对应 的一列为一根竖柱,或者对应的一行为一根横柱,因此实现柱的亮的方法如下所 述: 一根竖柱:对应的列置1,而行则采用扫描的方法来实现。 一根横柱:对应的行置0,而列则采用扫描的方法来实现。 5.汇编源程序 ORG 00H START: NOP MOV R3,#3 LOP2: MOV R4,#8124MOV R2,#0 LOP1: MOV P1,#0FFH MOV DPTR,#TABA MOV A,R2 MOVC A,@A+DPTR MOV P3,A INC R2 LCALL DELAY DJNZ R4,LOP1 DJNZ R3,LOP2 MOV R3,#3 LOP4: MOV R4,#8 MOV R2,#7 LOP3: MOV P1,#0FFH MOV DPTR,#TABA MOV A,R2 MOVC A,@A+DPTR MOV P3,A DEC R2 LCALL DELAY DJNZ R4,LOP3 DJNZ R3,LOP4 MOV R3,#3 LOP6: MOV R4,#8 MOV R2,#0 LOP5: MOV P3,#00H MOV DPTR,#TABB MOV A,R2 MOVC A,@A+DPTR MOV P1,A INC R2 LCALL DELAY DJNZ R4,LOP5 DJNZ R3,LOP6 MOV R3,#3 LOP8: MOV R4,#8 MOV R2,#7 LOP7: MOV P3,#00H MOV DPTR,#TABB MOV A,R2 MOVC A,@A+DPTR125MOV P1,A DEC R2 LCALL DELAY DJNZ R4,LOP7 DJNZ R3,LOP8 LJMP START DELAY: MOV R5,#10 D2: MOV R6,#20 D1: MOV R7,#248 DJNZ R7,$ DJNZ R6,D1 DJNZ R5,D2 RET TABA: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH TABB: DB 01H,02H,04H,08H,10H,20H,40H,80H END 6. C 语言源程序 #include &AT89X52.H& unsigned char code taba[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsigned char code tabb[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; void delay(void) { unsigned char i,j; for(i=10;i&0;i--) for(j=248;j&0;j--); } void delay1(void) { unsigned char i,j,k; for(k=10;k&0;k--) for(i=20;i&0;i--) for(j=248;j&0;j--); }126void main(void) { unsigned char i,j; while(1) { for(j=0;j&3;j++) //from left to right 3 time { for(i=0;i&8;i++) { P3=taba[i]; P1=0 delay1(); } } for(j=0;j&3;j++) //from right to left 3 time { for(i=0;i&8;i++) { P3=taba[7-i]; P1=0 delay1(); } } for(j=0;j&3;j++) //from top to bottom 3 time { for(i=0;i&8;i++) { P3=0x00; P1=tabb[7-i]; delay1(); } } for(j=0;j&3;j++) //from bottom to top 3 time { for(i=0;i&8;i++) { P3=0x00; P1=tabb[i]; delay1(); }127} } } 25. 点阵式LED“0-9”数字显示技术 1. 实验任务 利用8X8 点阵显示数字0 到9 的数字。 2. 电路原理图 图4.25.1 3. 硬件系统连线 (1). 把“单片机系统”区域中的P1 端口用8 芯排芯连接到“点阵模块” 区域中的“DR1-DR8”端口上;128(2). 把“单片机系统”区域中的P3 端口用8 芯排芯连接到“点阵模块” 区域中的“DC1-DC8”端口上; 4. 程序设计内容 (1). 数字0-9 点阵显示代码的形成 如下图所示,假设显示数字“0” 1 2 3 4 5 6 7 8 00 00 3E 41 41 41 3E 00 因此,形成的列代码为00H,00H,3EH,41H,41H,3EH,00H,00H;只要把这 些代码分别送到相应的列线上面,即可实现“0”的数字显示。 送显示代码过程如下所示 送第一列线代码到P3 端口,同时置第一行线为“0”,其它行线为“1”,延时 2ms 左右,送第二列线代码到P3 端口,同时置第二行线为“0”,其它行线为 “1”,延时2ms 左右,如此下去,直到送完最后一列代码,又从头开始送。 数字“1”代码建立如下图所示 1 2 3 4 5 6 7 8 其显示代码为00H,00H,00H,00H,21H,7FH,01H,00H● ● ● ● ● ● ● ● ● ● ● ● ● ●129● ● ● ● ● ● ● ● ● ●● ●数字“2”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,27H,45H,45H,45H,39H,00H 数字“3”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,22H,49H,49H,49H,36H,00H 数字“4”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,0CH,14H,24H,7FH,04H,00H● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●130● ● ● ● ● ● ● ● ● ● ● ●数字“5”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,72H,51H,51H,51H,4EH,00H 数字“6”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,3EH,49H,49H,49H,26H,00H 数字“7”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,40H,40H,40H,4FH,70H,00H● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●131● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● 数字“8”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,36H,49H,49H,49H,36H,00H 数字“9”代码建立如下图所示 1 2 3 4 5 6 7 8 00H,00H,32H,49H,49H,49H,3EH,00H 5. 汇编源程序 TIM EQU 30H CNTA EQU 31H CNTB EQU 32H ORG 00H LJMP START ORG 0BH LJMP T0X ORG 30H START: MOV TIM,#00H MOV CNTA,#00H MOV CNTB,#00H MOV TMOD,#01H● ● ● ● ● ● ● ● ● ● ● ● ● ●132● ● ● ● ● ● ● ● ● ● ●●●● ●● ●● ● ●MOV TH0,#()/256 MOV TL0,#() MOD 256 SETB TR0 SETB ET0 SETB EA SJMP $ T0X: MOV TH0,#()/256 MOV TL0,#() MOD 256 MOV DPTR,#TAB MOV A,CNTA MOVC A,@A+DPTR MOV P3,A MOV DPTR,#DIGIT MOV A,CNTB MOV B,#8 MUL AB ADD A,CNTA MOVC A,@A+DPTR MOV P1,A INC CNTA MOV A,CNTA CJNE A,#8,NEXT MOV CNTA,#00H NEXT: INC TIM MOV A,TIM CJNE A,#250,NEX MOV TIM,#00H INC CNTB MOV A,CNTB CJNE A,#10,NEX MOV CNTB,#00H NEX: RETI TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH DIGIT: DB 00H,00H,3EH,41H,41H,41H,3EH,00H DB 00H,00H,00H,00H,21H,7FH,01H,00H DB 00H,00H,27H,45H,45H,45H,39H,00H DB 00H,00H,22H,49H,49H,49H,36H,00H DB 00H,00H,0CH,14H,24H,7FH,04H,00H DB 00H,00H,72H,51H,51H,51H,4EH,00H DB 00H,00H,3EH,49H,49H,49H,26H,00H DB 00H,00H,40H,40H,40H,4FH,70H,00H133DB 00H,00H,36H,49H,49H,49H,36H,00H DB 00H,00H,32H,49H,49H,49H,3EH,00H END 6. C 语言源程序 #include &AT89X52.H& unsigned char code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; u

我要回帖

更多关于 android 模拟定位实现 的文章

 

随机推荐