微机原理课设 汽车速度控制
热身
测接口实验
测试实验台的 8255 接口是否完好,可以这么测:按下一个键, LED 显示对应开关的打开与否。我们组运气比较倒霉,第一天时碰到有坏的接口。
需要注意的地方:把端口号(我们的实验台 IOY0 是 0600H,状态控制字端口是 0606H,控制字 82H 表示 B口输入 其他口输出),状态控制字都检验一遍,查看 8255 每个端口是否能正常输入输出。
;(1)按下任意一个键,LED显示对应开关的打开与否 IOY0 EQU 0600H AA EQU IOY0+0*2 BB EQU IOY0+1*2 CC EQU IOY0+2*2 MODE EQU IOY0+3*2 STACK1 SEGMENT STACK DW 256 DUP(?) STACK1 ENDS CODE SEGMENT ASSUME CS:CODE,SS:STACK1 START: MOV DX,MODE MOV AL,82H OUT DX,AL NEXT: MOV DX,BB IN AL,DX MOV DX,AA OUT DX,AL MOV AH,1 JMP NEXT MOV AH,4CH INT 21H CODE ENDS END START
流水灯实验要求
能够在自行设计的接口开发板上,利用不同开关控制 LED 灯的变化。例如:K1 从左往右,K2 从右往左,K3 从中间向两边,K4 从两边向中间依次亮灭变化
解法
这段代码当时做的时候没存储,不过代码的逻辑很简单:设置好实验台上的端口输出与状态字相关操作后,利用一个十六位的寄存器负责将数据输出到两个八排 LED 灯,每次循环执行 ROR 或者 ROL(根据需求而定)。
当时的实验台:
下面这段代码只是一个 Demo,可以以此基础上改:
;(2)流水灯实验 IOY0 EQU 0600H AA EQU IOY0+0*2 BB EQU IOY0+1*2 CC EQU IOY0+2*2 MODE EQU IOY0+3*2 STACK1 SEGMENT STACK DW 256 DUP(?) STACK1 ENDS CODE SEGMENT ASSUME CS:CODE,SS:STACK1 START: MOV DX,MODE 这几行是设置控制字 MOV AL,80H ;80H 输出, 82H输入 OUT DX,AL MOV BL,80H MOV BH,01H NEXT: MOV DX,AA 输出步骤:1、设置值 2、设置地址 3、向端口输出 MOV AL,BL OUT DX,AL MOV DX,BB MOV AL,BH OUT DX,AL CALL DELAY ROR BL,1 ROL BH,1 JMP NEXT MOV AH,4CH INT 21H DELAY PROC NEAR MOV CX,20H D1: MOV AX,0FFFFH D2: DEC AX JNZ D2 LOOP D1 RET DELAY ENDP CODE ENDS END START
数码管实验要求
能够在自行设计的接口开发板上,上电数码管显示 0-7,实现拨动不同开关,数码管显示该开关位置(1-8);若拨动两个及以上的开关,数码管显示“E”
解法
B口读取开关并进行条件判断,并利用右移判断有几个0,再根据这个信息找到段码中对应的值并显示在数码管上。没有啥很难的算法,当时被坑的地方主要在于段寄存器没有初始化,使得数码管半天不亮。
IOY0 EQU 0600H AA EQU IOY0 + 0 * 2 BB EQU IOY0 + 1 * 2 CC EQU IOY0 + 2 * 2 MODE EQU IOY0 + 3 * 2 DATA SEGMENT CODES db 00h, 3fh, 06h, 5bh, 4fh, 66h, 6dh, 7dh, 07h, 7fh, 6fh, 79h LEN EQU $-CODES DATA ENDS STACK1 SEGMENT STACK DW 256 DUP(?) STACK1 ENDS CODE SEGMENT assume cs:CODE, ds:DATA, ss:STACK1 START: ;set control-word MOV DX, MODE MOV AL, 82H OUT DX, AL ;set ds MOV AX, DATA MOV DS, AX L: ;GET KEY VALUE MOV DX, BB IN AL, DX CALL FUNCTION JMP L FUNCTION PROC CMP AL, 00H JZ DEFAULT CMP AL, 01H JZ SHOW CMP AL, 02H JZ SHOW CMP AL, 04H JZ SHOW CMP AL, 08H JZ SHOW CMP AL, 10H JZ SHOW CMP AL, 20H JZ SHOW CMP AL, 40H JZ SHOW CMP AL, 80H JZ SHOW JMP EXCEPTION SHOW: ;MOV AH, 00H ;MOV BL, 02H ;DIV BL MOV CL, 0 ;get Codes address ;ADD SI, AX ;ADD SI, 01H JMP COUNT DEFAULT: MOV SI, OFFSET CODES MOV AL, DS:[SI] ;set original value MOV DX, AA ;set address OUT DX, AL CALL DELAY JMP L NEXT: MOV SI, OFFSET CODES MOV AH, 00H MOV AL, 00H MOV AL, CL ADD SI, AX MOV AL, DS:[SI] ;set original value MOV DX, AA ;set address OUT DX, AL CALL DELAY RET EXCEPTION: MOV SI, OFFSET CODES ADD SI, len DEC SI MOV AL, DS:[SI] ;set original value MOV DX, AA ;set address OUT DX, AL CALL DELAY RET COUNT: ADD CL, 01H SHR AL, 1 JNC COUNT JMP NEXT FUNCTION ENDP EXIT : MOV AH, 4CH INT 21H DELAY PROC PUSH CX PUSH BX MOV BX, 0FFFH D1: MOV CX, 010H D2: LOOP D2 DEC BX JNZ D1 POP BX POP CX RET DELAY ENDP CODE ENDS END START
汽车控制
我们的汽车控制逻辑是这样:利用两个数码管显示汽车速度,一个数码管显示档位,4个开关控制速度的增加与减少,K1 为 1 挡(10 km/h),K2 为 2 挡(20 km/h),K3 为 4挡(40km/h),K4 为 6挡(60km/h),加速时只能依次加,而不能直接增加到 6挡,减速时可以直接从 60 减速到 0。
实现难点在于数码管的动态显示:由于四位一体数码管同用一个串口进行输入,这样的话我们就不能分别送不同的值给四个数码管,所以需要通过 8255 的 C 口输出数码管地址口而不是将数码管地址口全部接 GND,使其中三个通高电平,一个接地(共阴极数码管,相当于这个口输入为 0),使得某一个数码管亮而其他几个是熄灭的。然后再传值,传入的值是将速度除以 10 之后的十位数字或者是各位数字,采用 div 指令实现。然后我们通过改变延时时长与 call 子程序的次数,改变每个灯亮的间隔,让肉眼感觉多个数码管同时在改变数字。
代码部分
IOY0 EQU 0600H ;片选IOY0对应的端口始地址 MY8255_A EQU IOY0+00H*2 ;8255的A口地址 MY8255_B EQU IOY0+01H*2 ;8255的B口地址 MY8255_C EQU IOY0+02H*2 ;8255的C口地址 MY8255_MODE EQU IOY0+03H*2 ;8255的控制寄存器地址 SSTACK SEGMENT STACK DW 32 DUP(?) SSTACK ENDS DATA SEGMENT NUMS DB 3FH,06H,5BH,4FH,66h,6dh,7dh,07h,7fh,6fh,79H ; ;SELECT_OUTSMG1 DB 0H, 0FEH, 0FDH, 0FBH, 0F7H DATA ENDS CODE SEGMENT ASSUME CS:CODE,SS:SSTACK START: MOV AX,DATA MOV DS,AX MOV AX,SSTACK MOV SS,AX MOV DX, MY8255_MODE MOV AL, 82H ;1000 0001 表示A口C口高四位低四位输出,B口为输入 OUT DX, AL ;控制字送控制寄存器 MOV BX, 0 ;清零 CTRL: MOV DX , MY8255_B IN AL, DX ;C口值送AL,进行输入 MOV AH,0 ;AX的高8位清零 TEST AL,1H ;AL是否等于1,进行and操作,影响标志位 JNZ T1 ;若AL为XXXX XXX1,跳T1 MOV CX ,00 ;CX送0 JMP A1 T1: TEST AL, 2H JNZ T2 ;若AL为XXXX XX1X,跳T2 MOV CX,10 ;CX送10 MOV DX , MY8255_B mov AL,00010000B ; out DX, AL ;将AL的值给C口 JMP A1 T2: TEST AL, 4H JNZ T3 ;若AL为XXXX X1XX,跳T3 MOV CX, 20 ;CX送20 MOV DX , MY8255_B mov AL, 00100000B out DX, AL JMP A1 T3: TEST AL,8H JNZ T4 ;若AL为XXXX 1XXX,跳T4 MOV CX,40 MOV DX , MY8255_B mov AL,01000000B out DX, AL JMP A1 T4: MOV CX,60 ;CX送60 MOV DX , MY8255_B mov AL,10000000B out DX, AL JMP A1 A1: CMP BX,CX JNZ AMD ;ZF=0,跳AMD CMP BX,0 JE CWT ;ZF=1,跳CWT AMD: CMP CX,BX JB ASD ;CX小于BX,跳ASD CALL PRINT1 ;执行子程序,会返回 JMP CTRL ASD: CALL PRINT2 JMP CTRL CWT: CALL PRI JMP CTRL PRINT1 PROC ;因为每次只能亮1个的原因,所以要call多次实现肉眼错觉 CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI ;CALL PRI ;CALL PRI ;CALL PRI INC BX CMP BX,CX JB PRINT1 MOV BX,CX RET PRINT1 ENDP PRINT2 PROC CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI CALL PRI ;CALL PRI ;CALL PRI ;CALL PRI DEC BX CMP CX,BX JB PRINT2 MOV BX,CX RET PRINT2 ENDP PRI PROC PUSH CX PUSH DX PUSH AX PUSH BX ;速度高位 MOV AX,BX MOV CL,10 DIV CL ; AH 余数 AL 商 36 / 10 = 3 ..... 6 MOV CX,0 MOV CX,14 ;0000 1110b,就是设置第一个数码管亮 MOV BL,AL ; 3 CALL HUA CALL YANSHI ;速度低位 MOV BL,AH MOV CX,13 ;0000 1101b,就是设置第二数码管亮 CALL HUA CALL YANSHI ;档位 MOV BL, AL MOV CX,7 ;0000 0111b,就是设置第4个亮 CALL HUA CALL YANSHI POP BX POP AX POP DX POP CX RET PRI ENDP HUA PROC PUSH BX PUSH AX ;控制第XXX灯亮 MOV DX, MY8255_C MOV AX,CX OUT DX,AX ;B口输出CX ;输出值到数码管 MOV BH,0 MOV DX,MY8255_A MOV SI,OFFSET NUMS MOV AX,[SI+BX] OUT DX,AX ;A口输出BX,也就是NUMS[BX] POP AX POP BX RET HUA ENDP YANSHI PROC PUSH CX MOV CX,2000 YS: CALL YANSHI2 DEC CX JNZ YS POP CX RET YANSHI ENDP YANSHI2 PROC PUSH CX MOV CX,1 TYUY: DEC CX JNZ TYUY POP CX RET YANSHI2 ENDP CODE ENDS END START
实验台接法
注意实验台部分 B C 口对调,C 口低四位输入控制开关 ,所以代码需要将状态控制字改成 81 H 并且将下面的 MY8255_C 和 MY8255_B 对调
实验台效果展示
拨动 K1 K2,汽车速度为 20 km/h,档位为 2 挡
电路布线图
四位一体数码管的引脚可能会不一样,另外推荐做一个镜像图,焊板子背面的时候方便
洞洞板实物图
需要注意的是老师不让用飞线,而我嫌背面太丑用了两个飞线焊到了洞洞板的正面,所以得去掉这两个飞线,换成背面的导线
飞线版本的洞洞板(老师不让用)
无飞线版本
感悟
因为自己大一是电路相关专业的,有学过 C51 和 STM32 ,以及大二自己看了一点王爽的汇编,所以这次实验总体难度不大,但是周围的同学普遍对硬件有排斥的心理,而幸运的是我的队友们比较好,原意去学一下这次实验的东西。发现软工学生硬件真是一个硬伤,硬件课程少,没焊过甚至没见过电路板,感觉有点可惜