重庆邮电大学综合实验报告——单片机控制步进电机调速学生姓名:组长:AAAA组员:AAAAAAAA学号:XXXXXXXXXXXXXXXXXX所在学院:自动化班级:XXXXX专业:机械设计制造及其自动化指导老师:XXXX成绩评定:检测与控制实验中心目录一、实验要求与目的 (3)1、设计要求 (3)2、实验目的 (3)二、设计思路 (3)三、实验原理 (4)1、步进电机 (4)2、步进电机控制系统结构 (4)3、速度控制算法 (5)四、功能概述及方案设计 (5)1、显示模块 (5)2、AD转换模块 (6)3、步进电机细分驱动模块 (6)五、实验运行程序 (7)六、实验心得 (13)参考文献 (13)一、实验要求与目的1、设计要求1、步进电机的给定速度由电位器通过AD转换输入2、只有给定速度和实际速度显示功能3、实际速度通过红外光电开关(或霍尔元件)检查4、步进电机具有细分功能:1/2细分 1/4细分 1/8细分5、测试步进电机的响应时间及曲线2、实验目的1、熟悉步进电机的工作原理2、熟悉51系列单片机的工作原理及调试方法3、设计基于51系列单片机控制的步进电机调速原理图4、实现51系列单片机对步进电机的速度控制5、了解霍尔元件和步进电机细分驱动芯片tb6560的使用二、设计思路主控芯片采用STC89C52单片机,显示采用1602液晶,由于步进电机速度设定由电位器输入,使用外部AD tlc5510,AD时钟源接89C52 ALE引脚,AD为并行,AD使用单片机P1口,可以直接读取,根据对应数据设定速度。
步进电机速度控制采用闭环控制,由于传统的PID控制算法波动较大,我们采用分级设定加速度的办法,并把编码器反馈回来的速度与设定速度进行比较确定是加速还是减速,软件模拟加速减速过程,步进电机细分由驱动芯片TB6560提供,由于驱动细分由m1、m2口电平决定,我们采取直接通过拨码开关设定电平,从而设定驱动细分值。
三、实验原理1、步进电机步进电机是数字控制电机,它将脉冲信号转变成角位移,即给一个脉冲信号,步进电机就转动一个角度,因此非常适合于单片机控制。
步进电机可分为反应式步进电机(简称VR)、永磁式步进电机(简称PM)和混合式步进电机。
步进电机区别于其他控制电机的最大特点是,它是通过输入脉冲信号来进行控制的,即电机的总转动角度由输入脉冲数决定,而电机的转速由脉冲信号频率决定。
步进电机的驱动电路根据控制信号工作,控制信号由单片机产生。
其基本原理作用如下:(1)控制换相顺序通电换相这一过程称为脉冲分配。
例如:三相步进电机的三拍工作方式,其各相通电顺序为A-B-C-D,通电控制脉冲必须严格按照这一顺序分别控制A,B,C,D相的通断。
(2)控制步进电机的转向如果给定工作方式正序换相通电,步进电机正转,如果按反序通电换相,则电机就反转。
(3)控制步进电机的速度如果给步进电机发一个控制脉冲,它就转一步,再发一个脉冲,它会再转一步。
两个脉冲的间隔越短,步进电机就转得越快。
调整单片机发出的脉冲频率,就可以对步进电机进行调速。
2、步进电机控制系统结构单片机在适当的时刻通过对计数器0赋初值,设置好加减速过程的频率变化(即速度、加速度变化),以防止失步。
例如,在点位控制中设置好速度曲线图,在起动和升速时,使步进电机产生足够的转矩驱动负载,跟上规定的速度和加速度;在减速时,下降特性使负载不产生过冲,停止在规定的位置。
启动细分驱动电路中的固化程序以产生一定频率的脉冲,经功率放大后驱动步进电机运动。
步进电机运动方向的改变及启动和停止均由计算机控制硬件控制电路实现。
图2 步进电机控制系统3、速度控制算法单片机控制系统通过A/D电路检测设定速度值,通过编码器得到实际速度值,当实际速度值大于设定速度值,步进电机加速,反之减速。
根据实际速度真与设定速度值的差值大小的不同,将加速度分为三个等级,相差越大,加速度越大。
从而达到既能快速达到设定速度值,又能让实际速度稳定在设定速度值左右的目的。
四、功能概述及方案设计1、显示模块显示模块采用1602液晶显示测量参数和显示所有测量数据。
程序逻辑功率驱动器步进电机编码器电源输入脉冲细分指令2、AD转换模块3、步进电机细分驱动模块TB6560步进电机驱动电路主要包括3部分电路:控制信号隔离电路、主电路和自动半流电路,可利用简单的编程实现。
五、实验运行程序/******************************************************Display.c文件******************************************************/#include <reg52.h>#include <intrins.h>#define Data P0 //数据端口#define LENGTH 7typedef unsigned char uchar;typedef unsigned int uint;code char num[] = "0123456789";char setSd[LENGTH] = "SetSpd:";char nowSd[LENGTH] = "NowSpd:";char r_min[5] = "r/min";//---------液晶显示接口------------sbit RS = P2^4;sbit RW = P2^5;sbit E = P2^6;void DelayMs(uchar ms);void DelayUs(uchar us);void InitLcd(void);void WriteData(uchar c);void WriteCommand(uchar c);void DisPlay(uint number, uchar status);void DisplayStr(char *s,uchar length);/****************************************************************** 数据显示******************************************************************/ void DisPlay(uint number, uchar status){char i;static char pre_i = 0;char temp[8] = {0};if(status == 0){WriteCommand(0x80);DisplayStr(setSd,LENGTH);}else{WriteCommand(0xc0);DisplayStr(nowSd,LENGTH);}if(number == 0){WriteData(num[temp[0]]);}else{i = 0;while(number){temp[i] = number%10;number /= 10;i++;}if(pre_i > i){WriteCommand(0x01); //显示清屏}pre_i = i;while(i > 0){i--;WriteData(num[temp[i]]);}}DisplayStr(r_min,5);}/*******************************************字符串显示函数********************************************/void DisplayStr(char *s,uchar length){uchar j = 0;while(j < length){WriteData(s[j]);j++;}}/****************************************************************** 写入命令函数******************************************************************/ void WriteCommand(uchar c){DelayMs(5);//操作前短暂延时,保证信号稳定E=0;RS=0;RW=0;_nop_();E=1;Data=c;E=0;}/******************************************************************写入数据函数******************************************************************/ void WriteData(uchar c){DelayMs(5); //操作前短暂延时,保证信号稳定E=0;RS=1;RW=0;_nop_();E=1;Data=c;E=0;RS=0;}/****************************************************************** 初始化函数******************************************************************/ void InitLcd(void){DelayMs(15);WriteCommand(0x38); //display modeWriteCommand(0x38); //display modeWriteCommand(0x38); //display modeWriteCommand(0x06); //显示光标移动位置WriteCommand(0x0c); //显示开及光标设置WriteCommand(0x01); //显示清屏}/****************************************************************** 微妙级函数12MHz频率******************************************************************/ void DelayUs(uchar us){uchar uscnt;uscnt = us>>1;while(--uscnt);}/****************************************************************** 毫秒延时函数******************************************************************/ void DelayMs(uchar ms){while(--ms){DelayUs(250);DelayUs(250);DelayUs(250);DelayUs(250);}}/******************************************************Init.c文件******************************************************/#include <reg52.h>typedef unsigned char uchar;typedef unsigned int uint;sbit CW = P2^1;sbit ENABLE = P2^2;extern void InitLcd(void);/************************************************ TB6560初始化*************************************************/ void InitTB6560(void){CW = 0;ENABLE = 1;}/************************************************定时器0初始化函数功能:周期定时50ms*************************************************/ void InitTime0(void){TMOD |= 0x01;EA = 1;ET0 = 1;TH0 = (65536-50000)/256;TL0 = (65536-50000)%256;TR0 = 1;}/************************************************定时器1初始化函数功能:设定为外部脉冲计数模式*************************************************/ void InitTime1(void){TMOD |= 0x50;EA = 1;ET1 = 0;TH1 = 0;TL1 = 0;TR1 = 1;}/************************************************定时器1初始化函数功能:设定为外部脉冲计数模式*************************************************/ void InitTime2(void){RCAP2H = (65536-50000)/256; //重装载计数器赋初值RCAP2L = (65536-50000)%256;ET2 = 1; //开定时器2中断EA = 1; //开总中断TR2 = 1; //开启定时器,并设置为自动重装载模式}/************************************************总初始化函数*************************************************/void InitSystem(void){InitLcd();InitTB6560();InitTime0();InitTime1();InitTime2();}/****************************************************** StepMotor.c文件******************************************************/#include <reg52.h>#include <math.h>#include "StepMotor.h"void main(void){int K;InitSystem();while(1){if(statusFlag == 0){preSetSpeed = setSpeed;setSpeed = SET_SPEED;if(setSpeed > nowSpeed){if(setSpeed - nowSpeed > 10)K = 10;else if(setSpeed - nowSpeed > 5)K = 20;else K = 60;if(adjustment < 1)adjustment = 1;adjustment = adjustment - adjustment/K;}else if(setSpeed < nowSpeed){if(setSpeed - nowSpeed > 10)K = 10;else if(setSpeed - nowSpeed > 5)K = 20;else K = 60;if(adjustment > 30000)adjustment = 30000;adjustment = adjustment + adjustment/K;}DisPlay(setSpeed,0);DisPlay(nowSpeed,1);statusFlag = 1;}}}/************************************************定时器2中断函数功能:周期定时50ms*************************************************/void Tsr_Time2(void) interrupt 5{static volatile uchar inTimes = 0;TR1 = 0;if(inTimes < 20){inTimes++;}else{nowSpeed = TH1*256 + TL1;statusFlag = 0;inTimes = 0;TH1 = 0;TL1 = 0;}TF2 = 0; //定时器2的中断标志要软件清0TR1 = 1;}/************************************************定时器0中断函数功能:周期定时50ms*************************************************/void Tsr_Time0(void) interrupt 1{CLK = ~CLK;TH0 = (65536 - adjustment)/256; //2600一转每秒TL0 = (65536 - adjustment)%256;}/****************************************************** StepMotor.h*******************************************************/ /********************************clk p2.0 步进电机转速c/cw P2.1 正反转Enable P2.2 驱动使能singal P3.5 编码器信号反馈*********************************/#define SET_SPEED P1typedef unsigned char uchar;typedef unsigned int uint;sbit CLK = P2^0;sbit CW = P2^1;sbit ENABLE = P2^2;//--------------函数声明--------------extern void InitSystem(void);extern void WriteData(uchar c);extern void WriteCommand(uchar c);extern void DisPlay(uint number, uchar status);//------------变量定义-------------int setSpeed; //速度设定int preSetSpeed;uchar count = 0;volatile int nowSpeed; //当前速度int staticAdjustment = 0;volatile int adjustment = 30000; //周期调整volatile uchar statusFlag = 0;六、实验心得经过这次的实验,我们受益匪浅,熟悉掌握了步进电机的工作原理,对51系列单片机的工作原理及调试方法也有了更进一步的了解,对霍尔元件和步进电机细分驱动芯片tb6560的使用也有了一定的了解,经过这次实验,锻炼了我们对知识的综合能力,在动手能力方面也有了进一步的提高。