搜索
bottom↓
回复: 29

AVR单片机PID控制电机程序2011-3-30

[复制链接]

出0入0汤圆

发表于 2011-8-7 15:04:04 | 显示全部楼层 |阅读模式
转一个 AVR单片机PID控制电机程序
AVR单片机PID控制电机程序2011-3-30
2011-04-10 2053

Project  PID_motor
Version  第一版
Date     2011-3-30
Author                              
Company                           
Comments
Chip type            ATmega16L
Program type         Application
Clock frequency      4.000000 MHz
Memory model         Small
External SRAM size   0
Data Stack size      256

#include mega16.h
#include delay.h
#include fyd12864.h
#include string.h

sfrw ICR1=0x26;                                            补充定义16位寄存器ICR1地址为0x26(mega16.h中未定义)                                 
unsigned int icp_v1;
unsigned int icp_v2;
unsigned char icp_n;
unsigned char max_icp;                              量程定义字
bit icp_ok;
bit time_4ms_ok;
bit freq_ok;
bit begin_m;                                               定时器1溢出,重新测量标志字
bit full_ok;                                                  定时器1溢出
long fv;

struct PID
{  
    unsigned int SetPoint;                          设定目标 Desired Value  
    unsigned int Proportion;                       比例常数 Proportional Const  
    unsigned int Integral;                           积分常数 Integral Const  
    unsigned int Derivative;                       微分常数 Derivative Const  
    unsigned int LastError;                        Error[-1]  
    unsigned int PrevError;                       Error[-2]  
    unsigned int SumError;                       Sums of Errors  
};  
struct PID spid;                                       PID Control Structure

long rout;                                               PID Response (Output)  
long rin;                                                 PID Feedback (Input)

void PID_Init(struct PID pp)  
{  
    memset ( pp,0,sizeof(struct PID));     全部初始化为0
}
unsigned int PID_Calc( struct PID pp, unsigned int NextPoint )  
{  
    unsigned int dError,Error;  
    Error = pp-SetPoint - NextPoint;                   偏差     
    pp-SumError += Error;                                 积分     
    dError = pp-LastError - pp-PrevError;       当前微分   
    pp-PrevError = pp-LastError;     
    pp-LastError = Error;  
    return (pp-Proportion  Error                      比例项     
    + pp-Integral  pp-SumError                     积分项  
    + pp-Derivative  dError);                           微分项  
}   

Timer 2 比较匹配中断服务,4ms定时
interrupt [TIM2_COMP] void timer2_comp_isr(void)   
{
  #asm(sei)                           开放全局中断,允许中断嵌套   
    time_4ms_ok = 1;
}

Timer 1 溢出中断服务
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
    full_ok = 1;
}

Timer 1 输入捕捉中断服务
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
    if (icp_n = max_icp)    第N个上升沿到
    {
        icp_v2 = ICR1;       记录第N个上升沿时间
        TIMSK = 0x80;        禁止TCI输入捕捉和溢出中断
        icp_ok = 1;
    }
    else if (icp_n == 0)
    {
        icp_v1 = ICR1;       记录第1个上升沿时间
    }   
    icp_n++;     
}

void main(void)
{
    unsigned int icp_1,icp_2;   
    PORTB=0x00;
    DDRB=0x08;
    PORTD=0x40;              PD6(icp)输入方式,上拉有效
   
     TC0 定时初始化
    TCCR0=0x79;              Mode Fast PWM top=FFh   
    TCNT0=0x00;              OC0 output Non-Inverted PWM
    OCR0=0xff;
     TC1 计数初始化
    TCCR1B = 0x41;           TC1正常计数方式,上升沿触发输入捕捉,4M1计数时钟
    TIMSK = 0xA4;              允许TC2比较匹配中断,允许TC1输入捕捉、溢出中断

     TC2 定时初始化
    TCCR2=0x0C;              内部时钟,64分频(4M64=62.5KHz),CTC模式
    OCR2=0xff;                  OCR2 = 0xf9(249),(249+1)62.5=4ms
  
    icp_n = 0;
    max_icp =1;                                 定义上升沿的位序
    #asm(sei)                                  开放全局中断
    INIT_FYD();
    Show_Text(3,0,chinese);           (列,行,显示字)
    PID_Init(&spid);                          Initialize Structure
    spid.SetPoint = 168;                  设定目标 Desired Value  
    spid.Proportion = 6;                  比例常数 Proportional Const  
    spid.Integral =5;                        积分常数 Integral Const  
    spid.Derivative =2;                   微分常数 Derivative Const  
    FM_Num(0,1,spid.Proportion);      显示比例
    FM_Num(3,1,spid.Integral);           显示积分
    FM_Num(6,1,spid.Derivative);       显示微分
    FM_Num(0,2,spid.SetPoint);          显示目标
    while (1)
{
     if (icp_ok == 1)                                                完成一次测量
     {
         if (icp_v2 = icp_v1)                                    计算N个上升沿的时钟脉冲个数,
             icp_2 = icp_v2 - icp_v1;                         两次连续的ICR1的差值
         else                                          
             icp_2 = 65536 - icp_v1 + icp_v2;          定时器1溢出,加上65535         
         if (!(icp_v2 = icp_v1 && full_ok))              有溢出,数据无效   
            {           
                if (icp_2 == icp_1)                              两次个数相等,测量有效
             {
                    fv = 1000000  (long)max_icp  icp_2;        换算成频率值
                    freq_ok = 1;                                    频率换算完成
               
                    if (fv  4000)
                    {
                        max_icp = 20;                              如果频率大于4Khz,N=64
                    }
                    else
                    {
                        max_icp = 1;                                  N=1
                    }
                }
         }
         else
         max_icp = 1;                                               有溢出,N=1         
         icp_1 = icp_2;         
         icp_ok = 0;
            begin_m = 1;
       }        
     if (time_4ms_ok)                                            定时器2,定时到         
     {                           
         if(freq_ok)                                                判断频率是否换算完成
         {
            rin=fv;
            FM_Num(0,3,rin);
            rout = PID_Calc ( &spid,rin );
            rout=rout100;
            FM_Num(3,3,rout);            
            if(rout100&&rout256)
            OCR0=rout;                       
            freq_ok = 0;
         }
         else if(begin_m)         
         {
                icp_n = 0;       开始新的一次测量,
                full_ok = 0;     清除溢出标志
             TIFR = 0x24;     清除可能存在的输入捕捉、溢出中断标志位
             TIMSK = 0xa4;  开启TC1输入捕捉、溢出中断允许        
             begin_m = 0;
         }
            time_4ms_ok = 0;     
     }
    }
}

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

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2011-8-7 16:02:15 | 显示全部楼层
上面的版本有格式上得错误
/*****************************************************
Project : PID_motor
Version : 第一版
Date    : 2011-3-30
Author  :                           
Company :                           
Comments:
Chip type           : ATmega16L
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/
#include <mega16.h>
#include <delay.h>
#include <fyd12864.h>
#include <string.h>

sfrw ICR1=0x26;                                           // 补充定义16位寄存器ICR1地址为0x26(mega16.h中未定义)                                 
unsigned int icp_v1;
unsigned int icp_v2;
unsigned char icp_n;
unsigned char max_icp;                              //量程定义字
bit icp_ok;
bit time_4ms_ok;
bit freq_ok;
bit begin_m;                                               //定时器1溢出,重新测量标志字
bit full_ok;                                                  //定时器1溢出
long fv;

struct PID
{  
    unsigned int SetPoint;                         // 设定目标 Desired Value  
    unsigned int Proportion;                      // 比例常数 Proportional Const  
    unsigned int Integral;                          // 积分常数 Integral Const  
    unsigned int Derivative;                      // 微分常数 Derivative Const  
    unsigned int LastError;                       // Error[-1]  
    unsigned int PrevError;                      // Error[-2]  
    unsigned int SumError;                      // Sums of Errors  
};  
struct PID spid;                                      // PID Control Structure

long rout;                                              // PID Response (Output)  
long rin;                                                // PID Feedback (Input)

void PID_Init(struct PID *pp)  
{  
    memset ( pp,0,sizeof(struct PID));     //全部初始化为0
}
unsigned int PID_Calc( struct PID *pp, unsigned int NextPoint )  
{  
    unsigned int dError,Error;  
    Error = pp->SetPoint - NextPoint;                  // 偏差     
    pp->SumError += Error;                                // 积分     
    dError = pp->LastError - pp->PrevError;      // 当前微分   
    pp->PrevError = pp->LastError;     
    pp->LastError = Error;  
    return (pp->Proportion * Error                     // 比例项     
    + pp->Integral * pp->SumError                    // 积分项  
    + pp->Derivative * dError);                          // 微分项  
}   

// Timer 2 比较匹配中断服务,4ms定时
interrupt [TIM2_COMP] void timer2_comp_isr(void)   
{
  #asm("sei")                          // 开放全局中断,允许中断嵌套   
    time_4ms_ok = 1;
}

// Timer 1 溢出中断服务
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
    full_ok = 1;
}

// Timer 1 输入捕捉中断服务
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
    if (icp_n >= max_icp)   // 第N个上升沿到
    {
        icp_v2 = ICR1;      // 记录第N个上升沿时间
        TIMSK = 0x80;       // 禁止T/CI输入捕捉和溢出中断
        icp_ok = 1;
    }
    else if (icp_n == 0)
    {
        icp_v1 = ICR1;      // 记录第1个上升沿时间
    }   
    icp_n++;     
}

void main(void)
{
    unsigned int icp_1,icp_2;   
    PORTB=0x00;
    DDRB=0x08;
    PORTD=0x40;             // PD6(icp)输入方式,上拉有效
   
    // T/C0 定时初始化
    TCCR0=0x79;             // Mode: Fast PWM top=FFh   
    TCNT0=0x00;             // OC0 output: Non-Inverted PWM
    OCR0=0xff;
    // T/C1 计数初始化
    TCCR1B = 0x41;          // T/C1正常计数方式,上升沿触发输入捕捉,4M/1计数时钟
    TIMSK = 0xA4;             // 允许T/C2比较匹配中断,允许T/C1输入捕捉、溢出中断

    // T/C2 定时初始化
    TCCR2=0x0C;             // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
    OCR2=0xff;                 // OCR2 = 0xf9(249),(249+1)/62.5=4ms
  
    icp_n = 0;
    max_icp =1;                                 //定义上升沿的位序
    #asm("sei")                                 // 开放全局中断
    INIT_FYD();
    Show_Text(3,0,chinese);           //(列,行,显示字)
    PID_Init(&spid);                         // Initialize Structure
    spid.SetPoint = 168;                  //设定目标 Desired Value  
    spid.Proportion = 6;                  //比例常数 Proportional Const  
    spid.Integral =5;                        //积分常数 Integral Const  
    spid.Derivative =2;                   //微分常数 Derivative Const  
    FM_Num(0,1,spid.Proportion);      //显示比例
    FM_Num(3,1,spid.Integral);           //显示积分
    FM_Num(6,1,spid.Derivative);       //显示微分
    FM_Num(0,2,spid.SetPoint);          //显示目标
    while (1)
{
     if (icp_ok == 1)                                               // 完成一次测量
     {
         if (icp_v2 >= icp_v1)                                   // 计算N个上升沿的时钟脉冲个数,
             icp_2 = icp_v2 - icp_v1;                         //两次连续的ICR1的差值
         else                                          
             icp_2 = 65536 - icp_v1 + icp_v2;          //定时器1溢出,加上65535         
         if (!(icp_v2 >= icp_v1 && full_ok))             // 有溢出,数据无效   
            {           
                //if (icp_2 == icp_1)                             // 两次个数相等,测量有效
             {
                    fv = 1000000 * (long)max_icp / icp_2;       // 换算成频率值
                    freq_ok = 1;                                    //频率换算完成
               
                    if (fv > 4000)
                    {
                        max_icp = 20;                             // 如果频率大于4Khz,N=64
                    }
                    else
                    {
                        max_icp = 1;                                 // N=1
                    }
                }
         }
         else
         max_icp = 1;                                              // 有溢出,N=1         
         icp_1 = icp_2;         
         icp_ok = 0;
            begin_m = 1;
       }        
     if (time_4ms_ok)                                            //定时器2,定时到         
     {                           
         if(freq_ok)                                                //判断频率是否换算完成
         {
            rin=fv;
            FM_Num(0,3,rin);
            rout = PID_Calc ( &spid,rin );
            rout=rout/100;
            FM_Num(3,3,rout);            
            if(rout>100&&rout<256)
            OCR0=rout;                       
            freq_ok = 0;
         }
         else if(begin_m)         
         {
                icp_n = 0;      // 开始新的一次测量,
                full_ok = 0;    // 清除溢出标志
             TIFR = 0x24;    // 清除可能存在的输入捕捉、溢出中断标志位
             TIMSK = 0xa4; // 开启T/C1输入捕捉、溢出中断允许        
             begin_m = 0;
         }
            time_4ms_ok = 0;     
     }
    }
}

出0入0汤圆

发表于 2011-10-27 18:50:11 | 显示全部楼层
谢谢,正需要这个

出0入0汤圆

发表于 2011-10-27 19:50:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-27 20:54:56 | 显示全部楼层
发程序不如发思路。但还是谢谢

出0入0汤圆

发表于 2012-1-9 15:25:37 | 显示全部楼层
好像缺一个定时器0的中断函数!

出0入0汤圆

发表于 2012-1-9 20:20:03 | 显示全部楼层
又是PID,学学。

出0入0汤圆

发表于 2012-1-9 22:19:53 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-1-16 11:49:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-1-16 17:03:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-9 16:35:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-9 16:44:13 | 显示全部楼层
以备不时之需

出0入0汤圆

发表于 2012-2-9 19:48:26 | 显示全部楼层
PID电机实例

出0入0汤圆

发表于 2012-2-9 21:18:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-13 18:44:04 | 显示全部楼层
好的,Mark

出0入0汤圆

发表于 2012-2-15 17:21:36 | 显示全部楼层
正在学习

出0入0汤圆

发表于 2012-2-15 17:38:41 | 显示全部楼层
顶起来!

出20入22汤圆

发表于 2012-2-15 18:56:38 | 显示全部楼层
学习,不过说一下思路,最好了

出0入0汤圆

发表于 2012-2-15 19:00:42 | 显示全部楼层
Mark

出0入0汤圆

发表于 2012-2-16 08:42:57 | 显示全部楼层
留个脚印。回头来看

出0入0汤圆

发表于 2012-2-29 00:25:04 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-29 10:30:36 | 显示全部楼层
MARK

出0入0汤圆

发表于 2012-3-2 18:27:03 | 显示全部楼层
MARK

出0入0汤圆

发表于 2012-3-3 01:45:45 | 显示全部楼层
MARK

出0入0汤圆

发表于 2012-3-6 19:43:18 | 显示全部楼层
想学习一下PID,不清楚是交流还是直流电机

出0入0汤圆

发表于 2012-4-11 23:36:24 | 显示全部楼层
谢谢楼主正在学这个.....

出0入0汤圆

发表于 2012-4-12 07:20:23 来自手机 | 显示全部楼层
谢谢楼主,总有用到的时候!

出0入0汤圆

发表于 2012-4-12 08:23:56 | 显示全部楼层
标记:学习!!!

出0入0汤圆

发表于 2012-4-12 08:39:40 | 显示全部楼层
呵呵,整理成附件的格式好一些吧。MARK!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-23 19:22

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

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