找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 16894|回复: 4
打印 上一主题 下一主题
收起左侧

急用,求单片机C编程,用STC89C52单片机实现直流电机的PID控制。通过PWM控制电机。...

[复制链接]
跳转到指定楼层
楼主
ID:50448 发表于 2013-5-20 12:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hzz156077851 于 2013-5-20 13:26 编辑

以下是我编好的调试好的可用的测速及显示模块,需要在此基础上加上PID调速模块。
要求如下:直流电机增量式PID的速度闭环控制。通过光电传感器回馈的脉冲(电机没转得到2脉冲)测得当前的电机转速,通过PID调节得到当前的输出PWM占空比。4位的7段码LCD显示当前速度。PID参数可我自己根据电机特性调整。(目前测速和显示程序已经编写好)

我的联系QQ:156077851,电话:15249237747
程序编写要求:
测速和显示程序已经编好了,需要在此基础上实现直流电机的PID闭环调速。是基于STC89C52单片机的程序。
不需要仿真和电路图。

直流电机使用L298实现PWM调速的。由于单片机上没有按键,要用循环语句让电机以一个速度恒定的运行8秒,8秒后通过软件让电机转速增加一次并通过PID调速让其稳定在设定的转速值(即软件里面已经事先通过循环语句(或table语句)写好的转速设定值)附近,然后再运行个8秒之后电机速度再增加一次,如此直到增加9次后电机停止运行。整个过程直流电机通过软件实现PWM调速的。电机设定的转速分别为40,50,60,70,80,90,100,110,120r/s,每个速度各运行8秒。
至于P I D的参数KP(比例系数)  KI(积分系数)  KD(微分系数)参数的设定我自己通过实验调试,说是PID调速,其实我们老师要求我们只要用PI调速就可以了。所以微分环节可以不用。

电机的转速范围在40-130r/s之间把,别太高,也别低于40,不然电机转不动;

L298N:
en1:表示直流电机的 使能端 当值为1(高电平)时有效,接在了单片机的P1.2引脚;
zhen1:表示直流电机的 正转信号输出端,当值为1(高电平)时有效,接在了单片机的P1.0引脚;
fan1:表示直流电机的 反转信号输出端,当值为1(高电平)时有效,接在了单片机的P1.1引脚;
光电测速传感器的 脉冲信号输出端 接的是P3.5引脚;
PWM一个周期是20ms;

下面是已经编好的测试通过的可以测速和显示速度的程序:
#include <REG52.H>                 
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar a,b,c,d;
#define LED_DAT P0
sbit pin_SpeedSenser = P3^5; //速度传感器脉冲信号输出端接在T1上
#define TIME_CYLC 100 //12M晶振,定时器10ms 中断一次 我们1秒计算一次转速,1000ms/10ms = 100
#define PLUS_PER 2 //码盘的齿数 ,这里假定码盘上有2个齿,即传感器检测到2个脉冲,认为1圈
#define K 1.0   //校准系数
sbit zhen1=P1^0;
sbit fan1=P1^1;
sbit en1=P1^2;

uchar code loops[] = {0x7f,0xbf,0xdf,0xef};         //定义显示位控制驱动码
uchar code table[]={0x14,0xd7,0x4c,0x45,0x87,0x25,0x24,0x57,0x04,0x05};          // 0,1,2,3,4,5,6,7,8,9 7段码表,这个单片机开发板上的LED数码管的接法和一般的有点不一样,这个表是正确的,已经测试过了  
                    
uint Tcounter = 0;   //时间计数器
bit Flag_Fresh = 0; // 刷新标志
bit Flag_clac = 0; //计算转速标志
bit Flag_Err = 0; //超量程标志
//在数码管上显示一个四位数
void DisplayFresh();

//计算转速,并把结果放入数码管缓冲区
void ClacSpeed();

//初始化定时器
void init_timer();

//延时函数
void Delay(uint ms);

void it_timer0() interrupt 1 //定时器0中断的响应函数
{
TF0 = 0;       //定时器 T0用于数码管的动态刷新      
TH0 = 0xD8;            //初始化
TL0 = 0xF0;
Flag_Fresh = 1;
Tcounter++;
if(Tcounter>TIME_CYLC)
{
   Flag_clac = 1;//周期到,该重新计算转速了
}
}
void it_timer1() interrupt 3 //中断地址是0x001b
{
TF1 = 0;   //定时器T1用于单位时间内收到的脉冲数,要速度不是很快,T1永远不会益处
Flag_Err = 1;   //如果速度很高,我们应考虑另外一种测速方法:脉冲宽度算转速
}

void main(void)
{
init_timer();
while(1)
{
  zhen1=1;                                
  fan1=0;
  en1=1;
  Delay(30);
  en1=0;
  Delay(170);
  
if(Flag_Fresh)
   {
    Flag_Fresh = 0;
    DisplayFresh();    // 定时刷新数码管显示
   }

   if(Flag_clac)
   {
            Flag_clac = 0;
            ClacSpeed(); //计算转速,并把结果放入数码管缓冲区  
            Tcounter = 0;//周期定时清零
            TH1=TL1 = 0x00;//脉冲计数清零
    }
   if(Flag_Err)        //超量程处理
   {
            //数码管显示字母'EEEE',开机时初始化为0000
            a = 0x2c;
            b = 0x2c;
            c = 0x2c;
            d = 0x2c;
    while(1)
    {
     DisplayFresh();//等待复位,不再测速
    }
   }
}
}

//在数码管上显示一个四位数
void DisplayFresh()
{                  
         P2 =loops[0] ;
         LED_DAT = table[a];
         Delay(20);
         P2 =loops[1] ;
         LED_DAT = table;
         Delay(20);
         P2 =loops[2] ;
         LED_DAT = table[c];
         Delay(20);
         P2 =loops[3] ;
         LED_DAT = table[d];
         Delay(20);
}

//计算转速,并把结果放入数码管缓冲区
void ClacSpeed()
{
         uint speed ;
         ulong PlusCounter;
         PlusCounter = TH1*256 + TL1;
         speed = K*(PlusCounter/PLUS_PER);//K是校准系数,如速度不准,调节K的大小
         a = (speed/1000)%10;
         b = (speed/100)%10;
         c = (speed/10)%10;
         d = speed%10;
}

void init_timer()                 //初始化
{
         TMOD = 0x51; //定时10毫秒,TOT1选择软件门方式1,T0定时,T1计数,96页可查
         TH0 = 0xD8;            //T0初始化
         TL0 = 0xF0;  
         ET0=1;                     //T0中断允许
         EA=1;               //T0中断
         TR0=1;               //TO运行
         TH1 = 0x00;            //T1初始化
         TL1 = 0x00;  
         ET1=1;                     //T1中断允许
         TR1=1;               //T1运行
         zhen1=1;
         fan1=0;
}
                        
void Delay(uint ms)               //0.1ms延时函数
{
uchar x,y;
   for(x=ms;x>0;x--)
   for(y=11;y>0;y--);
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:40961 发表于 2013-8-7 19:51 | 只看该作者
学习学习
回复

使用道具 举报

板凳
ID:55601 发表于 2013-10-3 15:03 | 只看该作者
看过了
回复

使用道具 举报

地板
ID:205444 发表于 2017-5-28 14:58 | 只看该作者
楼主解决了吗?这个跟我的毕设一样
回复

使用道具 举报

5#
ID:219792 发表于 2017-7-14 23:55 | 只看该作者
数码管显示字母'EEEE'  錯誤解决了吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表