吉林大学单片机实验三 步进电机原理及应用
  9i7LsoN8SSEp 2023年11月02日 38 0

实验题目

编制MCS-51程序使步进电机按照下面规定的转速和方向进行旋转:

  • 以40转/分速度正转5周,等待S1开关按下

  • 以25转/分速度反转10周,等待S1开关按下

  • 以10转/分速度持续正转,当按下S2开关时暂停旋转

将已转动的步数(不管正反)以十进制显示在数码管上。

本程序要求使用定时器中断来实现,不准使用程序延时的方式。

学习路径

1.步进电机工作原理

步进电机与驱动芯片FAN8200连接,FAN8200有4个引脚,分别是

FAN8200 CPU 备注
P1.1 CE1 CE1是控制引脚,相当于IN1的使能引脚
P1.4 CE2 CE2是控制引脚,相当于IN2的使能引脚
P3.2 IN1 控制步进电机转动的引脚
P1.0 IN2 控制步进电机转动的引脚

在实验中,IN1和IN2按照 01->11->10->00->01 输出,电机就会朝一个方向转动,电机转动一周需要24步

2.定时器中断

简单来说,定时器就是一个累加器,每经过一个定时周期,累加器加一,直到累加器溢出,就会产生一个中断信号。

定时器的4种工作方式

  • 方式0,13位定时器
  • 方式1,16位定时器
  • 方式2,8位定时器,自动重装计数初值
  • 方式3,T0分成两个8位定时器

定时器的初值设定

定时周期 = 12/CPU晶振频率(本实验中晶振频率为12M)
累加器最大计数值 = 2^定时器最大位数(定时器最大位数取决于工作方式)
计数初值 = 累加器的最大计数值 - 计时时间/定时周期

使用定时器需要用到的寄存器

寄存器 功能 计数结束后是否需要重新设置
IE 中断允许寄存器
IP 中断优先级寄存器
TMOD 定时器控制字(设置定时器工作方式)
TCON 定时器控制字
THx,TLx 定时器初值 除方式3外,需重新设置

也可以参考网上关于定时器中断的更多资料

3.数码管显示
试验箱上的数码管与实验二仿真实验中的数码管连接方式相同,但是增加到了三个,使用P4.4和P4.5控制,分别是数据线和检测上跳沿移位。74hc595的复位引脚并未连接至CPU。

P4口是扩展接口,是把内存中的一个地址映射为P4口,所以使用前需要进行如下设置

P4 EQU 0C0H     ;宏定义,把内存中的一个单元映射为P4口
P4SW EQU 0BBH   ;宏定义,给P4SW的地址起一个别名
MOV P4SW,#30H   ;设置启用P4口

4.学习定义变量

本次实验需要存储很多数据,所以要学会定义变量。单片机中的变量定义很简单,就是给某一个内存地址起一个别名,后面就可以直接用这个别名访问这个地址。但是要注意以下几个问题:

1.这个地址不能和已经有用的地址重合,比如堆栈区,特殊功能寄存器。

2.我们定义的变量相当于内存数,使用的时候要注意指令能否把内存数作为操作数。

3.并非每一个地址都能进行位编址,也就是不是每一个地址都能定义成bool型变量。

如果能理解透彻单片机的存储结构,那么变量定义就不会是一件难事,建议参考网上的关于单片机存储结构(单片机片内数据存储区)的相关文章。

5.学习keil软件和stm烧录软件

主要步骤为

1.选择cpu型号,建立工程
2.建立新文件,编写代码
3.设置生成.HEX文件
4.在stm软件中烧录程序(使用stm软件打开时的默认参数就可以可以完成烧录)

编程思路

首先,我们要明确控制步进电机转动的方式。根据题目中给出的转速,我们可以计算出转一圈的时间,因为一圈需要24步,进而计算出前进一步的时间。使用定时器,每经过预设的时间,向IN1和IN2输出下一步的电平,就可以让步进电机以预设的转速转动。

这一步存在一个问题,前进一步的时间会超过定时器能设置的最大时间,这就需要我们记录进入中断的次数,直到多次进入中断,达到预设时间时,才进行下一步操作。

然后,我们需要确定程序主体的框架。这个程序要求很长,但仅仅是长,并没有很多控制逻辑,所以我们可以像写顺序结构的c语言代码一样写这个程序。实现第一行要求的伪代码如下

//以40转/分速度正转5周
for(int step=0;step<120;step++) //5周*24步/周=120步
    TL0=...;TH0=...;//设置定时器初值,设置进入定时器中断多少次达到预设时间
    out_display();  //调用八段数码管显示的模块,显示之后自动将步数+1
    out_motor();    //调用步进电机转动的模块,向IN1和IN2输出下一步的信号
    while(sym==0)  
        ;           //等待时钟中断

//等待S1开关按下
while(S1未按下)
    ;       //等待S1按下

参考代码

代码很长,实现的功能与题目并不完全一致,仅供参考。

;R0用于标志时间是否改变
;R1用于记录一次计时进入中断的次数
;R2R4 DISPLAYONE
;R3用于记录是否暂停
P4 EQU 0C0H
P4SW EQU 0BBH
LEDCLK EQU P4.4
LED EQU P4.5

S1 EQU P3.6     
S2 EQU P3.7     

ONE EQU 30H
TEN EQU 31H
HUNDRED EQU 32H
extra_intr EQU 33H
step_target EQU 34H
step_completed EQU 35H
motor_voltage EQU 36H

ORG 0000H
LJMP start
ORG 000BH
LJMP timer_intr
TABLE:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
ORG 0040H
start:  ;51单片机初始化
    MOV DPTR,#TABLE
	MOV SP,#40H
    MOV P4SW,#30H   ;!!设置P4SW 4,5两位为1
    SETB P1.1       ;CE1
    SETB P1.4       ;CE2
    MOV TMOD,#01H   ;工作方式寄存器TMOD 方式1
    MOV IE,#82H     ;中断允许寄存器IE
    MOV IP,#02H     ;中断优先级寄存器IP
    MOV R1,#0
    MOV ONE,#00H    ;计数值清零
    MOV TEN,#00H
    MOV HUNDRED,#00H
    MOV motor_voltage,#01111000B

init_for_status1:
	CLR P0.0        ;test
    MOV step_completed,#0
    MOV step_target,#121
    MOV extra_intr,#0
load_status1:       ;计数器初值3036
    MOV TL0,#0DCH
    MOV TH0,#0BH
    MOV TCON,#10H   ;工作方式寄存器TCON,计时器0开始工作
    CALL OUT_DISPLAY
    CALL OUT_MOTOR_FRONT

    MOV R0,#0
wait_status1:
    MOV A,R0
    JZ wait_status1

    ;检查步数是否达到要求
    INC step_completed
    MOV A,step_target
    SUBB A,step_completed
    JNZ load_status1
	
wait_s1_status1:    ;等待S1按下
    SETB P3.6
	JB P3.6,wait_s1_status1

init_for_status2:
	CLR P0.1        ;test
    MOV step_completed,#0
    MOV step_target,#240
    MOV extra_intr,#1
    MOV R1,#0

load_status2:
    MOV TL0,#0DCH
    MOV TH0,#0BH
    MOV TCON,#10H   ;工作方式寄存器TCON,计时器0开始工作
    CALL OUT_DISPLAY
    CALL OUT_MOTOR_BACK

    MOV R0,#0
wait_status2:
    MOV A,R0
    JZ wait_status2

    ;检查步数是否达到要求
    INC step_completed
    MOV A,step_target
    SUBB A,step_completed
    JNZ load_status2

wait_s1_status2:    ;等待S1按下
    SETB P3.6
	JB P3.6,wait_s1_status2

init_for_status3:
	CLR P0.2        ;test
    MOV step_completed,#0
    MOV step_target,#240
    MOV extra_intr,#3
    MOV R1,#0

load_status3:
    MOV TL0,#0DCH
    MOV TH0,#0BH
    MOV TCON,#10H   ;工作方式寄存器TCON,计时器0开始工作
    CALL OUT_DISPLAY
    CALL OUT_MOTOR_FRONT

    MOV R0,#0
	MOV R3,#0
wait_status3:       ;检查S2是否按下
    MOV P0,R3
	SETB P3.7
	JNB P3.7,timer_chagne
	
   check_timer:
    MOV A,R0
    JZ wait_status3
    JMP load_status3

timer_chagne:       ;计时器停止/计时状态切换
	MOV A,R3
	JZ timer_stop
	MOV TCON,#10H
	MOV R3,#0
	JMP check_timer
	timer_stop:
	MOV TCON,#00H
	MOV R3,#1
	JMP check_timer

timer_intr:         ;时钟中断处理程序
    INC R1
    MOV A,R1
    SUBB A,extra_intr
    JZ start_new_timer
    MOV TL0,#00H
    MOV TH0,#00H
    MOV TCON,#10H
	SETB TR0
    RETI
start_new_timer:
    MOV R0,#1
	MOV R1,#0
    RETI

OUT_DISPLAY:        ;八段数码管显示,计数值+1
    MOV A,ONE       ;在数码管显示ONE
    MOVC A,@A+DPTR
    MOV R2,A
    LCALL displayone

    MOV A,TEN       ;在数码管显示TEN
    MOVC A,@A+DPTR
    MOV R2,A
    LCALL displayone

    MOV A,HUNDRED   ;在数码管显示THUNDRED
    MOVC A,@A+DPTR
    MOV R2,A
    LCALL displayone

    ;计数值+1
	INC ONE         ;个位+1
	MOV A,ONE       ;ONE增加到10时清零
	CJNE A,#0AH,END_DISPLAY;比较不相等转移指令
	INC TEN         ;十位+1
	MOV ONE,#0 
    MOV A,TEN
    CJNE A,#0AH,END_DISPLAY
    INC HUNDRED     ;百位+1
    MOV TEN,#0
END_DISPLAY:
    RET

displayone:
	MOV A,R2        ;R2左移
	RL A 
	MOV R2,A
	  
	MOV R4,#8       ;循环次数
	lp:
		;取r2最低位
		MOV A,#1
		ANL A,R2

		;将r2最低位赋值给c
		CLR C
		JZ lpend
		SETB C
		lpend:
				
		;输出
		CLR LEDCLK
		MOV LED, C
		SETB LEDCLK
				
		;R2左移
		MOV A,R2
		RL A
		MOV R2,A
		
		DJNZ R4,lp  ;循环
	RET

OUT_MOTOR_FRONT:
    MOV A,motor_voltage     ;输出至两个端口
    RRC A
    MOV P1.0,C
    RRC A
    MOV P3.2,C
    MOV A,motor_voltage     ;修改motor_voltage
    RR A
    RR A
    MOV motor_voltage,A
    RET

OUT_MOTOR_BACK:
    MOV A,motor_voltage
    RLC A
    MOV P3.2,C
    RLC A
    MOV P1.0,C
    MOV A,motor_voltage
    RL A
    RL A
    MOV motor_voltage,A
    RET

避坑指南

1.试验箱数码管采用共阳极连接方式,与实验二仿真实验中数码管连接方式相反,记得修改段码表。

2.一定要设置堆栈指针SP。CPU在响应中断或者子程序调用的时候,会将16位PC指针入栈,如果不设置堆栈指针,默认为07H,可能与定义的变量冲突。

3.如果步进电机出现前后反复跳动,不朝一个方向转动的情况,可以试试每次改变IN1和IN2的时候,将CE1和CE2置0再置1,或者更换实验箱。

4.实验箱的P0口连接了LED指示灯,可以利用LED指示灯debug。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
9i7LsoN8SSEp