打印

请大家帮我看看我的直流电机PID调速程序哪里有问题,谢谢

[复制链接]
1794|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
TT的爱|  楼主 | 2013-3-6 14:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 TT的爱 于 2013-3-6 14:57 编辑

无论怎么调,速度总是差那么一点。请大家帮我看一下。
我使用的芯片是PIC16F876A,编译环境是CCS。目标是通过PID实现调速,但只使用了比例积分调节。
RA0接口为模拟电压输入,AD转换完的数据由单片机处理后,可以设定目标转速。光电编码器通过RC0接口输入计数脉冲,计算出实际转速,通过PID计算不断调整,最终接近目标转速。
定时器0每过10ms取计数器1的脉冲计数值,光电编码器分辨率为360。现在有两个情况比较奇怪,
1:我把P参数从1到10,I参数从0到5都试了一遍。当I参数过大时会出现实际速度变低的情况,当I参数为2时电机不能转动,其他情况下实际速度基本区别不大。
2:我将目标速度调高时(例如超过5000r/min),则实际速度比目标速度高出的部分会越来越大。而当目标速度调低时(如低于3000r/min),实际速度比目标速度低出的部分会越来越大。无论P,I如何设定,都是这样的情况。

程序如下。
#include  <16f876a.h>
#include  <lcd.h>
#fuses HS,PUT,NOPROTECT,NOWDT
#use delay(CLOCK = 20000000,RESTART_WDT)    //时钟频率20MHz

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)

unsigned long int overflow=0,get_count,new_count=0,get_speed=0,new_error=0,new_speed=0,old_count=0,old_speed=0,old_error=0;//所需变量
unsigned int ch0_channel,new_duty;
float new_pwm,set_speed;

#int_TIMER1
TIMER1_isr()      //定时器1中断函数
{
    overflow++;   
}

#int_TIMER0
TIMER0_isr()     //定时器0中断函数
{
    set_timer0(0x3C);                     //定时器0每过10ms发生一次中断
  
    new_count = get_timer1();          //读取计数器1的脉冲计数值
    get_count = new_count-old_count;                            //PID部分
    get_speed = get_count*50/3;
    new_error = set_speed-get_speed;
    new_speed = (new_error-old_error)*1+1*new_error+get_speed;
        

    new_pwm = (float)new_speed/31;    //感觉是这边出问题了
    new_duty = (int)new_pwm;
    set_pwm1_duty(new_duty);
   
   
    old_error = new_error;
    old_count = new_count;
    old_speed = new_speed;
    overflow = 0;
}

void main(void)
{
        set_tris_a(0b11111111);                            //0:输出、1:输入
        set_tris_b(0b11000000);                            //0:输出、1:输入
        set_tris_c(0b00000001);                            //0:输出、1:输入
   
        SETUP_ADC_PORTS(RA0_ANALOG);                      //RA0 为模拟输入
        SETUP_ADC(ADC_CLOCK_DIV_32);                       //Fosc/32  
        set_adc_channel(0);                                             //选择channel0

        enable_interrupts(GLOBAL);                         //允许全局中断
        enable_interrupts(INT_TIMER0);                   //允许定时器0中断
        enable_interrupts(INT_TIMER1);                   //允许定时器1中断

        setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);       //定时器0分频
        setup_timer_1(T1_EXTERNAL_SYNC|T1_DIV_BY_1);   //定时器1用作计数器

        set_timer0(0x3C);
               setup_timer_2(T2_DIV_BY_16,255,1);                 //定时器2设置
        setup_ccp1(ccp_pwm);                                       // 选择PWM模式

        read_adc(ADC_START_ONLY);                          //读取八位AD值
   
        lcd_initial();                                     //lcd初始化
        while(1)                                          
        {                                 
            ch0_channel = read_adc(ADC_READ_ONLY);         //读取AD转换值
            read_adc(ADC_START_ONLY);                            //AD转换开始
            set_speed = (float)31*ch0_channel;                   //经过测试测试,速度大概是channel0数值的31倍

            printf(lcd_data,"sv:%3.3f",set_speed);              //第一行显示目标速度
            lcd_cmd(0b11000000);                           
            printf(lcd_data,"pv:%lu",get_speed);                 //第2行显示实际速度
         
            delay_ms(200);                                 //lcd延迟200ms
            lcd_clear();                                       //lcd清除

     }   
}
[upload=txt,pid.txt]viewFile.asp?ID=14022[/upload]<br/>

相关帖子

沙发
airwill| | 2013-3-6 19:06 | 只看该作者
不收敛, P 加大.

使用特权

评论回复
板凳
opl90100| | 2013-3-6 20:55 | 只看该作者
楼主,我是一名本科生,最近也在做关于直流电机闭环控制系统的课程设计,要求比较简单.有几个问题,希望你能帮我答疑一下,可以的话加我QQ312916624

使用特权

评论回复
地板
电子过客| | 2013-9-7 12:01 | 只看该作者
楼主,我最近做PLC方面的,编码器,也是PID  你能把PID函数 或相关的文件,参考以下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

36

帖子

0

粉丝