您的当前位置:首页正文

【全方位资料】基于51单片机的步进电机控制(阀门控制)

2023-07-09 来源:步旅网
一、课题设计的主要内容:

设想的控制系统的是流量传感器采集到流量信息,通过变换器,转化为电信号,AD转换器将模拟电信号转化为离散信号,传给单片机。单片机软件系统根据事先的设定值对采集的信息进行处理,输出离散的控制信号。DA转换器将离散的控制信号转化为模拟电量。通过模拟电量来控制阀门的动作,从而调节流量,实现流量的精确控制。

考虑到设计的难度,将系统简化为:利用按键模块代替数据采集器对AT89C52单片机进行信号输入,输入设定值,在控制系统软件的作用下,发出相应的执行命令给执行机构——步进电机。步进电机带动阀门动作,对流体流量进行控制。并利用显示电路实时显示步进电机运行的转数、转向,具有实时性的特点。

其中,硬件电路的搭接是本设计的重点,控制系统软件的设计是本课题的核心。硬件电路部包括AT89C52单片机+时钟电路+复位电路构成的最小系统,外接L297和L298组成的步进电机驱动电路,用四相八拍步进电机作为执行部件,。并用8位数码管作为显示模块。。系统软件设计部分,分别对按键设定值输入,步进电机控制、数码管显示等程序进行了设计,并且设计了PID控制程序。

二、设计流程

1

1

确定设计方案 使用PROTEL设计电路图 根据电路图编写程序流程图 使用KEIL编写程序 不成功 调试 成功 生成.HEX文件 不成功 PROTEUS仿真 成功 购买元件焊制硬件实物 完成设计 三、设计的相关介绍

1、步进电机

步进电机是一种将电脉冲转化为角位移的执行机构。通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角)。你可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时您可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到速度控制的目的。

本次设计选用28BYJ-48步进电机。

步进电机28BYJ-48型四相八拍电机,电压为DC5V—DC12V。当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态的改变完成一个循环时,转子转过一个齿距。如下图所示:

2、由L297和L298组成的步进电机驱动电路

1 2

(1) 驱动芯片L297介绍

SGS公司的L297单片步进电机控制集成电路适用于双极性两相步进电机或四相单

极性步进电机的控制,与两片H桥式驱动芯片L298组合,组成完整的步进电机固定斩波频率的PWM恒流斩波驱动器。

L297产生四相驱动信号,用以控制双极性两相步进电机或四相单极性步进电机,

可以采用半步、两相励磁、单相励磁三种工作方式控制步进电机,并且控制电机的片内PWM斩波电路允许三种工作方式的切换。

图1 L297引脚图 图2 L297的内部方框图

L297 各引脚功能说明

1脚(SYNG)——斩波器输出端。如多个297同步控制,所有的SYNC端都要连在一起,共用一套振荡元件。如果使用外部时钟源,则时钟信号接到此引脚上。 2脚(GND)——接地端。

3脚(HOME)——集电极开路输出端。当L297在初始状态(ABCD=0101)时,此端有指示。当此引脚有效时,晶体管开路。 4脚(A)——A相驱动信号。

5脚(INH1)——控制A相和B相的驱动极。当此引脚为低电平时,A相、B相驱动控制被禁止;当线圈级断电时,双极性桥用这个信号使负载电源快速衰减。若CONTROL端输入是低电平时,用斩波器调节负载电流。 6脚(B)——B相驱动信号。 7脚(C)——C相驱动信号。

8脚(INH2)——控制C相和D相的驱动级。作用同INH1相同。 9脚(D)——D相驱动信号。

10脚(ENABLE)——L297的使能输入端。当它为低电平时,INH1,INH2,A,B,C,D都为低电平。当系统被复位时用来阻止电机驱动。

1

3

11脚(CONTROL)——斩波器功能控制端。低电平时使INH1和INH2起作用,高电平时使A, B,C,D起作用。

12脚(Vcc)——+5V电源输入端。

13脚(SENS2)——C相、D相绕组电流检测电压反馈输入端。 14脚(SENS1)——A相、B相绕组电流检测电压反馈输入端。

15脚(Vref )——斩波器基准电压输入端。加到此引脚的电压决定绕组电流的峰值。 16脚(OSC)——斩波器频率输入端。

17脚(CW/CCW)—方向控制端。步进电机实际旋转方向由绕组的连接方法决定。当改变此引脚的电平状态时,步进电机反向旋转。

18脚(CLOCK)——步进时钟输入端。该引脚输入负脉冲时步进电机向前步进一个增量,该步进是在信号的上升沿产生。 19脚(HALF/FULL)——半步、全步方式选择端。此引脚输入高电平时为半步方式(四相八拍), 低电平时为全步方式。如选择全步方式时变换器在奇数状态,会得到单相工作方式(单四拍)。 20脚(RESET)——复位输入端。此引脚输入负脉冲时,变换器恢复初始状态(ABCD=0101)。 中。

变换器是一个重要组成部分。变换器由一个三倍计算器加某些组合逻辑电路组成,产生一个基本的八格雷码(顺序如图3所示)。由变换器产生4个输出信号送给后面的输出逻辑部分,输出逻辑提供禁止和斩波器功能所需的相序。为了获得电动机良好的速度和转矩特性,相序信号是通过2个PWM 斩波器控制电动波器包含有一个比较器、一个触发器和一个外部检测电阻,如图4所示,晶片内部的通用振荡器提供斩波频率脉冲。每个斩波器的触发器由振荡器的脉冲调节,当负载电流提高时检测电阻上的电压相对提高,当电压达到Uref时

(Uref是根据峰值负载电流而定的),将触发器重置,切断输出,直至第二个振荡脉冲到来、此线路的输出(即触发器Q输出)是一恒定速率的PWM信号,L297的CONTROL端的输入决定斩波器对相位线A,B,C,D或抑制线INH1和INH2起作用。CONTROL为高电平时,对A,B,C,D有抑制作用;为低电平时,则对抑制线INH1和INH2有抑制作用,从而可对电动机和转矩进行控制。

图3 四相八拍模式波形图

图4 单四拍模式波形

1 4

图5 双四拍模式波形图

(2) 驱动芯片L298简介:

L298N 为双全桥步进电机专用驱动芯片,内部包含4信道逻辑驱动电路,是一种二相和四相步进电机的专用驱动器,可同时驱动2 个二相或1个四相步进电机,内含二个H-Bridge 的高电压、大电流双全桥式驱动器,接收标准TTL逻辑准位信号,可驱动46V、2A以下的步进电机,且可以直接透过电源来调节输出电压;此芯片可直接由单片机的IO 端口来提供模拟时序信号,但在本驱动电路中用L297 来提供时序信号,节省了单片机IO 端口的使用。

散热片与各管脚相连

图1 L298N引脚图

L298N引脚功能表 引脚 1 15 2 3 4 1

符号 SENSING A SENSING B OUT 1 OUT 2 Vs 功能 此两端与地连接电流检测电阻,并向驱动芯片反馈检测到的信号 此两脚是全桥式驱动器A的两个输出端,用来连接负载 电机驱动电源输入端 5

5 7 6 11 8 9 10 12 13 14

IN 1 IN2 ENABLE A ENABLE B GND Vss IN 3 IN 4 OUT 3 OUT 4 输入标准的TTL逻辑电平信号,用来控制全桥式驱动器A的开关 使能控制端.输入标准TTL逻辑电平信号;低电平时全桥式驱动器禁止工作。 接地端,芯片本身的散热片与8脚相通 逻辑控制部分的电源输人端口 输入标准的TTL逻辑电平信号,用来控制全桥式驱动器B的开关 此两脚是全桥式驱动器B的两个输出端,用来连接负载 3、PID控制算法介绍

将偏差的比例(P)、积分(I)和微分(D)通过线性组合构成控制量,用这一控制量

对被控对象进行控制,这样的控制器称PID控制器。

PID控制器是控制系统中技术比较成熟,而且应用最广泛的一种控制器。 PID控制器最先出现在模拟控制系统中,传统的模拟PID控制器是通过硬件(电子元件、气动和液压元件)来实现它的功能。随着计算机的出现,把它移植到计算机控制系统中来,将原来的硬件实现的功能用软件来代替,因此称作数字PID控制器,所形成的一整套算法则称为数字PID算法。数字PID控制器与模拟PID控制器相比,具有非常强的灵活性,可以根据试验和经验在线调整参数,因此可以得到很好的控制性能。

PID控制中的积分作用可以减少稳态误差, 但另一方面也容易导致积分饱和, 使系统的超调量增大。

微分作用可提高系统的响应速度, 但其对高频干扰特别敏感, 甚至会导致系统失稳。 所以, 正确计算控制器的参数, 有效合理地实现 PID控制器的设计,对于PID 控制器在过程控制中的广泛应用具有重要的理论和现实意义。

在PID控制系统中, PID控制器分别对误差信号e(t)进行比例、积分与微分运算, 其

结果的加权和构成系统的控制信号u(t),送给对象模型加以控制。 PID控制器

的数学描述为

其传递函数可表示为:

从根本上讲, 设计PID控制器也就是确定其比例系数Kp、积分系数T i 和微分系数T d , 这三个系数取值的不同, 决定了比例、积分和微分作用的强弱。

1

6

4、AT89C52芯片介绍

AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的AT89C52单片机可为您提供许多较复杂系统控制应用场合。

AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。

· 兼容MCS51指令系统

· 8k可反复擦写(>1000次)Flash ROM · 32个双向I/O口 · 256x8bit内部RAM

· 3个16位可编程定时/计数器中断 · 时钟频率0-24MHz · 2个串行中断 · 可编程UART串行通道 · 2个外部中断源 · 共6个中断源 · 2个读写中断口线 · 3级加密位

· 低功耗空闲和掉电模式 · 软件设置睡眠和唤醒功能

AT89C52引脚图

AT89C52主要管脚有:XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚。

P0 口

P0 口是一组8 位漏极开路型双向I/O 口, 也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8 个TTL逻辑门电路,对端口P0 写“1”时,可作为高阻抗输入端用。

在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8 位)和数据总线复用,在访问期间激活内部上拉电阻。

在Flash 编程时,P0 口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。

P1 口

1 7

P1 是一个带内部上拉电阻的8 位双向I/O 口, P1 的输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。

P2 口

P2 是一个带有内部上拉电阻的8 位双向I/O 口,P2 的输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑门电路。对端口P2 写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。

在访问外部程序存储器或16 位地址的外部数据存储器(例如执行MOVX @DPTR 指令)时,P2 口送出高8 位地址数据。在访问8 位地址的外部数据存储器(如执行MOVX @RI 指令)时,P2 口输出P2 锁存器的内容。 Flash 编程或校验时,P2亦接收高位地址和一些控制信号。

P3 口

P3 口是一组带有内部上拉电阻的8 位双向I/O 口。P3 口输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻

辑门电路。对P3 口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3 口将用上拉电阻输出电流(IIL)。

P3 口除了作为一般的I/O 口线外,更重要的用途是它的第二功能 P3 口还接收一些用于Flash 闪速存储器编程和程序校验的控制信号。

RST

复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位

ALE/PROG

当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8 位字节。一般情况下,ALE 仍以时钟振荡频率的1/6 输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE 脉冲。对Flash 存储器编程期间,该引脚还用于输入编程脉冲(PROG)。如有必要,可通过对特殊功能寄存器(SFR)区中的8EH 单元的D0 位置位,可禁止ALE 操作。该位置位后,只有一条MOVX 和MOVC指令才能将ALE 激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE 禁止位无效。

PSEN

程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C52 由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN 有效,即输出两个脉冲。在此期间,当访问外部数据存储器,将跳过两次PSEN信号。

1

8

EA/VPP

外部访问允许。欲使CPU 仅访问外部程序存储器(地址为0000H—FFFFH),EA 端必须保持低电平(接地)。需注意的是:如果加密位LB1 被编程,复位时内部会锁存EA端状态。如EA端为高电平(接Vcc端),CPU 则执行内部程序存储器中的指令。Flash 存储器编程时,该引脚加上+12V 的编程允许电源Vpp,当然这必须是该器件是使用12V 编程电压Vpp。

XTAL1

振荡器反相放大器的及内部时钟发生器的输入端。

XTAL2

振荡器反相放大器的输出端。

5、芯片74HC573简要介绍

74HC573为八进制 3态非反转透明锁存器。当锁存使能端为高时,这些器件的锁存对于数据是透明的(也就是说输出同步)。当锁存使能变低时,符合建立时间和保持时间的数据会被锁存。

图 74HC573管脚图

四、数码管显示电路

两片74HC573与数码管的连接图

1

9

四位共阳极数码管管脚

五、总结及体会

步进机在工业控制中是常用的嵌入式运动控制设备之一,本系统采用单片机搭配驱动

芯片L297、L298实现对步进电机的控制。电机的转动方向、转数可以通过键盘输入, 运用程序对这些数据进行处理, 由单片机发出相应的控制信号给步进电机, 增加了控制的灵活性。运用中断方式, 使系统在运行时可随时改变步进电机的运作方式。经实验验证, 达到了预期的设计目的。

完成这个阀门控制的系统设计,期间会遇到各种各样的问题。在设计电路图和程序设计,及焊接电路过程都要求对芯片有一定的熟练程度。通过查阅材料,询问他人等等都是很好的解决方法。通过这次单片机的步进电机控制电机设计中,学习到了如何用单片机

来实现控制,也见证了一堆器件从零到整的制作过程。我们于网上大量搜索与下载资料,从设计方案、设计内容、设计思路,从基础的硬件设计到软件编程,从一个个单独模块制作到整个完整作品,此次设计还有很多可以完善的地方,比如在89C52单片机与步进电机驱动电路之间,应该接上光电耦合电路进行隔离,消减电磁干扰,保证单片机运行稳定正确运行。

如果要设计更完善功能更强大的系统的话,我仍需要各方面的学习与探讨,不过可以肯定的是我们通过这次单片机控制步进电机的系统设计,积累了一定的经验,可以为以后设计打下坚实的基础。

1

10

附1:电路设计图

1

11

附2:实物图

1

12

附3:软件设计

#include

#define DataPort P2 //定义数据端口 程序中遇到DataPort 则用P2 替换 sbit LATCH1=P3^0;//定义锁存使能端口 段锁存 sbit LATCH2=P3^1;// 位锁存

//******************************************************************************

sbit queren=P3^2; sbit setzy=P3^3; sbit setsx=P3^4;

unsigned char code s10[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; unsigned char code P28[6]={0x1,0x2,0x4,0x10,0x20,0x40}; unsigned char w6[6]; unsigned char key2[3];

unsigned char i,f,j,s,key1,a,key4; unsigned char t,ok;

//******************************************************************************

sbit CW=P1^0; sbit CLK=P1^1; sbit ENABLE=P1^2; unsigned char n1,m,f48; int n;

//******************************************************************************

int ek0,ek1,ek2,puk,uk,n,rk,rk1,yk,yk1;

//*********************************************** //显示初始化

void initxianshisetflux(){ TMOD=0x11; //设定时器 w6[0]=0; w6[1]=0; w6[2]=1; w6[3]=0; w6[4]=1; w6[5]=0; j=0; f=0; s=0; key1=0; t=0; a=0; EA=1;

1

13

ET0=1; TH0=0xF6; TL0=0xF8; TR0=1; ok=1; }

//*********************************************** //PID初始化 void initpid(){ yk=10; rk=100; uk=4; ek0=0; ek1=0; ek2=0; }

//*********************************************** //执行步进电机 void initzxbj(){ CW=1; CLK=1; ET1=1; TH1=0xFB; TL1=0x7C; }

//*********************************************** //显示

void delayus(unsigned int i) { unsigned int j; while(i--){ for(j=0;j<39;j++) {;} } }

void xianshi() { if(s>=3){ s=0; } if(f>=6){ f=0; }

1

14

if(j>=6){ j=0; } DataPort=0xff; //清空数据,防止有交替重影 LATCH1=1; //段锁存 LATCH1=0; DataPort=P28[f++]; LATCH2=1; //位锁存 LATCH2=0; DataPort=s10[w6[j++]]; LATCH1=1; //段锁存 LATCH1=0; s++; delayus(6); }

//*********************************************** //设置流量 void zhuoyou() { setzy=1; if(setzy==0){ key4=t; w6[key4]=key2[key4]; t++; if(t>2){ t=0; } } while(setzy!=1){ setzy=1; xianshi(); } }

void shangxia() { setsx=1; if(setsx==0){ (key2[t])++; if(t==2){

1

15

if(key2[1]>=5){ if(key2[t]>1){ key2[t]=0; } } else{

if(key2[t]>2){ key2[t]=0; } } }

if(key2[2]==2){ if(t==1){

if(key2[0]>=5){ if(key2[t]>4){ key2[t]=0; } } else{

if(key2[t]>5){ key2[t]=0; } } }

if(t==0){

if(key2[1]==5){ if(key2[t]>5){ key2[t]=0; } } else{

if(key2[t]>9){ key2[t]=0; } } } } else{

if(key2[t]>9){ key2[t]=0; } }

}

1

16

while(setsx!=1){ setsx=1; xianshi(); } }

void shaomiaoqueren() { unsigned char i; key1=~key1; if(key1){ for(i=0;i<3;i++){ key2[i]=w6[i]; } } else{ for(i=0;i<3;i++){ w6[i]=key2[i]; } t=0; } while(queren==0){ queren=1; xianshi(); } }

void ifqueren() { P3=0xff; if(queren==0){ shaomiaoqueren(); } }

void setflux(){ do{

xianshi(); P3=0xff; ifqueren(); P3=0xff; if(key1){ shangxia(); P3=0xff; zhuoyou();

1

17

P3=0xff;

rk=100*w6[2]+10*w6[1]+w6[0]; } }

while(key1); }

//*********************************************** //执行步进电机

void delay(unsigned int t)

{ unsigned int k; while(t--) {

for(k=0; k<100; k++); } }

void csp0(){ //设定时器 delay(1); ET1=1; TH1=0xFB; TL1=0x7C; TR1=1;

while(n1>0){ xianshi(); }

f48=1;

while(n>0){ xianshi(); }

TR1=0; }

void zxbj()

{ if(ek0>5||ek0<-5){ ENABLE=1; f48=0; if(n<0){ CW=1; n=-n;

for(m=0;m<5;m++); } else{ CW=0;

for(m=0;m<5;m++); }

1

18

delay(1); csp0();

ENABLE=0; ok=1; } }

//********************************************** //PID算法计算 void Pid() {

rk=100*w6[2]+10*w6[1]+w6[0]; yk=uk*255/100; w6[3]=yk%10;

w6[4]=(yk%100)/10; w6[5]=yk/100; ek0=rk-yk;

if(ek0>5||ek0<-5){ if(ek0>20||ek0<-20){ ek1=0; ek2=0; puk=ek0/2; }

else if(ek0>10||ek0<-10){ ek2=0;

puk=ek0/2-ek1/2; ek1=ek0; } else{ ek2=ek1; ek1=ek0;

puk=ek0/2-ek1/2+ek2/5; }

uk=puk+uk; if(uk>100){

puk=100+puk-uk; uk=100; }

else if(uk<0){ puk=puk-uk; uk=0; }

n=8192/100*puk; }

1

19

else{ n=0;

ENABLE=0; f48=0; ek0=0; ek1=0; ek2=0; } }

//*********************************************** void main() { initxianshisetflux(); initpid(); initzxbj(); while(1){ xianshi(); rk=100*w6[2]+10*w6[1]+w6[0]; setflux(); Pid(); zxbj(); while(ok){ xianshi(); setflux(); ENABLE=0; } } }

//************************************************* //定时器0

void timer0() interrupt 1 using 0 { TH0=0xF6; TL0=0xF8; i++; if(i>=200){ if(key1){ switch(a){ case 0:w6[t]=10;a=1;break; case 1:w6[t]=key2[t];a=0;break; } } if(ENABLE==0){

1

20

ok=0; yk=uk*255/100; yk1=yk; w6[3]=yk%10; w6[4]=(yk%100)/10; w6[5]=yk/100; } i=0; } }

//************************************************* //定时器1

void timer1(void) interrupt 3 { if(f48){ TH1=0xFB; TL1=0x7C; n--; } else{

TH1=0xF6; TL1=0xf8; n1--; /*脉冲数*/ } CLK=!CLK;

for(m=0;m<100;m++) { ; }

CLK=!CLK; }

//*************************************************

1

21

1 22

因篇幅问题不能全部显示,请点此查看更多更全内容