8086_i386试验箱综合设计实验

8086_i386试验箱综合设计实验

完成于 2018-3-27 22:22:03
tags:

  • 汇编
  • 计算机原理

设计要求

  1. 利用实验台上的开关(K7-K4),实现步进电机的转速、转向控制。具体要求如下:

    • 利用8255的PC3-PC0做输出,输出步进电机的相序、驱动步进电机工作(同时使用四个LED监视步进电机的相序信号),相序之间的时间决定着步进电机的转速,而间隔时间由延时程序中的CX寄存器的初值决定。
    • 利用8255的PC7-PC4做输入,与K7-K4连接。其中K7做步进电机的转向控制,其余位做步进电机的转速控制。程序运行时通过K7-K4对步进电机实施动态控制。
    • 利用8253做秒脉冲发生器,产生约2秒的周期性方波信号。其中CNT0做分频器:将1MHZ信号分频为100HZ;CNT1做秒脉冲输出(0.5HZ)。
    • 利用386模块的主8259的MIR5做中断请求输入,将CNT1的OUT1秒信号方波作为中断请求信号,引发中断服务ISR。
    • 在中断服务程序中实现对步进电机的转速、转向实时记录存储。方法如下:在ISR中,对D8255的PC7-PC4口进行一次输入操作,并根据输入的数据:
      • 对D7(与K7对应)位的数据识别为步进电机的转向控制;
      • 对D6-D4(与K6-K4对应)位的数据识别为步进电机的转速控制。
  2. 利用实验台上的8*8点阵显示电路实现“小人跑步”的模拟。具体要求如下:

    • 利用8255的PA7-PA0与8*8LED点阵显示模块的“行线Ri”连接,控制着每一列的8个LED的显示数据。
    • 利用8255的PB7-PB0与8*8LED点阵显示模块的“列线Ri”连接,列线信号即为“位扫描”信号,决定着8255的PA数据显示在哪一列LED上。
    • 利用8*8LED点阵显示一个小人在运动的动态画面,即显示一个小人四肢在摆动。
    • 实现小人运动的速度与电机转速保持一致。即步进电机转速快,则小人运动快,转速慢,小人运动慢。
  3. 利用实验台上的六位数码管锁存器驱动动态显示具体档位。具体要求如下:

    • 利用六位数码管模块的CPU模式实现功能。
    • 利用锁存器(74LS73)电路实现一位共阴极数码管动态显示档位。
    • 实现六位数码管锁存器驱动动态显示具体档位,即由滑动开关确定档位后,即时的显示对应的档位数字。
  4. 利用试验台的8253完成一个定时提示器。具体要求如下:

    • 在CNT1的基础上,利用8253的CNT2做负脉冲发生器(0.1HZ)。
    • 指定计数初值,实现定时使逻辑笔闪烁,实现提示功能。

设计分析及系统方案设计

程序结构

主要程序组成如下结构图。

结构图

算法描述

开关控制步进电机的转速、转向

步进电机驱动原理是通过对电机每相线圈施加某一顺序电压(电流)来使电机作步进式旋转。驱动电路由脉冲信号来控制,所以调节脉冲的频率便可改变步进电机的转速。由ULN2803八路达灵顿反向驱动器实现电机的电流驱动,只要在ULN2803的输入端(BJ_IN1~BJ_IN4)提供相序信号。经ULN2803反相后实现电机的驱动。ULN2803与步进电机的链接在实验台上已经完成。利用8255的低四位PC端口连接到ULN2803的输入端,输出脉冲序列,从而控制步进电机的旋转。

程序设计中,为了实现更为便捷的操作,使用“双四拍”相序信号。于是将初始相序存放在一个寄存器中(原始相序数据位33H),然后利用对该寄存器“移位”的方式产生下一个相序。这种方式下,输出脉冲的频率决定着步进电机的旋转速度,而对寄存器中的数据移位方向则决定着电机旋转方向。

所以在程序设计中,通过读取8255的PC口的高四位,以PC7作为方向,将其存放在方向数据变量direc,进而控制步进电机旋转方向。而PC6~PC4中数据作为速度参数,这里的速度参数存在程序中的速度数据变量speed中,而它又与步进电机相序输出的延时有关。以这样的方式,实现了对于步进电机的速度的调控。

在这里需要指定8255的工作方式,向8255的控制口输出10001000b,设定PA,PB口为输出,PC高位输入,低位输出。

实际中,还需要利用8253来实现定时引发自定义的中断。对于1MHZ时钟进行两次分频,最终获得周期为2s的输出信号,将这个信号接到MIR5上,定时引发中断。在中断程序中实现对于开关信号的读取和转存到对应的变量direc和speed内的功能。在编制与中断相关的程序时,需要设定中断屏蔽字、中断向量表以及开中断的操作。

在利用PC口进行读写操作时,这里需要注意,由于高四位为输入,低四位为输出,这导致读写数据时会修改了其他端口的数据,这对于程序的正常运行是不利的。所以,需要使用“读改写”的操作,在写数据的时候,先读入数据,再保留高四位的基础上,只写入低四位数据,再利用OUT指令输出。这样就保证了数据的稳定性和程序的健壮性。

8*8点阵显示

这里要实现对于8x8点阵的操作,在连接好8255的PA与行接口,PB与列接口后,通过对PA与PB的写数据,可以实现对具体LED的操作。为了实现小人跑步的模拟,需要先在数据段中准备好至少两份不同的小人动作的图形字符码,即程序中的LED1与LED2。通过利用speed来控制8x8点阵的扫描速度,来实现小人的运动速度的控制。这里利用speed来控制,也有利于点阵变化与步进电机变化的同步,更为合理的实现了“小人跑步”的概念设定。

8*8点阵图案的绘制,首先需要设定最高位扫描码,再通过对8255的PB口输出0,来关闭扫描信号,熄灭led,接下来通过向PA送列码,向PB送对应的列上的行的数据,不断地左移列码,显示行数据,这就是实现了图案从左向右扫描不断地显示。而多次调用,显示不同的图案,从表面上来看,就是实现了小人的运动状态的“模拟”。

六位数码管显示

程序使用的是CPU模式来操作一个七段数码管,来显示对应的数据的档位。对于数码管的操作,需要指定它的地址,这里使用220h,这里实际指定的是字型码锁存器,而扫描码锁存器地址为221h。实际的使用需要向220h中写入对应的字形码,指定显示的数字,而向221h中写入对应的扫描码,指定使用的数码管的位置。

程序设计中,先在数据段中指定0-3的字型码,对应四个档位。利用分支结构,实现了对应的字型码的选择。再对220h与221h中写数据,进而实现对于不同档位的显示。

定时指示

为了实现对于“运动者”定时的提示,利用8253的CNT2手动指定初值,以及工作于方式2,来实现对于CNT1输出的2s的信号定时引发负脉冲的功能,将输出接到逻辑笔上,进而实现了指示功能。

对8253的控制口输出控制字0b4h,指定cnt2的工作方式。实现负脉冲发生器。

硬件电路图

8255

用于配合CPU实现对8x8LED点阵,步进电机以及滑动开关的数据的相关读写操作。初始化命令字为10001000b,PA,PB口链接行列接口,控制8x8LED点阵,PC3~PC0连接BJ_IN4~BJ_IN1以及LED灯,用于控制步进电机和显示相序,PC7~PC4接K7~K0,用于读取开关数据。

8255连接方式示意图

8253

用于实现对于基准时钟1MHZ的分频输出2s脉冲引发中断以及指定时间输出到逻辑笔。

8253连接方式示意图

数码管

用于显示对应的档位数字。将地址接到230h即可

数码管示意图

程序流程图

主程序以及中断服务程序流程图

8*8LED显示以及七段数码管显示子程序

程序清单

```asm
; 2018-3-27 22:57:16
; BY: Lart Pang

.model  small
.386

;begin  for variable of address
io8253_0    equ 200h
io8253_1    equ 201h
io8253_2    equ 202h
io8253_k    equ 203h
p8255_a     equ 210h
p8255_b     equ 211h
p8255_c     equ 212h
p8255_ctl   equ 213h
SMG         equ 220h
;end    for variable of address

data    segment
    ;begin  for motor
    buf     db 0                ;相序存储
    speed   db 0                ;转速控制
    direc   db 0                ;转向控制
    ;end    for motor

    ;begin  for 7-seg led
    ledcode     db 3fh, 06h, 5bh, 4fh    ;0-3的对应字形码 
    ;end    for 7-seg led       

    ;begin  for 8*8 led
    led1    db 88h, 44h, 24h, 1fh, 1fh, 24h, 44h, 88h
    led2    db 02h, 04h, 84h, 7fh, 7fh, 84h, 04h, 02h
    count   dw 00h              ;查表计数器
    bz      dw ?                ;定义一个位扫描码字的空间
    ;end   for 8*8 led
data    ends

ss_seg  segment stack
    dw  100 dup(0)
ss_seg  ends

code    segment
    assume  cs:code, ds:data
start:
    cli                         ;关中断
    mov     ax, data            ;指定数据段
    mov     ds, ax

;begin  8259 for interruption
    in      al, 21h             ;读IMR寄存器
    and     al, 11011111b       ;开放主片IR5中断
    out     21h, al             ;装载中断到IMR

    push    ds                  ;压栈保存数据
    mov     ax, 0               ;设置中断向量
    mov     ds, ax              
    lea     ax, cs:int_proc        ;AX指向中断程序入口地址
    mov     si, 35h             ;中断类型码35H
    add     si, si               ;35H*4H找到相应中断向量表中的位置
    add     si, si
    mov     ds:[si], ax           ;装入自定义中断服务程序IP
    push    cs                  ;将CS压栈,用以获取CS地址存到AX中
    pop     ax
    mov     ds:[si+2], ax          ;装入自定义中断服务程序CS:int_proc
    pop     ds                  ;恢复数据
;end    8259 for interruption

;begin  8255 for initialization
    mov     dx, p8255_ctl       ;设定A口方式0输出,B口方式0输出  
    mov     al, 10001000b       ;高C口方式0输入,低C口方式0输出 
    out     dx, al
;end    8255 for initialization
    
;begin  for setting the initial phase sequence
    mov     buf, 33h            ;初始相序33h = 0011 0011,这里是用"双四拍"
                                ;相序驱动电机,故实际使用33h
;end    for setting the initial phase sequence

;begin  8253 for frequency division
    ;第一次分频  1M-->1K
    mov     dx, io8253_k        ;cnt0 双数 方式3 二进制
    mov     al, 36h             ;00   11   011  0
    out     dx, al              ;方波发生器,方式3  
    
    mov     dx, io8253_0        ;cnt0产生1000Hz(1ms)的时钟
    mov     ax, 1000            ;分高低位写入1000
    out     dx, al
    mov     al, ah
    out     dx, al
    ;第二次分频  1K-->0.5
    mov     dx, io8253_k        ;cnt1 双数 方式3 二进制
    mov     al, 76h             ;01   11   011   0 
    out     dx, al
    
    mov     dx, io8253_1        ;cnt1产生0.5Hz的时钟
    mov     ax, 2000            ;分高低位写入2000
    out     dx, al
    mov     al, ah
    out     dx, al
    
    ;计时         2s->10s
    mov     dx, io8253_k        ;cnt2 双数 方式2 二进制
    mov     al, 0b4h            ;10   11   010   0 
    out     dx, al
    
    mov     dx, io8253_2        ;cnt2产生指定时间的负脉冲
    mov     ax, 5               ;分高低位写入指定数据
    out     dx, al              ;这里指定为5
    mov     al, ah
    out     dx, al
;end    8253 for frequency division

;begin  main program
    mov     dx, p8255_c         ;读取8255C口内容
    in      al, dx              ;由于C口既有输入又有输出,所以为了不会干扰
    and     al, 11110000b       ;在写数据的时候,要保证不会改动输入的口的数据
    mov     bl, buf
    and     bl, 00001111b       ;只写buf的低四位到al里
    add     al, bl              ;这里需要在低四位写数据,所以保留高四位。
    out     dx, al              ;将数据传送
    
loop_main:   
    cmp     direc, 0            ;比较direc,决定相序正向输出还是反向输出
    je      direc_0             ;这里的方向控制实际上就是通过改变相序的循环方向
                                ;进而改变的
    mov     al, buf             ;载入相序
    ror     al, 1               ;循环右移一位
    jmp     direc_1
direc_0:                
    mov     al, buf 
    rol     al, 1               ;循环左移一位
direc_1:                        ;移动完成后,进行后续操作
    mov     buf, al

    mov     dx, p8255_c         ;读取8255C口内容
    in      al, dx              ;由于C口既有输入又有输出,所以为了不会干扰
    and     al, 11110000b       ;在写数据的时候,要保证不会改动输入的口的数据
    mov     bl, buf
    and     bl, 00001111b       ;只写buf的低四位到al里
    add     al, bl              ;这里需要在低四位写数据,所以保留高四位。
    out     dx, al              ;将数据传送

    sti                         ;开中断

    ;begin  8*8 led & 7-seg digital tube
    mov     di, offset led1     ;设di为字型码缓冲区(指向首地址)
    call    display
    mov     di, offset led2     ;设di为字型码缓冲区(指向首地址)
    call    display    
    call    disp_shumaguan
    ;end    8*8 led & 7-seg digital tube

    jmp     loop_main
;end    main program

;begin  for interrupt service program
int_proc    proc far
    push    ax                  ;保护现场
    push    cx
    push    dx
    
    mov     dx, p8255_c         ;读8255C口,修改方向
    in      al, dx              ;读取端口信息
    and     al, 80h             ;1000 0000保留方向位
    mov     direc, al           ;将方向存入方向存储单元
    mov     dx, p8255_c         ;再读8255C口,修改速度
    in      al, dx              ;读取端口信息
    and     al, 01110000b       ;0111 0000保留速度档位
    mov     speed, al           ;将速度档位信息存入存储单元

    mov     al, 20h             ;发EOI结束命令
    out     20h, al

    pop     dx                  ;恢复现场
    pop     cx
    pop     ax
    sti                         ;开中断
    iret
int_proc    endp
;end    for interrupt service program

;begin  for 8*8 led display
display     proc
    push    bx                  ;保护现场
    push    ax
    push    dx
    
    mov     count, 0000h        ;计数器初始值0
    mov     bh, 01h             ;产生最高位扫描码
    mov     al, 0               ;扫描码消失(熄灭)
    mov     dx, p8255_b         ;指向b口
    out     dx, al              ;输出扫描码熄灭数码管
again:
    mov     byte ptr bz, bh     ;将位扫描码字节送存储空间bz
    push    di                  ;保存变量指针
    add     di, count           ;修改变量数据指针(基地址+偏移量)
    mov     bl, byte ptr [di]   ;查表得到变量数据送bl
    pop     di                  ;恢复变量指针
    mov     al, bl              
    mov     dx, p8255_a         ;指向a口
    out     dx, al              ;输出扫描码
    mov     al, byte ptr bz     ;使相应的数码管亮
    mov     dx, p8255_b
    out     dx, al              ;显示字型
    inc     count
    push    cx                  ;保护CX
    mov     dh, speed           ;设定延时
dh_0_disp:
    mov     cx, 30h             ;设定循环延时次数
loop_disp:   
    loop    loop_disp
    dec     dh
    jnz     dh_0_disp
    pop     cx                  ;恢复CX
    
    mov     al, 0               ;扫描码消失(熄灭)
    mov     dx, p8255_b         ;指向b口
    out     dx, al              ;输出扫描码熄灭数码管
    mov     bh, byte ptr bz      ;取出扫描码
    shl     bh, 1               ;将扫描码右移一位
    jnz     again               ;如果不等于0就跳转again
    
    pop     dx                  ;恢复现场
    pop     ax
    pop     bx
    ret
display     endp
;end    for 8*8 led display

;begin  for 7-seg digital tube
disp_shumaguan  proc
    push    bx                  ;保护现场
    push    ax
    push    dx
            
    mov     al, speed           ;读取已经存储好的速度信息
    cmp     al, 01000000b       ;第一档
    jz      al_1
    cmp     al, 00100000b       ;第二档
    jz      al_2
    cmp     al, 00010000b       ;第三档
    jz      al_3
    ;al=0
    mov     si, 0               ;第0档:最慢,因为其间隔时间最长
    jmp     next_0
al_1:
    mov     si, 1
    jmp     next_0
al_2:
    mov     si, 2
    jmp     next_0
al_3:
    mov     si, 3
next_0:
    lea     bx, ledcode             ;将数码管的字形码地址赋给BX里
    mov     bl, [bx+si]           ;将对应的字形码存放到BL里
    mov     al, bl
    mov     dx, SMG             ;将数码管的地址存到DX里
    out     dx, al
    
    mov     al, 01h             ;设置数码管的位码,这里使用第一个数码管
    inc     dx                    ;数码管的位码,在CPU模式下
                                ;要存在数码管地址的下一地址
    out     dx, al
    
    pop     dx                  ;恢复现场
    pop     ax
    pop     bx
    ret
disp_shumaguan  endp
;end    for 7-seg digital tube

code    ends
    end     start               ;程序结束
```

实验结果与分析

系统运行环境

  • 硬件:Windows XP 32位、386EX试验箱
  • 软件:HQFC集成开发环境
  • 设计语言:8086汇编

调试遇到的问题

  • 由于使用了8*8点阵,导致只能将8255的接口PC分高低位用于不同的工作方式。在按此,高四位接好滑动开关,低四位接好步进电机后,运行程序,发现显示结果不正常。
  • 在最后,准备利用8253分频配合逻辑笔,实现定时提示功能,代码写好,接口连接好后,发现逻辑笔始终显示低电平。

对应的解决办法

  • 因为在程序中的读写PC口的时候,没有考虑到每次的写操作,是会影响到另外的四个口的数据的。所以在原来向PC口写数据的基础上,进行了进一步的处理,即“读改写”操作,先读回来原来的数据,只修改低四位,改为想要发送的数据,再写回去。这样就避免了互相干扰的问题,最终恢复正常了。
  • 仔细检查代码后,发现,原来是CNT2相应的命令字写错了。对于2号计数器的指定出了错误,应该是0b4h,结果写成了0e4h。这里主要是因为对于16进制数字不熟悉的结果,导致信息错乱,没有输到想要的位置上。

系统运行结果

由下图可见,最终实现了档位指示,小人跑步模拟,步进电机的转动以及定时提示。

实验结果图

结论及设计体会

最终,完成了自己的设计,实现了“跑步机”的模拟。

最终完成的功能有:8*8LED点阵动态显示小人运动,一位七段数码管显示对应的速度档位,而利用滑动开关,实现跑步机(步进电机)的正反转和档位的控制,同时,利用分频实现定时功能,可以在指定时间输出负脉冲,将逻辑笔的指示灯切换,最终实现了定时提示的功能。

这个实验持续了两三周的时间,之前由于有考试,主要的精力没有放在这个上面,只是先做好了步进电机的基本功能,还未拓展点阵和数码管的功能。不过还好,最后还是赶上来了。

这个思路很好,在一个小的,课本的例子的基础上,不断扩展,不断增加更多的功能,这样也让我在不断地学习新的模块的知识,同时不同模块之间的配合,也在考验着我的能力,因为并不是把模块拿来接好就可以用的,总是会遇到各种各样的问题,需要我们不断地取寻找,解决。

这时,渐近式的编程就显得尤为重要。保留好源代码,先修改一部分,测试,再修改,再测试,不断地反复,直到效果满足预期要求,否则就不能拿来用,只能使用原来的未修改的源代码。这里也提示了我们,及时存档的重要性。

总的看来,磕磕绊绊,但还是走到了终点。

本次试验最遗憾的事情就是12864没用上。为了它我花费了半天时间,查资料,咨询老师,研究了半天,但最终也还是也没有用上12864。不过还是感谢老师的指导。

这次实验学到了很多,包括各种模块的使用,接口操作,中断操作,这都是在程序设计中使用到的,以及对于各种问题的调试解决方法,甚至对于编程也有了进一步的认识。汇编这门语言也因此而熟练了许多。感觉获益匪浅。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值