微机接口课程设计之远程控制步进电机实验
1.课程设计目的
- 熟悉各常用可编程接口芯片的工作原理、使用方法及引脚连接特性,正确操作实验设备,能根据设计要求制定总体方案,完成硬件连线,承担责任。
- 能够根据要求编写出满足功能要求的软件代码,能够利用开发工具进行设计调试、协助分析运行结果、定位设计错误等。
- 具有创新意识。尝试对所要求的功能设计提出有效的改进设想并努力实现;或尝试增加新的系统功能并努力实现。
- 具有对微机输入输出系统进行需求分析的能力,能针对具体的问题获取新知识完成系统的设计。
- 能够以口头和书面方式准确地描述、总结所完成的设计和主要成果,撰写比较规范的课程设计报告。
- 掌握综合控制键盘、数码管、步进电机的能力。
- 掌握有关中断服务程序的编制方法。
2. 需求分析
2.1 项目背景
远程控制技术在工业自动化领域有着广泛应用。本项目旨在通过远程控制步进电机系统,模拟工业现场中常见的远程精确控制场景。通过本项目,可以深入理解串行通信、电机控制等关键技术。
2.2 功能需求
2.2.1 用户需求
- 控制机功能需求:
- 通过键盘输入控制命令
- 实时显示电机位置信息
- 支持多种控制模式(速度控制、步数控制)
- 提供紧急停止功能
- 执行机功能需求:
- 准确解析并执行控制命令
- 实时计算并反馈位置信息
- 控制步进电机运动
- 本地显示位置信息
2.2.2 系统需求
功能性需求: 命令|功能 ---|--- A|停步进电机 B##|正转(速度:##转/分)(顺时针) C##|反转(速度:##转/分)(逆时针) D##|正向步进##步(顺时针) E##|反向步进##步(逆时针) F |程序结束
位置信息格式 说明 0### 正向位置(范围0~999) -### 反向位置(范围-999~0) 性能需求:
- 命令响应时间 < 100ms
- 位置信息更新频率 ≥ 10Hz
- 步进电机速度范围:1~99转/分
- 位置计数范围:±1000步
3.实验设备
本实验使用的主要设备包括: 1. 两套 SUN ES86PCIU+ 实验仪,分别作为: - 控制机:负责发送控制命令 - 执行机:负责接收命令并控制步进电机 2. 其中使用的主要硬件组件为: - 8255 可编程并行接口芯片 - 8259 可编程中断控制器 - 8253 可编程定时器 - 8251 串行通信接口 - 2×4 矩阵键盘 - 8 位数码管显示模块 - 步进电机(4相) 3. 开发环境:星研集成开发环境
4.硬件设计
4.1 系统硬件框图
4.2 关键硬件模块设计
4.2.1 步进电机驱动模块设计
原理图介绍与分析:
步进电机的步距角为18度(即转一圈走20步),采用单极型驱动1,其两个中心抽头(即图中的5线和6线)接VCC,因此驱动电机要给低电平。
ULN2003A是一个达林顿阵列驱动器,其包含7组达林顿对,每组达林顿对的工作原理是反相输出2,即输入为高电平则输出为低电平。我们在ULN2003A输入前加了四个非门,所以驱动电机我们要控制PC口输出的是低电平。
从原理图中我们可以看出,顺时针运转需要依次给 D -> C -> B -> A 进行通电,逆时针则是 A -> B -> C -> D。 8255的PC4、PC5、PC6、PC7分别接电机的A、B、C、D,因此8255的PC4~PC7要配制成输出模式。
驱动方式 逆时针(顺时针只需倒序激励序列) 单四拍 A->B->C->D->A 双四拍 AB->BC->CD->DA->AB 单双八拍 A->AB->B->BC->C->CD->D->DA->A
原理简述(以图中步距角为45度的简单步进电机为例)3:
复习一下安培定则:用右手握住通电螺线管,让四指指向电流的方向,那么大拇指所指的那一端是通电螺线管的N极。
如图所示,电机的转子有磁性,我们在定子铁芯上绕上线圈,根据安培定则可知改变通过线圈的电流的方向就可以改变它的极性,为简化驱动,我们没有采用需要改变电流方向的双极型电机,而是采用类似上图所示的单极型。图中红色代表N极,蓝色代表S极,以单四拍为例,给D通电,转子的N极与定子的S极一一对应,之后再给C通电,通过同性相斥、异性相吸的动力就可以驱动电机旋转。由于中心抽头的存在,我们一次只使用了半个线圈,所以两个绕组可以当成四个来用,即四相。
速度调节: 以单四拍为例,给A通电,电机逆时针旋转18度,过一秒后给B通电,电机再逆时针旋转18度,依次类推,每一秒通一次电就走一步,而转一圈要20步,因此此时电机转一圈要20秒,即速度为3r/min。由此可知,我们通过调整两次通电间的时间间隔(比如上述的1秒),就可以调节电机的转速。要精准地控制时间间隔,我们采用了8253定时器来完成这一点。
在速度为99r/min时,1min要走99 * 20 = 1980步,时间间隔约为0.03秒,在速度为1r/min时,1min走20步,时间间隔约为3s,公式表示一下时间间隔的计算即:\(n\ (r/min)\) 要求延时 \(= \frac{60\text{秒}}{n \times 20\text{步}} = \frac{3}{n} \text{秒}\)
8253定时器的计数初值最多可以有16为,二进制下最大是65535。若根据不同的速度要求给定时器置入不同的计数初值,将定时器的out用作中断,就可以在每一次中断发生时给线圈通电,以达到调速的目的。假设给8253的定时器0接 1Hz 的时钟频率,则计数初值的计算公式表示为:\(n\ (r/min)\) 要求计数初值 \(= {3 \over n}s = {3000 \over n}ms\) ,在 65535 的范围之内。
但是本次实验没有采用上述方式,而是固定计数初值,另设一个speed_delay变量来保存不同的速度下的延时,其单位为中断发生的次数,且8253定时器0接的是1MHz的时钟。这样,speed_delay的计算公式为:\({3\ \times 10 ^6 us \over {n\times N}}\) ,其中 \(N\) 为计数初值,在本次实验中N 取150,则speed_delay \(= {20000 \over n}\) 。
由于采用了中断的方式,因此我们还使用了8259芯片,该芯片的参数配置为:边沿触发,单片方式,中断类型号高五位为 00001,一般全嵌套,缓冲方式,非自动结束,只开放 IR0 引脚的中断请求,即将 8253 的out0 连接到 IR0上。
4.2.2 通信模块设计
通信方式选择依据: 由于并行通信的8255已被其他器件(如数码管、按键)占用,且并行传输距离过短,无法支持两个实验箱的距离,因此我们采用了串行通信的方式。 实验箱虽有RS485模块,但我们不需要多点通信,RS232的一对一已足够完成本实验所需功能4。可惜实验中缺少RS232的连接线,因此我们将两个实验箱靠的较近,以使通信距离较短,进而可以直接采用TTL电平的方式通信,我们选用了8251芯片,并使控制机和执行机的8251芯片的RxD和TxD交叉相连(其中RxD为接受,TxD为发送,即发送对接受,接受对发送)。
8251通信参数配置:
- 通信模式:异步通信
- 数据位:8位
- 停止位:1位
- 校验方式:偶校验
- 波特率:4800bps
- 波特率系数:16倍
- 工作模式:全双工(同时支持发送和接收)
可靠性考虑:
- 由于线路连接比较简陋,选择较低波特率(4800)以提高通信可靠性
- 采用偶校验位进行错误检测(但是本此实验中软件程序并没有对其处理,未来可以增加以提高通信的可靠性)
- 确保共用同一地(GND)参考电平
4.2.3 按键模块设计
原理图介绍:
实验箱上的矩阵键盘部分虽然看上去是 \(4 \times 4\) 的,但是通过原理图我们可知实际上这是一个 \(2 \times 8\) 的矩阵键盘。键盘的列线接8255的PB口,有两个行线,其中 KL1 接 PC0,KL2接PC1。
按键扫描分析:从原理图中可知,行线KL1和KL2接了一个上拉电阻到VCC,因此当没有按键按下时为高电平,采用逐列扫描的方式,向某一列输出低电平(而其他列为高电平),当某个按键被按下时,对应的行线就会被拉低,因此通过检测到的低电平行线和当前扫描列的组合可以得到该按键的行列码。因此也可知8255的PC0~PC3配置成输入模式,而PB口配置成输出模式。
按键消抖处理:
由机械按键的抖动特性:
机械按键的抖动时间一般在5ms~10ms之间
一般的机械按键按下持续时间不会低于100ms
因此我们采用延迟重采样的方式,一次延时间隔约10ms,一共重采样2次
4.2.4 数码管显示模块设计
原理图介绍:
数码管是共阳极的,段码和位选都是低电平有效,其段码接8255的PA口,位选接8255的PB口,因此8255的PB口和PA口都要配置成输出模式。
数码管扫描频率:扫描频率太低数码管会出现闪烁的现象,频率太高则亮度不够甚至无法看清,所以一般扫描间隔多为1ms或几毫秒,我们需要控制一下这个间隔时间。 根据对实验箱CPU模块的观察以及上网查找到的资料,本次实验的8086芯片由 SAB 8284B-P 时钟发生器和驱动器芯片提供系统时钟,SAB 8284B-P 外接的是 DX-A1V 12.000 晶振,最终供给8086的应该是8MHz5。 由此我们计算一下位扫描间隔时间,在delay中使用loop指令空循环以达到延时的目的,查阅资料可知在8086中loop指令在成功跳转情况下的时钟周期6是17,假设我们循环500次,这将耗费8500个时钟周期,为8500/8MHz = 1.0625ms,完全合适。
4.3 连线说明
控制机:
D3区(8255):CS、A0、A1 —— A3区:CS1、A0、A1 D3区:PC0、PC1 —— F5区:KL1、KL2 D3区:JP20(PB)、B、C —— F5区:A、B、C B3区:CS、A0 —— A3区:CS3、A0 B3区:INT、INTA —— A3区:INTR、INTA C4区(8253):CS、A0、A1 —— A3区:CS2、A0、A1 C4区:GATE —— C1区:VCC C4区:CLK1 —— B2区:2M C4区:OUT1 —— C3区:RxC TxC C3区(8251):CS、C/D —— A3区:CS4、A0 C3区:CLK —— B2区:4M C3区:RXD、TXD —— C3区(执行机):TXD、RXD 执行机:
D3区(8255):CS、A0、A1 —— A3区:CS1、A0、A1 D3区:PC4、PC5、PC6、PC7 —— D1区(步进电机):A、B、C、D B3区(8259):CS、A0 —— A3区:CS3、A0 B3区:INT、INTA —— A3区:INTR、INTA C4区(8253):CS、A0、A1 —— A3区:CS2、A0、A1 C4区:GATE —— C1区:VCC C4区:CLK0 —— B2区:1M C4区:OUT0 —— B3区:IR0 C4区:CLK1 —— B2区:2M C4区:OUT1 —— C3区:RxC TxC C3区(8251):CS、C/D —— A3区:CS4、A0 C3区:CLK —— B2区:4M C3区:RXD、TXD —— C3区(控制机):TXD、RXD
5.软件设计
5.1 数据定义
5.1.1 常量定义
1 | ;各外设端口地址 |
5.1.2 变量定义
1 | ;控制机 |
1 | ;执行机 |
5.2 各外设初始化
1 | ;CLK0 = 1M Hz |
1 | Init8255 PROC NEAR |
1 | Init8259 PROC NEAR |
1 | ; 8251初始化子程序 |
1 | ;CLK1 = 2M Hz |
1 | Reset8251 PROC NEAR |
5.3 控制机程序
5.3.1 控制机主程序
1 | ; 控制机主程序 |
5.3.2 读取两位参数子程序
1 | ; ReadTwoDigits - 读取两位十进制数字 |
5.4 执行机程序
5.4.1 执行机主程序
1 | ; 执行机主程序 |
5.4.2 命令处理子程序

1 | ; 处理命令子程序 |
1 | ; StartMotor - 启动电机连续运转 |
1 | ; StepMotor - 控制电机运行指定步数 |
5.4.3 延时计算子程序
1 | TakeDelay PROC NEAR |
5.4.4 中断
5.4.4.1 中断向量设置
1 | WriIntver PROC NEAR |
5.4.4.2 中断服务程序
1 | ; 定时器中断服务程序 |
5.4.5 位置计数更新子程序
1 | ; 位置计数更新子程序 |
5.5 通信程序
5.5.1 发送一个字节
1 | ;发送一个字节,输入参数 AL |
5.5.2 接收一个字节
1 | ; 接受一个字节,ZF = 0,且将结果存入AL |
5.5.3 发送一组数据
1 | ;发送一组数据,输入参数 SI,CX |
5.5.4 接受一组数据
1 | RecvGroup PROC NEAR |
5.5.5 延时
1 | ;延时 |
5.6 共同子程序
5.5.1 数码管扫描显示
1 | DISPLAY8 PROC NEAR |
1 | DIR PROC NEAR |
5.5.2 读取按键
1 | GETKEYA PROC NEAR |
1 | AllKey PROC NEAR |
5.5.3 UpdateDisplay
1 | ; 更新显示子程序 |
5.5.4 ConvertToDisplay
1 | ;for(int i = 0; i < CX; i++, AX /= 10) |
6.软硬件调试
数码管不亮
调用了Display8但是实验箱的数码管就是不亮,想了一下Display8是怎么实现的,原因是Display8只扫描一遍,而我没有循环重复调用显示数码管,以至于它是灭的。
实现F命令时出现PC指针超出范围
前期我在整个程序的最后,才调用INT 21H退出程序,但是由于代码太长,有三四百行,而JZ这种跳转指令只能跳转-128 ~ +127范围内的偏移量,显然超出范围了。(虽然后期我没有再把退出程序放到代码最后) 解决办法:中间加个 JMP 指令接力一下
尝试根据转速要求计算延时,但不知道电机的步距角
我先上网查了一下,好像大多数是1.8度,后来和老师讨论延时的计算时,有同学说这个电机看上去比较小,老师在淘宝上搜了一下微型步进电机,查看了参数,有一个产品的步距角是18度,觉得很像,让我测试一下转一圈是不是20步。我在电机的风扇上粘了一小块透明胶带,作为起始位置,将电机的转速调低,转过一圈时立马停止电机,此时数码管上的记录刚好是20步!
除法溢出
根据之前推导的计算延时的公式:\(StepDelay = {2000 \over n}\) ,我一开始想我的 \(n\) 最大只有 99,在 8 个 bit 之内,就想着采用 16 位的除法,但是没有考虑到:商是存在AL 中的,当 \(n\) 很小时,比如 \(n = 1\),商应该为 2000,显然 AL 这个8bit当寄存器最大只能存255,就产生的除法溢出。 解决办法:改用32位的除法。
步数减到0后突然从535开始继续递减,而不是999
这个问题是另一个同学调试我的程序时发现的,我之前还没有注意到这个问题,但是一直没有管这个问题,觉得可能是位置更新有点小问题影响不大,做完后续的其他模块后,我想起来这个问题,打算解决一下,发现问题没我想象的那么简单。
原本的 UpdatePosition 子程序是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20UpdatePosition PROC NEAR
CMP Direction,0
JE Pos_Inc
Pos_Dec:
DEC CurrentPos
CMP CurrentPos,-1000
JNE UpdatePos_Exit
MOV CurrentPos,0
JMP UpdatePos_Exit
Pos_Inc:
INC CurrentPos
CMP CurrentPos,1000
JNE UpdatePos_Exit
MOV CurrentPos,0
UpdatePos_Exit:
RET
UpdatePosition ENDP逻辑非常简单,是顺时针就将当前位置加一,加到1000变成0,是逆时针就将当前位置减一,减到-1000就变成0。但是在计算机的二进制中0 - 1 = -1,负数是用补码表示的,-1的补码是FFFFH,FFFFH经过ConvertToDisplay(内部是无符号除法)会变成65535,而我数码管显示只取低三位,所以减到0后就从535开始减了,非常合理地解释了我看到的一切!我很高兴的想,那把ConvertToDisplay里的除法改成有符号除法不就行了吗?!假的,FFFFH除以0AH后商是0,余数是FFFFH,按理说余数结果是-1一点没错,但是我数码管支持直接显示'-1'这个数吗?!段码里没有'-1'这个东西吧?毕竟这是一个'-'和一个'1',用两个数码管来显示的。没有办法,只能分类讨论了(见软件设计相应部分),并且把原本的第7位表示顺时针还是逆时针的定义改成了是正号还是负号。
想要让A命令实现暂停/启动的功能而不是单单只能停止,失败
我想实现暂停/启动的代码是这样的(由于错误的代码没有保存,这里用伪代码描述):
结果我按A它都停止不了了,然后我打断点调试的时候发现每次它都进入到第一个分支,溯源一下,发现上面的代码中,执行机收到命令后就停止电机运行了,所以走到A命令的处理时bRunning永远都是0,然后永远开中断让电机运行。但是我确实想用户在给电机新的命令时电机先停止运转,所以就放弃了把A命令实现为暂停/启动的功能。不过现在想来,可以在上面的代码中特判一下A命令,遇到A命令就不像遇到其他命令一样无脑关中断停止电机运转,而是直接进入命令处理环节。1
2
3
4
5
6if bRunning == 0:
bRunning = 1
STI
else:
bRunning = 0
CLI8251通信,控制机发过去但是执行机收不到,或者说收到的都是错误标志位拉满的奇怪数据
找了一个晚上的错,差点以为自己想做通信的念想到此为止了,准备写一对简单的收发程序专门对通信功能进行测试,这样避免了电机的其他部分代码的干扰,写新的测试程序的时候发现,原来执行机的定时器1忘记初始化了,导致两边波特率不一样,所以产生了数据错误。
可以收发数据,但是数据错位
在新的简单测试通信的代码中,我发现发一位数据可以正常接受一位数据,满心欢喜,然后放到电机程序上跑的时候,命令参数可以正确接收并显示,但是位置信息控制机显示的完全不对,简直是一团胡乱的数据,不知道是怎么回事,向老师询问之后说可能是不是错位了,让我写个静态的测一下。我就将之前发一位收一位的测试代码改成了发两位收两位,结果果真是错位了,发21但是收到的显示却是12,发三位791结果收成917。 我想是不是两次发送之间没有延迟,太快了导致的,就在两次发送之间尝试了很多不同的延时值,但是结果依然都是错位。到底为什么会错位呢?我想尝试单步调试一下寻找原因,但是在我手动控制发送机发一位执行机收一位,一共发收三次传完三个数据的时候,没有错位!全部正常接收了!而且无论重复多少次这个过程都是没有错位,太诡异了。
我实在是没有办法了,但是这个错位,让我想到了《计算机网络》里有提到过数据错位的问题,我寻思着数据链路层的任务是:封装层帧、透明传输、差错检测。那我将要发送的数据封装成帧是否可行呢?我看了一下要发送的数据,第一个字节(位置的符号位)只有可能是0或者1,就选择了0FAH这个较大的数当作帧头,用0FBH这个字节当作帧尾。在写的时候我还是担心,因为我没有实现透明传输,会不会把中间的正常数据误认为帧头或者帧尾之类的,因为毕竟位置的范围是0~999,包含FA也包含FB,不过先试试看吧。
要怎么实现封装成帧呢?如果仅仅是发送数据前先调用Sendbyte发送帧头,数据发完再调用帧尾的话,好像太不智能了,我每次发数据都要手动添加这两行代码,接收的时候也是,感觉太冗余了,就又写了一个SendGroup的函数,但是用一个函数的话,我怎么知道要发什么数据,发几个字节?这个好像通过寄存器很难传递,总不能AL是要发送第一个数据,AH是要发送的第二个数据诸如此类吧?借鉴了一下Display8的实现方式,采用存储器来传递数据,即在程序中定义一个缓冲区,我称之为IObuf,将要发送的数据存入这里,函数的入口参数中,SI就存着这个缓冲区的首地址,而CX就存要发送几个字节。
很可惜,在封装成帧(我的SendGroup)之后,我的数据收发还是不正确,但是单步调试又无法找出问题,有什么办法能在全速运行的情况下还能看到真实的收发数据是什么吗?我没有串口助手,就又开了一个大的存储空间(DATAbuf),专门用来存放收到的数据,存数据的实现就写在RecvByte里,一接受到就存下来,如下注释部分代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27; 接受一个字节,ZF = 0,且将结果存入AL
RecvByte PROC NEAR
PUSH DX
PUSH BX
MOV DX,Con_8251
Wait_Rx:
; D1: RxRDY,接收器是否准备好
IN AL,DX ;读入状态
TEST AL,2
JZ Wait_Rx ;有数据吗?
MOV DX,Dat_8251 ;有
IN AL,DX
; LEA BX,DATAbuf
; ADD BX,COUNT
; MOV [BX],AL
; INC WORD PTR COUNT
; LEA BX, COUNT
; CMP COUNT, 100
; JB Recv_Exit
;FULL:
; MOV COUNT, 0
Recv_Exit:
POP BX
POP DX
RET
RecvByte ENDP然后在FULL标记的代码处打一个断点,全速断点后就能在存储器窗口看到收的100个数据了,如下:
一帧的数据有三个字节,我们可以从接收到的数据中看出帧尾FB经常会出现两遍,但是帧头只有一个,并且数据的位置信息部分从01 9A 到 01 9B 到01 9C等等,看上去是完全正确接收了,那我就回过头来看一下我代码是怎么解析接受到的数据了,这一看就发现,之前手误把高低字节接受的顺序和发送机的搞反了,改完这个问题后,我的机子就实现了正常通信啦。
控制机的数码管显示有明显的闪烁
这是中途问老师问题,老师提出来的,让我把数码管的频率改改,我当时想着这系统时钟不是固定吗?我哪能提高?而且数码管的显示图方便是调用的库函数,也不是自己写的,这库函数我也改不了呀,就一直搁浅了这个问题。写报告的硬件设计部分涉及到了数码管显示的问题,我想起来这个问题,就好好研究了一番,发现库函数设计的扫描频率挺合适的,并且我执行机数码管不怎么闪,就控制机闪,我又回头看了一下我写的代码,坏!答辩的时候老师问我
JZ CONTROL_LOOP
的作用是什么,我说它如果没有位置更新还要跳回去显示数码管(上一次的值),还要去扫描按键等等,结果我代码里居然没有显示数码管(因为之前大量的简单测试代码,以及帮某人调试代码时都是把Display8放在循环的开头就显示了,以至于我理所当然的认为我的最终代码也是这样的,结果居然不是),只在 updateDisplay 里显示了,而 updateDisplay 只有有位置更新的时候才会调用,位置更新是通过8251通信从执行机里接收过来的,通信肯定有延迟吧,怪不得闪的厉害,我觉得原因应该是这样,并且在写报告的时候在循环开头把数码管显示加上去了,只是可惜如今实验室已经关门了,没法再测一下了。单步调试的时候进中断就出不来了
为了解决一些在中断函数中出现的疑问,常常想单步调试一下中断,在特定情况下再返回主程序,但是一旦在中断里单步,就算把断点撤了,再全速运行,结果还是在中断函数的开头停下来了,哪怕我没在那里打断点。
解决办法,可以临时加一些在特定条件下才会执行到的代码,然后再此处打上断点,全速断点到这里后再把这个断点删了,再在想回到的主程序的地方打断点,再全速断点,避免在中断函数里进行单步。
原因解释:首先单步一定是走不出中断程序的,因为我们太慢了,8253定时器是独立于8086工作的,在中断的时候8253的定时器依然在计数,依然在产生中断。至于为什么全速运行也走不出中断,还是会在中断入口处停下,暂时没有找到合理的解释。
7.设计总结
7.1 主要功能实现情况
本设计成功实现了以下功能:
- 基本控制功能:
- 步进电机的启停控制
- 正反转速度控制(1-99转/分)
- 正反向步数控制
- 实时位置显示
- 通信功能:
- 控制机与执行机之间的串行通信
- 命令和参数的可靠传输
- 位置信息的实时反馈
- 显示功能:
- 控制机显示当前命令和位置信息
- 执行机显示实时位置计数和接收到的命令
7.2 技术特点
- 硬件设计:
- 采用8251芯片实现TTL电平的串行通信
- 使用8253定时器实现精确的速度控制
- 通过8259中断控制器处理定时器中断
- 利用8255并行接口实现键盘扫描、数码管显示和电机驱动
- 软件设计:
- 采用帧格式封装提高通信可靠性
- 实现位置计数的正负值显示
- 使用中断方式控制电机转速
- 采用查表法实现数码管显示
7.3 创新点
- 通信可靠性设计:
- 采用帧头(0FAH)和帧尾(0FBH)标识,实现数据包的完整性检验
- 通过缓冲区管理提高通信效率
- 人机交互优化:
- 实现正负位置值的直观显示
- 提供实时位置反馈
- 支持多种控制模式切换
7.4 存在的不足与改进建议
- 功能扩展:
- 增加电机缓启动功能
- 实现更多控制模式,如增加选择是单四步还是双四步还是单双八步
- 当电机走完设定的步数时用蜂鸣器提醒用户
- 可靠性提升:
- 完善通信协议,实现透明传输
- 添加通信超时处理
- 实现数据校验和重传机制
8.心得体会
初版代码部分借鉴星研的 SUN ES86PCIU+
使用手册中的综合实验四:步进电机实验
所提供的代码,最初实现的也是步进电机综合控制实验,想着和远程控制步进电机实验功能基本一样,后期扩展成通信也方便实现。这是我第一次读别人的这么长的汇编代码,读得非常非常难受,基本上是捧着课本在读,好多指令的作用要翻书看一下,好多重复出现的指令的意思也记不住,看到只觉得眼熟,或者大概知道是做什么的,但是具体是从哪个隐含的寄存器放到哪个隐含的寄存器就说不上来了,还得翻书,尤其是串操作类指令,这部分上课也没讲过。这个代码我读了有一两天,边读边加注释,最后感觉对整个运行的框架和流程还是感觉有些不清晰,就照着代码画了一份流程图来帮助我理解,如下:
此时我觉得我基本上能非常清晰地理解整个代码逻辑了,甚至还见识到了神奇的函数跳转表这种写法,想着照葫芦画瓢是不是就能完成这次实验了,然后发现也没那么容易,命令处理那边好多要改,基本上除了初始化和一些转换的代码外全都重写了。
好处是这份代码给我提供了控制电机的方式和大体框架,坏处是我读懂代码,且觉得实现的很合理,但是没有细细思索背后这么设计的原因,而直接把大体控制流程复刻到我的实验当中,以至于我回头写报告再细细分析硬件设计部分时,我觉得在目前功能实现较为简单的情况下,可能有更方便的解决办法,如步进电机的延迟处理,可以不用那么麻烦,而是采用我在硬件设计部分提到的重新置计数初值的方式。不过我现在也知道为什么他要这么设计延时方式了,因为他还多一个当电机设置速度过快时缓慢启动的过程,而我没做这个。
9.参考文献
10.答辩记录
Q:你是怎么解决数据错位的?
A:我在数据发送时添加了帧头和帧尾,只有检测到帧头才开始接收一帧数据。
Q:CONTROL_LOOP 的作用是什么?
A:负责数码管显示的动态刷新和按键状态的定期扫描,维持系统状态的连续性,即使在没有新的位置信息时,系统也需要通过这个循环来维持上一次的显示状态。
"单极步进电机和双极步进电机的区别" https://blog.csdn.net/qq_40862304/article/details/106266399↩︎
"快速上手ULN2003达林顿管阵列,并学会控制步进电机" https://www.bilibili.com/video/BV1Uy4y1g7gY/↩︎
"步进电机的巧妙原理" https://www.bilibili.com/video/BV1nA4m1A7Ke/↩︎
"RS232和RS485通信总线" https://blog.csdn.net/m0_61298445/article/details/124108925↩︎
"SAB8284B-P Datasheet" https://www.alldatasheet.com/html-pdf/45585/SIEMENS/SAB8284B-P/3551/14/SAB8284B-P.html↩︎
"Intel 8086 Instruction Timing" https://www.oocities.org/mc_introtocomputers/Instruction_Timing.PDF↩︎