《微机原理与接口技术》
课程设计实验报告
题目:交通灯控制功能设计
指导老师:
专业:信息科学与工程学院
班级:自动化0807班
日期:20##-1-5
目录
一、设计思想和实施方案论述,硬件原理图及分析
1.1、课程设计名称
1.2、课程设计要求
1.3、课程设计目的
二、设计思想和实施方案论述,硬件原理图及分析
2.1、设计思想和实施方案
2.2、硬件原理图
三、典型模块以及典型编程技巧分析
3.1、8086典型模块分析
3.2、编程技巧分析
四、设计中遇到的问题及解决方法
五、程序清单和程序注释,相关流程图
5.1程序清单和注释
5.2、实验室及流程图
六、收获与体会
七、参考文献
一、 设计课程名称及要求
1.1、课程设计名称:交通灯控制功能设计。
1.2、课程设计要求:
(1)、分别用C语言和汇编语言编程完成硬件接口功能设计;
(2)、硬件电路基于80x86微机接口;
(3)、程序功能要求:小键盘给定、数码管(屏幕)显示;
(4)、同时具备急救车应急响应功能和时间倒计时显示功能。
1.3、课程设计目的:
《微机应用系统设计与综合实验(实践)》课程设计是自动化专业本科生必修的一门技术基础课。通过本课程设计,让学生对微机系统有一个较全面的理解,对典型数字接口电路的应用技术有一个较深入的掌握,并对应用系统进行硬件原理和软件编程进行分析、设计和调试,达到基本掌握简单微型计算机应用系统软硬件的设计方法,提高项目开发能力的目的。要求同学独立完成课题,写出课程设计说明书,画出电路原理图,说明工作原理,画出电路印制板图, 编写设计程序及程序流程图。
二、设计思想和实施方案论述,硬件原理图及分析
2.1、设计思想和实施方案:
本设计使用了两种方案,一种是采用8086和8255A可编程并行接口实现了交通灯的设计,分别对主干道和支干道显示红灯和绿灯并且计时,采用8254定时器/计数器产生1HZ的脉冲,来控制8259产生中断,从而实现整个电路的设计。交通灯采用红绿两种发光二极管,主干道亮45s,支干道亮30s,计数的最后5s中绿灯闪烁,用数码管倒计时显示时间,在发生紧急情况时,可以认为用开关控制主干道和支干道红灯均亮,禁止任何车通行。另一种方案是采用单片机来实现的,达到的效果和上述方案相同。单片机采用定时器T0和T1来触发中断,根据中断优先级的不同,从而可以处理不同的情况,交通灯也是采用红绿两种发光二极管,主干道亮45s,支干道亮30s,计数的最后5s中绿灯闪烁,用数码管倒计时显示时间,在发生紧急情况时,可以认为用开关控制主干道和支干道红灯均亮,禁止任何车通行,在故障清除后,断开开关可以使红绿灯和数码管回到原来的状态继续正常工作。
2.2、硬件原理图:
(a)图是基于8086的设计,(b)图是基于单片机的设计。在(a)图中,可编程并行接口芯片8255A用作输出口,控制红绿灯的亮暗和数码管的计时,定时器/计数器8254采用级联的方式产生1HZ的脉冲,并将此方波接到中断器8259的IR1上,即每秒钟让中断控制器产生依次中断,从而可以执行中断子程序。在(b)图中,P0口用于接数码管,P1口用于控制红绿灯的亮暗,P2口用于选通数码管,P32为定时器T0的控制端,当P32口为高电平时,定时器T0才会工作,并且T0的中断优先级高于T1,所以可以用于控制紧急情况。P37口接扬声器,在计数器T0工作时扬声器就会响。
三、典型模块以及典型编程技巧分析
3.1、8086典型模块分析:基于8086的设计主要由3个模块构成,其中8255是作为与外部显示电路的接口单元,8254和8259协同工作产生中断作为控制电路。可编程并行接口芯片8255A通过方式控制字设置成方式0工作模式,A、B、C口均为输出,可编程计数器/定时器8254通过控制字寄存器设置OU0和OU1均为方式3工作模式,通过级联产生1HZ的方波,中断控制器通过初始化命令字设置成边缘触发,8254的OU1口接到8259的IR1端,每秒钟就可以产生一次中断,每次执行中断子程序时使计数减1,从而可以实现倒计时功能,当计数到0时,重新给计数初值赋给,改变灯的状态。外部开关接8259的IR0端,它的中断优先级别高,设置成边缘触发,当按下开关,产生一个高电平的脉冲,就可以停止原来的状态来执行更高级别的中断子程序,这就可以处理紧急情况,让主干道和支干道都变成红灯。
单片机典型模块分析:基于单片机的设计主要是以51单片机为核心,通过变成开放T0和T1的中断,但T0要在INT0为高电平时计数器T0才会工作。计数器T1每50ms产生一次中断,每产生20次中断就令数码管的计数减1,当计数减到0时,重新设置数码管的计数初值,这样就可以依次循环工作了。当P32接高电平时,计数器T0开始工作,此时红灯都亮,扬声器发音,中断结束后还原原来的状态。
3.2、编程技巧分析:基于8086的设计编程语言是汇编语言,这里的几个编程模块就是方波产生模块,数码管显示模块和中断子程序模块。方波是通过8254级联产生的,设置8254的计时器0和计数器1工作在方式3,设置适当计数初值n即可,这个模块的程序如下所示:
LOOP2: MOV DX,MY8254_MODE
MOV AL,0
OUT DX,AL ;计数器0,读写16位低高字节,工作方式3,BCD计数
MOV AL,00H
MOV DX,MY8254_0
OUT DX,AL
MOV AL,50
OUT DX,AL
MOV DX,MY8254_MODE
MOV AL,77H
OUT DX,AL ;计数器1,读写16位低高字节,工作方式3,BCD计数
MOV AL,8
MOV DX,MY8254_1
OUT DX,AL
MOV AL,2
OUT DX,AL ;1.041667MHZ/2000/1000=1HZ,即计数器输出1HZ的方波
数码管的显示是通过调用显示函数实现的,通过设置8255的工作模式,选择数码管的高位工作,然后将计数的高位送到数码管,再选择数码管的低位工作,然后将计数的低位送到数码管,在1s钟内多次扫描就可以消除闪烁,从而达到理想的计数效果,它的程序如下所示:
disp PROC NEAR
C1:MOV DX,MY8255_C
MOV AL,0FEH;选通高位数码管
OUT DX,AL
SUB AH,AH
MOV AL,COUNT
MOV BL,0AH
DIV BL;商寄存在AL中,余数在AH中
MOV BX,OFFSET TAB
XLAT;通过查表找到对应的7段显示字符
MOV DX,MY8255_B
OUT DX,AL
CALL DELAY1ms
MOV AL,0
OUT DX,AL
MOV AL,0FDH;选通低位数码管
MOV DX,MY8255_C
OUT DX,AL
MOV AL,AH
MOV BX,OFFSET TAB
XLAT;通过查表找到对应的7段显示字符
MOV DX,MY8255_B
OUT DX,AL
CALL DELAY1ms
MOV AL,0
OUT DX,AL
MOV AH,1
INT 16H;有键按下则跳出
JNZ QUIT
disp ENDP
中断子程序模块是通过扩充中断源实现的,主要是通过设置8259的工作模式,开放TR1和TR0的中断,按上开关K后,TR0就发生中断,在TR0中断没有触发的情况下,从OU1口输出一个上升沿脉冲,TR1就中断一次,程序如下所示:
QUERY: MOV DX,MY8259_OCW3 ;向8259的OCW3发送查询命令
MOV AL,0CH
OUT DX,AL
IN AL,DX ;读出查询字
TEST AL,80H ;判断中断是否已响应
JZ QUERY ;没有响应则继续查询
AND AL,03H
CMP AL,00H
JE IR0ISR ;若为IR0请求,跳到IR0处理程序
JNE IR1ISR ;若为IR1请求,跳到IR1处理程序
JMP EOI
基于单片机的编程语言是C语言,它主要有数码管显示程序和中断服务子程序。数码管的显示和上面汇编语言的原理一样,它的程序如下:
void display(unsigned char t)//显示数码管函数
{
P2=0xf5;选通两个高位数码管
P0=tab[t/10];取t的十位送到P0口显示
delay();
P2=0xF0;开通所有的数码管,避免闪烁
P2=0xfa;选通低位两个数码管
P0=tab[t%10];取t的个位送到P0口显示
delay();
P2=0xF0;
}
中断服务子程序有计数器T0和计数器T1的子程序。T1的优先级低,它主要用于控制正常工作状态的红绿灯和数码管计数,而T0的优先级高,可以处理紧急情况,并且在处理紧急情况以后能返回原正常运行状态,这在汇编里面用的是栈保护,而在C语言中可以设置一个变量也存储原来的数据,可以达到同样保护数据的效果,这一点的实现代码如下:
void Time0(void) interrupt 1 using 0
{
t=0;
count1=count;//寄存中断前count的值,以便中断结束后恢复
while(t!=125)
{
t++;
sound=~sound;
P10=0;//紧急情况绿灯全熄
P12=0;
P11=1;//紧急情况红灯全亮
P13=1;
P2=0xF0;//点亮两个数码管
count=88;
display(count);
TH0=(65535-921)/256;
TL0=(65535-921)%256;
}
count=count1;//恢复原来count的值
if(a%2==0)
{P10=1;
P11=0;
P12=0;
P13=1;//返回主干道通行
}
else
{P10=0;
P11=1;
P12=1;
P13=0;//返回主干道通行
}
}
四、设计中遇到的问题及解决方法
1.数码管的计数每秒钟减1,当时不熟练8254的应用,就想用软件延时来实现这个功能,最后查资料的时候知道了计时器的级联应用,很容易的就解决了这个问题。
2.对于数码管的显示,最开始感觉很模糊,查阅资料的时候找到了XLAT表转换指令的应用,首先定义十进制的七段显示码,将表格首地址送入BX,数字的七段码在表格中的偏移量送入AL,然后执行XLAT就可以实现这个功能了。
3.对于要求中的紧急响应功能,开始时只想利用8254来实现,结果失败了,所以我就想到了用两级中断,产生高级中断时就开启紧急响应功能,触发蜂鸣器,点亮红灯。
4.在执行中断程序的过程中,寄存器中的变量好多都改变了,开始时束手无策,最后查资料时想到了栈的运用,利用入栈和出栈来保护寄存器中的初值。
5.在用C语言编程时,用PROTUES软件进行仿真时,数码管显示错误,一会显示一会停止,闪烁感太明显了。想想后,我就把显示函数从中断子程序中改放到主函数中,放在while(1)无限循环语句中,最后很好的解决了这个问题。查阅资料后才明白,执行中断子程序是很快的事,执行完了后就会返回到主函数中继续执行,所以显示函数放在中断子程序中只有在产生中断的时候才会工作,所以数码管很多时候就处于熄灭的状态,而显示函数放在主函数中就放好解决了这个问题。
6.要做到可以人为设置通行时间,在单片机中,我不熟练键盘扫描,所以就想到了另外一个办法,给P1的高四位赋不同的初值,这样可以得到16种组合,故可以设置16中初值,为了简化程序,我只设置了4种初值,不过同样可以达到设置初值的效果。
7.用单片机产生两级中断的时候,我不知道该选定时器中断还是外部中断,查资料后知道定时器0和定时器1的中断优先级不一样,定时器T0的优先级高,所以可以让定时器T1控制正常工作状态的灯显示和数码管计数,而定时器T0则控制突发情况。
五、程序清单和程序注释,相关流程图
5.1程序清单和注释:
基于8086汇编语言的程序清单及注释如下所示:
MY8255_A EQU IOY0+00H*4 ; 8255A口的地址
MY8255_B EQU IOY0+01H*4 ; 8255B口的地址
MY8255_C EQU IOY0+02H*4 ; 8255C口的地址
MY8255_MODE EQU IOY0+03H*4 ; 8255控制寄存器的地址
MY8254_0 EQU IOY1+00H*4 ; 8254计数器0端口的地址
MY8254_1 EQU IOY1+01H*4 ; 8254计数器0端口的地址
MY8254_MODE EQU IOY1+02H*4 ; 8254计数器0端口的地址
;***************根据CHECK配置信息修改下列符号值*******************
INTR_IVADD EQU 01CCH ;INTR对应的中断矢量地址
INTR_OCW1 EQU 0A1H ;INTR对应PC机内部8259的OCW1地址
INTR_OCW2 EQU 0A0H ;INTR对应PC机内部8259的OCW2地址
INTR_IM EQU 0F7H ;INTR对应的中断屏蔽字
PCI_INTCSR EQU 9438H ;PCI卡中断控制寄存器地址
IOY0 EQU 0C400H ;片选IOY0对应的端口始地址
IOY1 EQU 0C440H ;片选IOY0对应的端口始地址
IOY2 EQU 0C480H ;片选IOY0对应的端口始地址
;*****************************************************************
MY8259_ICW1 EQU IOY2+00H ;实验系统中8259的ICW1端口地址
MY8259_ICW2 EQU IOY2+04H ;实验系统中8259的ICW2端口地址
MY8259_ICW3 EQU IOY2+04H ;实验系统中8259的ICW3端口地址
MY8259_ICW4 EQU IOY2+04H ;实验系统中8259的ICW4端口地址
MY8259_OCW1 EQU IOY2+04H ;实验系统中8259的OCW1端口地址
MY8259_OCW2 EQU IOY2+00H ;实验系统中8259的OCW2端口地址
MY8259_OCW3 EQU IOY2+00H ;实验系统中8259的OCW3端口地址
RED EQU 0FAH ;紧急时刻,主支干道全部亮红灯
ZHU EQU 0F5H ;主干道灯的状态
ZHI EQU 0F9H ;支干道灯的状态
FLICKER EQU 0F0H ;控制灯闪烁
CLOSE EQU 00H ;关闭所有的灯
TIME1 EQU 20 ;主干道通行时间
TIME2 EQU 10 ;支干道通行时间
DATA SEGMENT
CS_BAK DW ?
IP_BAK DW ?
IM_BAK DW ?
TAB DB 40H,79H,24H,30H,19H,12H,02H,78H,00H,18H ;十进制数的七段显示码
COUNT DW ? ;存储计数的变量
FLAG DW ? ;flag为偶数时表明主干道通行
DATA ENDS
STACK1 SEGMENT STACK
DW 256 DUP(?)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
START: MOV AX,DATA
MOV DS,AX
CLI
MOV DX,MY8255_MODE
MOV AL,80H
OUT DX,AL ;初始化8255的工作模式A、B、C工作在方式0,均为输出
LOOP1: MOV DX,MY8255_A
MOV CX,3
A1: MOV AL,RED
OUT DX,AL
CALL DELAY1 ;延时0.5s
MOV AL,CLOSE
OUT DX,AL
CALL DELAY1
LOOP A1 ;初始状态主支干道红灯均闪烁,3s后进入正常工作状态
LOOP2: MOV DX,MY8254_MODE
MOV AL,0
OUT DX,AL ;计数器0,读写16位低高字节,工作方式3,BCD计数
MOV AL,00H
MOV DX,MY8254_0
OUT DX,AL
MOV AL,50
OUT DX,AL
MOV DX,MY8254_MODE
MOV AL,77H
OUT DX,AL ;计数器1,读写16位低高字节,工作方式3,BCD计数
MOV AL,8
MOV DX,MY8254_1
OUT DX,AL
MOV AL,2
OUT DX,AL ;1.041667MHZ/2000/1000=1HZ,即计数器输出1HZ的方波
MOV COUNT,TIME1
MOV FLAG,0 ;初始化主干道通行
MOV CL,ZHU
MOV AL,CL
MOV DX,MY8255_A
OUT DX,AL
MOV DX,PCI_INTCSR
SUB DX,19H
IN AL,DX
MOV DX,PCI_INTCSR ;初始化PCI卡中断控制寄存器
MOV AX,1F00H ;向PCI_INTCSR中写入003F1F00H
OUT DX,AX
ADD DX,2
MOV AX,003FH
OUT DX,AX
MOV AX,0000H ;替换INTR的中断矢量
MOV ES,AX
MOV DI,INTR_IVADD
MOV AX,ES:[DI]
MOV IP_BAK,AX ;保存INTR原中断处理程序入口偏移地址
MOV AX,OFFSET MYISR
MOV ES:[DI],AX ;设置当前中断处理程序入口偏移地址
ADD DI,2
MOV AX,ES:[DI]
MOV CS_BAK,AX ;保存INTR原中断处理程序入口段地址
MOV AX,SEG MYISR
MOV ES:[DI],AX ;设置当前中断处理程序入口段地址
MOV DX,INTR_OCW1 ;设置中断屏蔽寄存器,打开INTR的屏蔽位
IN AL,DX
XOR AX,AX
MOV IM_BAK, AX ;保存INTR原中断屏蔽字
AND AL,INTR_IM
OUT DX,AL
MOV DX,MY8259_ICW1 ;初始化实验系统中8259的ICW1
MOV AL,13H ;边沿触发、单片8259、需要ICW4
OUT DX,AL
MOV DX,MY8259_ICW2 ;初始化实验系统中8259的ICW2
MOV AL,08H
OUT DX,AL
MOV DX,MY8259_ICW4 ;初始化实验系统中8259的ICW4
MOV AL,01H ;非自动结束EOI
OUT DX,AL
MOV DX,MY8259_OCW1 ;初始化实验系统中8259的OCW1
MOV AL,0FCH ;打开IR0和IR1的屏蔽位
OUT DX,AL
STI
WAIT1: CALL DISP ;数码管显示
MOV AH,1 ;判断是否有按键按下
INT 16H
JZ WAIT1 ;无按键则跳回继续等待,有则退出
QUIT: CLI
MOV DX,PCI_INTCSR ;恢复PCI卡中断控制寄存器
MOV AX,0000H
OUT DX,AX
MOV AX,0000H ;恢复INTR原中断矢量
MOV ES,AX
MOV DI,INTR_IVADD
MOV AX,IP_BAK ;恢复INTR原中断处理程序入口偏移地址
MOV ES:[DI],AX
ADD DI,2
MOV AX,CS_BAK ;恢复INTR原中断处理程序入口段地址
MOV ES:[DI],AX
MOV DX,INTR_OCW1
XOR AX,AX
;恢复INTR原中断屏蔽寄存器的屏蔽字
MOV AX,IM_BAK
OUT DX,AL
STI
MOV AX,4C00H ;返回到DOS
INT 21H
MYISR PROC NEAR ;中断处理程序MYISR
QUERY: MOV DX,MY8259_OCW3 ;向8259的OCW3发送查询命令
MOV AL,0CH
OUT DX,AL
IN AL,DX ;读出查询字
TEST AL,80H ;判断中断是否已响应
JZ QUERY ;没有响应则继续查询
AND AL,03H
CMP AL,00H
JE IRO0 ;若为IR0请求,跳到IR0处理程序
JNE IRO1 ;若为IR1请求,跳到IR1处理程序
JMP EOI
IRO0: MOV AL,FLAG ;IRO为高级中断,处理紧急情况
CBW
MOV BX,AX ;把count变成双字节存入AX,这样就可以存入栈中
MOV AL,COUNT ;把count变成双字节存入AX,这样就可以存入栈中
CBW
PUSH AX
PUSH BX
MOV CX,0FFFFH ;中断程序执行时间为65536*256/f=3s
LOOP0: MOV BL,0FFH
LOOP1: MOV DX,MY8255_A
MOV AX,0FAH ;主干道支干道红灯均亮
MOV DX,MY8255_C
MOV AL,80H ;PC7为高电平,接扬声器
OUT DX,AL
DEC BL
CMP BL,0
JNE LOOP1
LOOP LOOP0
POP BX
POP AX
MOV COUNT,AL ;还原中断前的变量值
MOV FLAG,BL
MOV AH,0
MOV AL,FLAG
MOV BL,2
DIV BL ;AH=1,FLAG为奇数 ,支干道通行
CMP AH,1
JE P3
MOV DX,MY8255_A
MOV AL,ZHU ;主干道通行灯的状态
OUT DX,AL
P3: MOV DX,MY8255_A
MOV AL,ZHI ;支干道通行灯的状态
OUT DX,AL
IRET
IRO1: MOV AL,COUNT
SUB AL,01H
DAS
MOV COUNT,AL ;计数初值自减1
CMP AL,0
JE L2
MOV AL,FLAG
MOV BL,2
DIV BL ;AH=1,FLAG为奇数 ,支干道通行
CMP AH,1
JE P1
MOV DX,MY8255_A
MOV AL,ZHU ;主干道通行灯的状态
OUT DX,AL
P1: MOV DX,MY8255_A
MOV AL,ZHI ;支干道通行灯的状态
OUT DX,AL
L2: MOV AL,FLAG
ADD AL,01H ;状态显示数加1
DAA
MOV AH,0
MOV BL,2
DIV BL ;AH=1,FLAG为奇数 ,支干道通行
CMP AH,1
JE P2
MOV COUNT,TIME1 ;支干道工作完后设置主干道的通行时间TIME1
P2: MOV COUNT,TIME2 ;主干道工作完后设置支干道的通行时间TIME2
IRET
EOI: MOV DX,MY8259_OCW2 ;向实验系统中8259发送中断结束命令
MOV AL,20H
OUT DX,AL
OVER: MOV DX,PCI_INTCSR
SUB DX,19H
IN AL,DX
MOV DX,PCI_INTCSR ;清PCI卡中断控制寄存器标志位
ADD DX,2
MOV AX,003FH
OUT DX,AX
MOV DX,INTR_OCW2 ;向PC机内部8259发送中断结束命令
MOV AL,20H
OUT DX,AL
MOV AL,20H
OUT 20H,AL
IRET
MYISR ENDP
DISP PROC
MOV DX,MY8255_C
MOV AL,0AH ;选通高位数码管
OUT DX,AL
MOV AL,COUNT
MOV BL,0AH
DIV BL ;十位存在AL中,个位存在AH中
MOV BX,OFFSET TAB
XLAT ;找到十位对应的七段显示码
MOV DX,MY8255_B
OUT DX,AL
CALL DELAY1MS
MOV DX,MY8255_C
MOV AL,05H
OUT DX,AL
MOV AL,AH
MOV BX,OFFSET TAB
XLAT ;找到个位对应的七段显示码
MOV DX,MY8255_B
OUT DX,AL
RET ;过程返回指令
DISP ENDP
DELAY1 PROC NEAR ;延时0.5s
PUSH AX
PUSH CX
MOV AX,05FFFH
D1: MOV CX,64FFH
D2: LOOP D2
DEC AX
JNZ D1
POP CX
POP AX
RET
DELAY1 ENDP
DELAY1MS PROC NEAR ;延时1ms
PUSH CX
MOV CX,50H
NEXT: NOP
NOP
LOOP NEXT
POP CX
RET
DELAY1MS ENDP
CODE ENDS
END START
基于单片机的C语言程序清单及注释如下所示:
#include <reg52.h>
unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char time;
unsigned char t;
unsigned char count;//储存通行时间
unsigned char main1;//主干道通行时间
unsigned char cross;//支干道通行时间
unsigned char count1;
unsigned char a;//测试主干道工作还是支干道工作
sbit P10=P1^0;//控制主干道绿灯
sbit P11=P1^1;//主干道红灯
sbit P12=P1^2;//控制支干道绿灯
sbit P13=P1^3;//支干道红灯
sbit P14=P1^4;//以下端口辅助拨码开关设置时间
sbit P15=P1^5;
sbit P16=P1^6;
sbit P17=P1^7;
sbit sound=P3^7;//发声音
void delay()//延时20ms
{ unsigned char i;
for(i=0;i<200;i++)
;
}
void display(unsigned char t)//显示数码管函数
{
P2=0xf5;
P0=tab[t/10];
delay();
P2=0xF0;
P2=0xfa;
P0=tab[t%10];
delay();
P2=0xF0;
}
void main()
{
EA=1; //开总中断
ET0=1; //开定时器0的中断
ET1=1; //开定时器1的中断
TMOD=0X19;//计数器1工作于方式1,计数器0工作于方式1,TR0为1且INT0为高电平启动工作
TH0=(65535-921)/256;
TL0=(65535-921)%256; //定时器0赋初值
TH1=(65535-46083)/256; //定时50ms
TL1=(65535-46083)/256;
TR0=1;
TR1=1;
P10=1;
P11=0;
P12=0;
P13=1;//初始化主干道通行
a=0;//初始化主干道工作
time=0;
count=30;//初始化主干道时间
while(1)
{
display(count);
if(P14==1&&P15==0&&P16==0&&P17==0)
{main1=20;cross=10;}
else if(P14==0&&P15==1&&P16==0&&P17==0)
{main1=30;cross=15;}
else if(P14==0&&P15==0&&P16==1&&P17==0)
{main1=40;cross=25;}
else if(P14==0&&P15==0&&P16==0&&P17==1)
{main1=50;cross=35;}
else
{main1=60;cross=45;}
/*通过拨码开关设置主支干道的通行时间,相当于键盘扫描的效果*/
}
}
void Time1(void) interrupt 3 using 0//定时器T1,较低级中断
{
time++;
if(time==20) //50*20=1000ms=1s,计数1s后count减1
{ count--;
if(count<5&&count>0) //最后5s设置绿灯闪烁
{ if(a%2==0)
P10=~P10;//主干道绿灯闪烁
else P12=~P12;//支干道绿灯闪烁
}
else if(count==0)
{ a++;
P10=~P10;//主干道工作完后灯取反
P11=~P11;
P12=~P12;
P13=~P13;
if(a%2==0)
count=main1; //主干道时间
else
count=cross; //支干道时间
}
time=0;
}
TH1=(65535-46083)/256; //重新给定时器1赋初值
TL1=(65535-46083)/256;
}
/*INT0为高电平时出发定时器0计数,高级中断 */
void Time0(void) interrupt 1 using 0
{
t=0;
count1=count;//寄存中断前count的值,以便中断结束后恢复
while(t!=125)
{
t++;
sound=~sound; //产生方波,触发蜂鸣器响
P10=0;//紧急情况绿灯全熄
P12=0;
P11=1;//紧急情况红灯全亮
P13=1;
P2=0xF0;//点亮两个数码管
count=88;
display(count);
TH0=(65535-921)/256;
TL0=(65535-921)%256;
}
count=count1;//恢复原来count的值
if(a%2==0)
{P10=1;
P11=0;
P12=0;
P13=1;//返回主干道通行
}
else
{P10=0;
P11=1;
P12=1;
P13=0;//返回主干道通行
}
}
5.2、实验室及流程图:
两种设计方案的思想完全一致,故它们的流程图基本相同,可以用下面的图来表示:
是
否
否
是
否 否
是
IR1的流程图:
否
是
否
是
否
是 否
IR0流程图:
否
是
是
是 否
按照流程图和相关的模块,就可以设计程序了。汇编语言和单片机C语言达到一样的效果,流程图代表了整个设计的核心思想,所以它们的流程图思想是一样的。主题思想就是定时器计数,计数满后就产生中断,中断子程序改变数码管的显示值,数码管显示0后就在下一次中断时改变灯的状态,另外重新给数码管一个新的计数初值,另外一个高级中断就处理异常事故,它的中断子程序要改变灯的状态,改变数码管的显示值,触发蜂鸣器响,中断执行完后就要恢复原来的状态,按照这样的工作方式不断的进行,就是一个完整的交通灯控制系统了。
六、收获与体会
这次课程设计,总体来说让我增加了很多知识,动手实践比上课有意思多了,但在设计的过程中我发现理论知识也同样重要,各种寻址方式以及8086的指令系统,还有各种寄存器的应用,掌握了这些基本知识,汇编就变得轻松多了。这次课程设计,我学会了8255和8254的应用,初步了解了8259中断的应用,把理论知识和实践相结合,从而提高了自己的同手能力和独立思考的能力。在听课的过程中,我对微机的工作原理不是很清楚,对计数器和外围接口芯片的用法也不熟悉,更不清楚中断的用法了,通过这次课程设计,我知道了状态控制字来工作这些芯片的工作模式,同时,我了解了中断的过程,产生中断时,系统会转去执行中断服务子程序,执行完子程序后又会返回到主函数中继续执行程序。
虽然我的收获很多,但在这次的课程设计中,我还有很多地方做的不好,我对中断子程序的调用还没有完全掌握,还不会使用键盘接口的编程,我也不会用C语言编程控制8086工作,所以我选择用单片机做这个设计以实现相同的功能。单片机与8086相比,它把中断器,输入输出设备,定时器/计数器都集成在一起,所以在设计小的系统上面显得容易很多。单片机的输入输出口很多,有P0,P1,P2,P3共32个端口,扩展系统也比较容易,它内部的定时器/计数器也简化了外部电路的设计。单片机的中断功能没有8086强大,但我设计的交通的控制系统只需要用到两个中断,并且是两个计数器中断,它们之间也有中断的优先级,所以正好用于控制不同的功能。我以前也学过一些单片机,但这次是我第一次完成靠自己思考完成的,确实感到很高兴。在这次设计中,我先设计一个最简单的交通灯系统,然后不断的扩展功能,先用软件仿真,然后在设计,这样的流程感觉很顺利。
在用单片机设计的过程中,我也有了很大的收获。对于定时器/计数器的应用,中断的应用以及中断优先级的运用,我慢慢尝试着运用,也就有点熟练了。多动手设计就会更快的掌握知识,实践就是最好的老师。
在以后的时间里,我一定会再接再厉,争取更大的进步!
七、参考文献
1、微型计算机原理与接口技术.周荷琴,吴秀清。中国科学技术大学出版社
2、单片机C语言应用100例.王东峰,王会良。电子工业出版社
3、32位微机原理与实验教程
/**********此交通灯实现的功能更多一些*********************/
/////**************************现代交通灯的设计***************************///////
#include<reg51.h>
/*位定义P1口,控制灯和数码管 */
sbit P10=P1^0;
sbit P11=P1^1;
sbit P12=P1^2;
sbit P13=P1^3;
sbit P14=P1^4;
sbit P15=P1^5;
sbit P16=P1^6;
sbit P17=P1^7;
sbit P20=P2^0;
sbit P21=P2^1;
sbit P22=P2^2;
sbit P23=P2^3;
sbit P37=P3^7;//控制扬声器发音
/**************************共阳数码管显示0~9的段码表*****************************/
unsigned char code number[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/*********************************************************************************/
unsigned char t1;//直道绿灯亮的时间
unsigned char t2;//直道黄灯亮的时间
unsigned char t3;//左转道绿灯亮的时间
unsigned char t4;//左转道黄灯亮的时间
unsigned char t5;//红灯亮的时间
unsigned char t10,t20,t30,t40,t50;
unsigned char count;//存储中断次数的变量
unsigned char flag;//判断通行情况
unsigned char f;//调节高频波形和低频波形的依次出现 ,便于产生救护车声音
unsigned int h;//高频波形
unsigned int l;//低频波形
unsigned char t;//调节高频波形和低频波形出现的时间
/**************************
延时函数:延时30ms
**************************/
void delay(void)
{
unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<100;j++)
;
}
/**************************
显示函数:显示数码管
**************************/
void display(unsigned char x)
{
P16=1;P17=0;
P0=number[x/10];//显示十位
delay();
P16=0;P17=1;
P0=number[x%10];//显示个位
delay();
P16=0;P17=0;
}
/**************************
主函数
**************************/
main()
{
EA=1;
ET1=1;//启动定时器T1的中断
EX0=1;//启动外部中断INTR0
TMOD=0x10;
TH1=(65535-46083)/256;
TL1=(65535-46083)%256;//50ms中断一次
t10=30;
t20=4;
t30=16;
t40=4;
t1=t10; //初始化通行时间
P1=0x1e;//初始化灯的状态
count=0;
flag=1;//初始化直道通行
f=0;
l=0;
h=0;
t=0;
TR1=1;//开定时器T1的中断
IT0=0;//INTR0为低电平触发外部中断INTR0
while(1)
{
if(P23==0&&P22==0&&P21==0&&P20==1)
{ t10=20;t30=11;}
if(P23==0&&P22==0&&P21==1&&P20==0)
{ t10=30;t30=16;}
if(P23==0&&P22==1&&P21==0&&P20==0)
{ t10=45;t30=26;}
if(P23==1&&P22==0&&P21==0&&P20==0)
{ t10=60;t30=31;}
switch(flag)
{ case 1:display(t1);P1=0x1e;break;
case 2:display(t2);P1=0x1d;break;
case 3:display(t3);P1=0x17;break;
case 4:display(t4);P1=0x0f;break;
case 5:display(t5);P1=0x1b;break;
default:break;
}
}
}
/*************************************************
定时器T1的中断子程序 :改变数码管和灯的状态
*************************************************/
void Time1(void)interrupt 3 using 0
{
count++;
if(count==20)//1s中执行下列程序一次
{ count=0;
if(flag==1)
{ t1--;
if(t1==0)
{ flag=2;
t1=t10;
t2=t20;
t3=t30;
t4=t40;
t5=t10+t20+t30+t40-2;
}
}
if(flag==2)
{ t2--;
if(t2==0)
{ flag=3;
t1=t10;
t2=t20;
t3=t30;
t4=t40;
t5=t10+t20+t30+t40-2;
} //切换到左转道工作
}
if(flag==3)
{ t3--;
if(t3==0)
{ flag=4;
t1=t10;
t2=t20;
t3=t30;
t4=t40;
t5=t10+t20+t30+t40-2;
}
}
if(flag==4)
{ t4--;
if(t4==0)
{ flag=5;
t1=t10;
t2=t20;
t3=t30;
t4=t40;
t5=t10+t20+t30+t40-2;
}//切换到红灯状态
}
if(flag==5)
{ t5--;
if(t5==0)
{ flag=1;
t1=t10;
t2=t20;
t3=t30;
t4=t40;
t5=t10+t20+t30+t40-2;
}//切换到直道通行状态
}
}
TH1=(65535-46083)/256;
TL1=(65535-46083)%256;//重新设置定时器T1的初值
}
/**************************************************
外部中断INTR0的中断子程序 :只有红灯亮,禁止通行
**************************************************/
void int0(void)interrupt 0 using 0
{
P1=0x3b;//只有红灯亮
display(88);
if(f==0)
{ h++;
if(h%5==0)
P37=~P37;//fh=2KHZ
if(h==10000)
{ t++;
if(t==10)
{ f=1;
t=0;
}
}
}
else if(f==1)
{ l++;
if(l%500==0)
P37=~P37;//fl=2HZ
if(l==10000)
{ t++;
if(t==10)
{
f=0;
t=0;
}
}
}
}