基于51单片机的闭环控制 附带源程序.docx
《基于51单片机的闭环控制 附带源程序.docx》由会员分享,可在线阅读,更多相关《基于51单片机的闭环控制 附带源程序.docx(18页珍藏版)》请在冰豆网上搜索。
基于51单片机的闭环控制附带源程序
《电气技术》
研究生课程设计报告
题目基于51单片机的直流电机PID调速系统
学院机械与汽车工程学院
专业班级车辆工程
学号2023
学生姓名木飞
指导教师
完成日期2017年01月12日
1引言
研究对象介绍
选题的目的和意义
直流电动机具有良好的起动、制动性能,宜于在大范围内平滑调速,在许多需要调速或快速正反向的电力拖动领域中得到了广泛的应用。
从控制的角度来看,直流调速还是交流拖动系统的基础。
早期直流电动机的控制均以模拟电路为基础,采用运算放大器、非线性集成电路以及少量的数字电路组成,控制系统的硬件部分非常复杂,功能单一,而且系统非常不灵活、调试困难,阻碍了直流电动机控制技术的发展和应用范围的推广。
2设计原理、方法及概述
设计原理及方法
直流电动机根据励磁方式不同,直流电动机分为自励和他励两种类型。
不同励磁方式的直流电动机机械特性曲线有所不同。
但是对于直流电动机的转速有以下公式:
n=U/Cc-TR内/CrCc其中:
U—电压;R内—励磁绕组本身的电阻;—每极磁通(Wb);Cc—电势常数;Cr—转矩常量。
由上式可知,直流电机的速度控制既可采用电枢控制法,改变电枢回路电阻,也可采用磁场控制法。
对于要求在一定范围内无级平滑调速系统来说,以调节电枢供电电压的方式为最好。
改变电阻只能是有级调速;减弱磁通虽然能够平滑调速,但是调速范围不大,往往只是配合调压方案,在基速(额定转速)以上做小范围的减弱升速。
因此,自动控制的直流调速往往以变压调速为主。
本文主要研究了利用MCS-51系列单片机,通过PWM方式控制直流电机调速的方法。
PWM控制技术以其控制简单、灵活和动态响应好的优点而成为电力电子技术最广泛应用的控制方式,也是人们研究的热点。
由于当今科学技术的发展已经没有了学科之间的界限,结合现代控制理论思想或实现无谐振软开关技术将会成为PWM控制技术发展的主要方向之一。
设计总概述
以直流电机电枢上电压的占空比来改变平均电压的大小,从而控制电动机的转速为依据,实现对直流电动机的平滑调速,并通过单片机控制速度的变化。
本文所研究的直流电机调速系统主要是由硬件和软件两大部分组成。
硬件部分是前提,是整个系统执行的基础,它主要为软件提供程序运行的平台。
而软件部分,是对硬件端口所体现的信号,加以采集、分析、处理,最终实现控制器所要实现的各项功能,达到控制器自动对电机速度的有效控制。
但是此设计中电机只需要正转,所以相对来说简单点。
3硬件设计
8051单片机简介
AT89C52是一个低电压,高性能CMOS8位单片机,片内含8kbytes的可反复擦写的Flash只读程序存储器和256bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,AT89C52单片机在电子行业中有着广泛的应用。
AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,AT89C52可以按照常规方法进行编程,也可以在线编程。
其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。
部分功能如下:
(1)8kB可反复擦写(大于1000次)FlashROM;
(2)32个双向I/O口;
(3)256x8bit内部RAM;
(4)3个16位可编程定时/计数器中断;
(5)时钟频率0-24MHz;
(6)2个串行中断,可编程UART串行通道;
(7)2个外部中断源,共8个中断源;
(8)2个读写中断口线,3级加密位;
直流电机
设计中采用直流电机,自带高精度的磁编码器,性能介绍如图一所示,
接线说明如图二所示:
性能介绍图一
接线图二
L298N
恒压恒流桥式2A驱动芯片L298N,简称H桥。
L298是SGS公司的产品,比较常见的是15脚Multiwatt封装的L298N,内部同样包含4通道逻辑驱动电路。
可以方便的驱动两个直流电机,或一个两相步进电机。
L298N芯片可以驱动两个二相电机,也可以驱动一个四相电机,输出电压最高可达50V,可以直接通过电源来调节输出电压;可以直接用单片机的IO口提供信号;而且电路简单,使用比较方便。
L298N可接受标准TTL逻辑电平信号VSS,VSS可接4.5~7V电压。
4脚VS接电源电压,VS电压范围VIH为+2.5~46V。
输出电流可达2.5A,可驱动电感性负载。
1脚和15脚下管的发射极分别单独引出以便接入电流采样电阻,形成电流传感信号。
L298可驱动2个电动机,OUT1,OUT2和OUT3,OUT4之间可分别接电动机,本实验装置我们选用驱动一台电动机。
5,7,10,12脚接输入控制电平,控制电机的正反转。
EnA,EnB接控制使能端,控制电机的停转。
L298芯片驱动电路图如下:
图1L298芯片驱动电路图
系统总体电路
图中控制器模块为系统的核心部件,电位器和显示器是用来实现人机交换功能,其中通过键盘将需要设置的参数和状态输入到单片机中,并且通过控制器显示到显示器上。
在运行过程中控制器产生PWM脉冲送到电机驱动电路中,经过放大后控制直流电机转速,同时利用速度检测模块将当前转速反馈到控制器中,控制器经过数字PID运算后改变PWM脉冲的占空比,实现电机转速实时控制的目的。
PWM脉冲
图1系统方案框图
4软件设计
PID算法
PI调节器是电力拖动自动控制中最常用的的一种,在微机数字控制系统中,当采样频率足够高时,可以先按模拟系统的设计方法设计,然后再离散化,得到数字控制器的算法。
PI调节器的传递函数如式所示:
()
若输入误差函数为e(t),输出函数为u(t),则e(t)和u(t)的关系时域表达式可写成:
()
式子中
为比例系数,
为比例系数。
将式转化为差分方程,得到数字PI调节器的表达式,其第k拍输出为:
()
式中
为采样周期。
增量式算法只需要当前的和上一拍的偏差即可计算出输出值。
增量式PI调节器算法为:
()
在控制系统中,常需要对调节器的输出实施限幅。
在数字控制算法中,要对u限幅,只需要在程序中设置限幅值。
不考虑限幅时,位置式和增量式两种算法完全等同,考虑限幅时,则两者略有差异。
增量式PI调节器算法只需要输出限幅,而位置式算法必须同时设置积分限幅和输出限幅。
若没有积分限幅,积分项可能很大,将产生较大的退饱和超调。
算法模块如下:
inte=0,e1=0,e2=0;
floatuk=0,uk1=,duk=;//PID输出值
floatkp=5,ki=,kd=;//PID控制系数
上面是初始化部分
voidPIDControl()//PID偏差计算
{
e=temp-num;//变量temp是AD采集过来的值,num是通过M法测出点值
duk=(kp*(e-e1)+ki*e+kd*(e-2e1+e2))
uk=uk1+duk;
out=(int)uk;
if(out>250)
{
out=100;
}
elseif(out<0)
{
out=0;
}
uk1=uk;
e2=e1;
e1=e;
value=out;//value最后送给PWM。
}
这部分是子程序
M法测速
在一定时间Tc内测取旋转编码器输出脉冲个数M1,用以计算这段时间内的转速,称作M法测速。
把M1除以Tc就可以得到旋转编码器输出脉冲的频率f1=M1/Tc,所以又称频率法。
电机每转一圈共产生Z个脉冲(Z=倍频系数*编码器光栅数),把f1除以Z就得到在单位时间内电机的转速。
在习惯上,时间Tc以s为单位,而转速是以r/min为单位,则电动机的转速为:
n=60M1/ZTc()
由于Z和Tc都是常数,因此转速n与计数值M1成正比,故此测速方法称M法测速。
具体程序部分用外部中断计数和定时器来完成,程序如下:
voidexter0()interrupt0//外部中断脉冲计数
{//M法测速度(外部中断0和定时器0用在M法测速上)
Inlpuse++;
}
voidtimer0()interrupt1
{
TH0=0x3c;//重装初值
TL0=0xb0;
time++;
if(time>=20)//1s钟读取一次转速(2*60ms)
{EX0=0;
TR0=0;
num=Inlpuse;//计算转速
Inlpuse=0;
PIDControl();//100ms控制一次
Inlpuse=0;
EX0=1;
TR0=1;
}
}
参数设定
在程序中修改PID调节算法中的比例系列、积分系数和微分系数可以得到不同特性的转速曲线。
参数改变,转速响应的超调量和调整时间发生变化。
系统的稳定性和快速性是一对矛盾,因此我们必须选择一个合适的PI参数。
在调试过程中,当令kp=5、ki=、kd=时系统的快速性和稳定性达到最佳状态。
电位器的AD采集模块
AD采集模块利用是我是直接调用了开发板里面的程序,这个模块可以也可以自己制作。
我用的XPT2046是一款4线制电阻式触摸屏控制器,内含12位分辨率125KHz转换速率逐步逼近型A/D转换器。
此芯片支持从到的低电压I/O接口。
XPT2046能通过执行两次A/D转换查出被按屏幕位置,除此之外,还可以测量加在触摸屏上的压力。
主要特性如下:
(1)工作电压范围为到
(2)支持的数字I/O口
(3)内建参考电压
(4)内建结温测量功能
(5)触摸压力测量,具有自动省电功能
(6)采用3线制SPI通信接口
程序见最后的程序清单。
5课题总结
从课题选定开始,先是看了一遍课本以及网上找了对应的论文,然后看了老师发的试验资料以及各个元器件的原理和用法,最后把硬件焊接起来,然后想如何测测速,如何给定,如何用PID进行控制,最后如何通过PID去控制PWM的占空比。
在调试的过程中遇到一个很简单和致命的问题,就是我用的开发板和L298N开始的时候没有共接地导致调速一直失败,最后通过用示波器观测PWM输出的波形发现了问题,当真正的实现调速的时候感觉很好,终于通过自己的努力完成了一项有点技术含量的事情。
继续加油。
全部程序如下:
对于程序,每个读者的I/0口或者用的ad采集方式不一样,程序可能不同,但是解决闭环问题的核心是读取给定值用AD转换,读取测速值用外部中断和定时器中段,PWM输出也用一个定时器。
#include""
#include""
//--定义使用的IO--//
#defineGPIO_DIGP0
sbitPWM=P1^0;
inte=0,e1=0,e2=0;//PID偏
floatuk=0,uk1=,duk=;//PID输出值
floatkp=5,ki=,kd=;//PID控制系数
intout=0;
sbitIN2=P1^1;
//--定义一个全局变量--//
unsignedintvalue,timer1;
uintnum;
uintInlpuse=0,num=0;//脉冲计数单元
uinttemp,count,temp1;
unsignedinttime=0;
sbitzhongduan=P3^2;
sbitLSA=P2^2;
sbitLSB=P2^3;
sbitLSC=P2^4;
//--定义全局变量--//
unsignedcharcodeDIG_CODE[17]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
ucharDisplayData[8];//用来存放要显示的8位数的值
voidDigDisplay(void);
voidPIDControl()//PID偏差计算
{
e=temp-num;
duk=(kp*(e-e1)+ki*e+kd*(e-2e1+e2))
uk=uk1+duk;
out=(int)uk;
if(out>250)
{
out=100;
}
elseif(out<0)
{
out=0;
}
uk1=uk;
e2=e1;
e1=e;
value=out;
}
voidSetSpeed(void)
{
temp1=Read_AD_Data(0x94);//AIN0电位器(100us采集一次
temp=2*temp1>>5;//temp的变化范围在0-250之间
}
voidDigDisplay(void)
{
unsignedchari;
unsignedintj;
DisplayData[7]=DIG_CODE[num%10000/1000];
DisplayData[6]=DIG_CODE[num%1000/100];
DisplayData[5]=DIG_CODE[num%100/10];
DisplayData[4]=DIG_CODE[num%10/1];
DisplayData[3]=DIG_CODE[temp%10000/1000];
DisplayData[2]=DIG_CODE[temp%1000/100];
DisplayData[1]=DIG_CODE[temp%100/10];
DisplayData[0]=DIG_CODE[temp%10/1];
for(i=0;i<8;i++)
{
switch(i)//位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0;break;//显示第0位
case
(1):
LSA=1;LSB=0;LSC=0;break;//显示第1位
case
(2):
LSA=0;LSB=1;LSC=0;break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0;break;//显示第3位
case(4):
LSA=0;LSB=0;LSC=1;break;//显示第4位
case(5):
LSA=1;LSB=0;LSC=1;break;//显示第5位
case(6):
LSA=0;LSB=1;LSC=1;break;//显示第6位
case(7):
LSA=1;LSB=1;LSC=1;break;//显示第7位
}
GPIO_DIG=DisplayData[i];//发送段码
j=50;//扫描间隔时间设定
while(j--);
GPIO_DIG=0x00;//消隐
}
}
voidexter0()interrupt0//外部中断脉冲计数
{//M法测速度(外部中断0和定时器0用在M法测速上)
Inlpuse++;
}
voidtimer0()interrupt1
{
TH0=0x3c;//重装初值
TL0=0xb0;
time++;
if(time>=20)//1s钟读取一次转速(2*60ms)
{EX0=0;
TR0=0;
num=Inlpuse;//计算转速
Inlpuse=0;
PIDControl();//100ms控制一次
Inlpuse=0;
EX0=1;
TR0=1;
}
}
voidT1_time()interrupt3
{
count1++;
if(count1>=100)count1=0;//计时100us*100=10ms=100Hz
if(count1elsepwm=0;
}
voidSystemInit()
{
TMOD=0x21;//设定时器0为工作方式1,定时器1为工作方式2(自动重装初值)
TH0=0x3c;//设定50ms一次中断
TL0=0xb0;
TH1=0x9c;//设定100us一次中断
TL1=0x9c;
EA=1;//开总中断
ET0=1;//开定时器0中断
ET1=1;//开定时器1中断
EX0=1;//开外部中断0
IT0=1;//启动下降沿触发有效
TR1=1;//启动定时器1
TR0=1;//启动定时器0
}
voidmain()
{
SystemInit();
while
(1)
{
DigDisplay();
}
}
AD采集模块:
(这一部分程序只是AD采集模块,用的芯片是XPT2046,用spi通信方式,最后改变电位器可以改变temp的值,这部分程序读者可以自己解决,)
#ifndef__XPT2046_H_
#define__XPT2046_H_
//---包含头文件---//
#include<>
#include<>
//---重定义关键词---//
#ifndefuchar
#defineucharunsignedchar
#endif
#ifndefuint
#defineuintunsignedint
#endif
#ifndefulong
#defineulongunsignedlong
#endif
//---定义使用的IO口---//
sbitDOUT=P3^7;//输出
sbitCLK=P3^6;//时钟
sbitDIN=P3^4;//输入
sbitCS=P3^5;//片选
uintRead_AD_Data(ucharcmd);
uintSPI_Read(void);
voidSPI_Write(uchardat);
#endif
#include""
/****
*函数名:
TSPI_Start
*输入:
无
*输出:
无
*功能:
初始化触摸SPI
****/
voidSPI_Start(void)
{
CLK=0;
CS=1;
DIN=1;
CLK=1;
CS=0;
}
/****
*函数名:
SPI_Write
*输入:
dat:
写入数据
*输出:
无
*功能:
使用SPI写入数据
****/
voidSPI_Write(uchardat)
{
uchari;
CLK=0;
for(i=0;i<8;i++)
{
DIN=dat>>7;//放置最高位
dat<<=1;
CLK=0;//上升沿放置数据
CLK=1;
}
}
/****
*函数名:
SPI_Read
*输入:
无
*输出:
dat:
读取到的数据
*功能:
使用SPI读取数据
****/
uintSPI_Read(void)
{
uinti,dat=0;
CLK=0;
for(i=0;i<12;i++)//接收12位数据
{
dat<<=1;
CLK=1;
CLK=0;
dat|=DOUT;
}
returndat;
}
/****
*函数名:
Read_AD_Data
*输入:
cmd:
读取的X或者Y
*输出:
endValue:
最终信号处理后返回的值
*功能:
读取触摸数据
****/
uintRead_AD_Data(ucharcmd)
{
uchari;
uintAD_Value;
CLK=0;
CS=0;
SPI_Write(cmd);
for(i=6;i>0;i--);//延时等待转换结果
CLK=1;//发送一个时钟周期,清除BUSY
_nop_();
_nop_();
CLK=0;
_nop_();
_nop_();
AD_Value=SPI_Read();
CS=1;
returnAD_Value;
}