搜索
bottom↓
回复: 18

麻烦傻孩子老师看一个简单的电机闭环控制PID的程序,谢谢!

[复制链接]

出0入0汤圆

发表于 2010-11-28 01:07:27 | 显示全部楼层 |阅读模式
本人新手,用的AVR mega16 想写一个简单的函数。让电机能够在速度为0的时候抱死,即用手拧不动。就用了比例一项。
我用的是输入捕获来计算脉冲的数目,同时在输入捕获的中断里面判断AB相的方向,如果正向就脉冲数加1 ,反之减1。现在有点不理解的就是,是否我可以用定时器每隔5个微秒读一下脉冲数和输入捕获里面的定时值。但是这样的话,定时值感觉就没有太大的意义了。不知道应该怎么处理呢?我程序里面写的是脉冲值一个变量,另外一个变量是无论脉冲正反,他都记一次数。记了10次,他就算一下脉冲值(有方向那个)和输入捕获的时间值。但是这样,如果速度为0的话,很有可能那个脉冲值达不到10.想问下有什么好办法吗?


下面是程序://定时器2  PWM输出端口在OC2引脚  ,PC2为码盘B相输入

//电机减速后事150转  码盘线数是400
#include<iom16v.h>
#include<macros.h>
#define uint unsigned int
#define uchar unsigned char

/**********************************************
电机速度和转向宏定义
***********************************************/
//定义PC0口为电机正反控制端1
#define CRT1_POWERON PORTC|=BIT(0)   
#define CRT1_POWEROFF PORTC&=~BIT(0)

//定义PC1口为电机正反控制端2
#define CRT2_POWERON  PORTC|=BIT(1)   
#define CRT2_POWEROFF PORTC&=~BIT(1)

//限制最高转速  若要求限定最高转速,改变这个值即可
#define speed_MAX       255

//限制最高转速  若要求限定最高转速,改变这个值即可
#define speed_MIN       0


/**********************************************
码盘宏定义
码盘M/T法测速:
测速时间内码盘输出的脉冲数m1,又检测同一时间间隔内高频时钟脉冲数m2。
设高频时钟脉冲频率为f0 则测速时间 T=M2/f0;
习惯上转速常以每分钟转数来表示,则电机的转速可表示为:
n=60M1 *f0/(z*M2)  r/min
式中,z为电机每转一圈所产生的脉冲数(z=倍频系数×码盘光栅数)
***********************************************/
#define  CRYSTAL  80000000  //晶振
#define  N   7000       //定义码盘线数
#define  BEI 1          //倍频数
#define  M1  100         //定义每次需测量的码盘输出的脉冲个数
#define  f0  CRYSTAL/256//定义时钟
#define  feedback    60*time*f0/(N*clknum)   //定义码盘反馈的转速
#define  setPWM  OCR2      //PWM  
//#define  direction     PC2    //定义码盘B相,码盘A相接ICP1  如果B相为1,则为正,为0 ,则为负

/**********************************************
PID参数宏定义
***********************************************/
#define P  100
#define I  10
#define D  20



float setspeed;     //设定转速
uchar direction; //定义方向,1为正,0为反     
uint olddata =0;//输入捕获ICP1的旧读数
uint newdata=0;//输入捕获ICP1的读数
uint clknum=0;
int adjPWM;   //PID调整后的PWM
int tt;   //码盘上升沿次数
float time;  //码盘上升沿次数 ,分了方向的
float adjspeed;



//1ms延时,准确性较高
void DelayMs(unsigned int i)               
   {
    while(i--)
    {                          
            unsigned int j;               
        for(j=1;j<=613;j++) ;
                                      
    }                       
    }
   
   /*-----------------------------------------------------------------
函数名称: void time2_int(void)
函数功能: 定时器2初始化函数
参    数: 无
返 回 值: 无
-----------------------------------------------------------------*/
void time2_int(void)
{
    TCNT2=0X01;
    OCR2=100;
    TCCR2=(1<<WGM20)|(1<<WGM21)|(1<<COM21)|0x06;//快速PWM,256分频,升序清0,降序置1
    TIMSK=0XC0;    //定时器2溢出中断使能,比较匹配中断使能
}

void PORT_INIT()
{
         DDRA|=0XFF;
         PORTA|=0;
         DDRB|=0XFF;
         PORTB|=0;
         DDRC|=0XFF&(~(1<<2));
        // PORTC|=BIT(0)|BIT(1);
         DDRD|=0XFF;
        // PORTD|=BIT(7);
}


/*正方向*/
void zheng()
{
         CRT1_POWERON;
         CRT2_POWEROFF;
}

/*反方向*/
void fan()
{
         CRT1_POWEROFF;
         CRT2_POWERON;
}

/*停止*/
void stop()
{
   CRT1_POWEROFF;
   CRT2_POWEROFF;
}

/*正转*/
void forward (float setspeed)
{
         if(speed!=0)
        {
                 setPWM=(setspeed*255)/150;//setspeed是想要的转速,这里把它转化成PWM的数字(0~255)

        }
       
         zheng();
         
}

/*反转*/

void reverse (uchar setspeed)
{
         if(speed!=0)
         {
                  setPWM=(setspeed*255)/150;   //setspeed是想要的转速,这里把它转化成PWM的数字(0~255)
         }
         fan();
         
}





/*PID反馈调速*/
void speedadjust()
{
         adjspeed=P*(setspeed-feedback);
         if(feedback>setspeed)
         {
          setspeed=adjPWM;
          zheng();
         // PORTC ^= (1 << PC0);
          //PORTC ^= (1 << PC1);
         }
         else
         {
          setspeed=adjPWM;
          fan();
           //PORTC ^= (1 << PC0);
           //PORTC ^= (1 << PC1);
         }
         forward(setspeed);
}


/*
输入捕获初始化
*/
void Timer1_Init(void)
{
    TCCR1A = 0x00;
                                                                     // Input Capture on Falling Edge
    TCCR1B = (1<<ICNC1)|(0<<ICES1)|(0<<CS12)|(1<<CS11)|(1<<CS10);   //噪声抑制 ,低电平进行捕捉 , 64预分频
                                                                   // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK = (1<<TICIE1);                                          //定时器1 输入捕捉使能
}

//定时器1 输入捕获中断
#pragma interrupt_handler timer1_capt_isr:6
void timer1_capt_isr(void)

{   
        if( PINC & (1 << 3) )   //读取PC2位,即B相
        {time++;}
        else
        {
         time--;
        }
        tt++;
       
       
        if(tt==M1)// 100次读一下
        {
         tt=0;
         time=0;
         newdata=ICR1;
         clknum=newdata-olddata;
         olddata=newdata;
        }
}


/*读取内部时钟的计数值
void readclk()
{

         tt=0;
         time=0;
         newdata=ICR1;
         clknum=newdata-olddata;
         olddata=newdata;
       
}*/



void main()
{

  Timer1_Init();
          _SEI();  //全局中断使能

PORT_INIT();
time2_int();

while(1)
{
forward(0);
speedadjust();

DelayMs(50);
}


}

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2010-11-28 10:09:16 | 显示全部楼层
闭环PI控制,期待

出0入0汤圆

发表于 2010-11-28 11:14:24 | 显示全部楼层
回复【1楼】ankjin
闭环pi控制,期待
-----------------------------------------------------------------------

支持

出0入0汤圆

 楼主| 发表于 2010-11-28 12:36:07 | 显示全部楼层
回复【楼主位】bhdsd
-----------------------------------------------------------------------

要是P会了,PI只是换个公式而已吧。难的应该就是调试I参数吧,挺想试试看用LABVIEW模拟的

出0入296汤圆

发表于 2010-11-29 14:08:25 | 显示全部楼层
我感觉输入捕获的时间值基本是没有用的。
直接用外中断就可以了,简单做,可以选择电平变化中断(只要变化了就中断),
然后判断A和B电平是否相同,相同+1,不同-1。

这就可以实现一个脉冲计数器。
然后根据这个脉冲计数器做一个简单的P就好了。
通常P就够用了,只要你的电动机齿轮变速比例够大。

出0入0汤圆

发表于 2010-11-29 15:05:55 | 显示全部楼层
电机不用做D的

出0入0汤圆

发表于 2010-12-9 19:17:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-9 21:38:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-28 22:14:07 | 显示全部楼层
mark
头像被屏蔽

出0入0汤圆

发表于 2011-1-1 21:22:38 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2011-1-1 22:07:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-15 22:02:45 | 显示全部楼层
学习

出0入0汤圆

发表于 2012-8-4 11:52:15 | 显示全部楼层
学习      

出0入0汤圆

发表于 2012-8-5 02:01:24 | 显示全部楼层
大家的电机抱死一般都怎么实现?

出0入296汤圆

发表于 2012-8-5 21:49:38 | 显示全部楼层
magicer2010 发表于 2012-8-5 02:01
大家的电机抱死一般都怎么实现?

位置环就可以实现。

出0入0汤圆

发表于 2012-8-6 14:30:46 | 显示全部楼层
mark,学习了

出0入0汤圆

发表于 2012-8-31 10:05:43 | 显示全部楼层
带速度和电流PID反馈的直流无刷电机的硬件电路是怎么设计的啊???

出0入0汤圆

发表于 2012-8-31 15:58:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2014-1-15 10:19:15 | 显示全部楼层
老大,请问你这个有设计文档或者程序流程图吗?直接看程序有点难看明白,好多变量没注释用途。
抱歉我是新手!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 14:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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