⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 新建 文本文档.txt

📁 自己可以通过设置P
💻 TXT
字号:
// S.Gupta 
// Mar 01,00 
// Time: 13:10 

// Digital Implementation of conventional PID algorithm 
// PIC16C773 microcontroller with 8 MHz crystal frequency 

#include <16C773.H> 

#BYTE OPTION = 0x81 
#bit TOIF = 0x0B.2 

#use Delay(Clock=8000000) 

#use RS232(Baud=9600, Xmit=PIN_C6, Rcv=PIN_C7, brghlok) 

#define BRAKE      PIN_B1 // Output to apply brake to motor 
#define DIRECTION  PIN_B2 // Output to control motor direction 
#define OVERHEATED PIN_B0 // Input H-bridge temperature flag 
#define ALARM      PIN_B4 // Output to buzzer/alarm 

// ***************************************************************** 
//     Global Variables 
// ***************************************************************** 
// All the control coefficients are entered as multiples of 
// desired values. This provides a hidden decimal point 
// to improve calculations 

long int KP;    // Entered as Kp * 8 
long int KI;    // KI is entered as Ki * TS 
                // KI = (Ki * 0.001024) * 256 
long int KD;    // Entered as (Kd/TS) * 256 
                // KD = (Kd / 0.001024) * 256 
long int TS;    // Cycle time 
long int V0;    // Current output 
long int V1;    // Last output 
long int ER0;   // Current error 
long int ER1;   // Previous error 
long int ER2;   // [Second] Previous error 
int SP_VEL;     // Desired velocity 
int MV_VEL;     // Measured velocity 
byte duty; 

// ***************************************************************** 

void initialize(void) 
{ 
    // Initialize all variables 

    byte tmp; 
    // Arbitrary assignment of controller coefficients 
    KP = 2;     // Proportional Coefficient 
    KI = 1;     // Integral Coefficient 
    KD = 1;     // Derivative Coefficient 
    V0 = 0;     // Current Controller output 
    V1 = 0;     // Previous Controller output 
    ER0 = 0;    // Current error 
    ER1 = 1;    // Last error 
    ER2 = 0;    // Second last error 
    SP_VEL = 0; // Current desired velocity 
    MV_VEL = 0; // Current motor velocity 
    TS = 977;   // Sample time 977 ms 
    duty = 0;   // Duty cycle 

    // Set up peripheral functions 
    // Set motor direction, and no brake 
    output_bit(DIRECTION, 1);  // Set direction as forward 
    output_bit(BRAKE, 0);      // No brakes 
    output_bit(ALARM, 0);      // Reset alarm 
                               // A buzzer/light can be connected to 
                               // this output 

    set_pwm1_duty(duty);       // Set up 0 duty cycle at the start 
    setup_ccp1(CCP_PWM);       // Configure CCP1 as a PWM 
    setup_timer_2(T2_DIV_BY_4, 255, 1); 
    set_pwm1_duty(duty);       // This sets duty cycle of 0 

    // Set up A/D 
    // First two channels are used to read SP & MV 
    setup_port_a(ALL_ANALOG); 
    setup_adc(ADC_CLOCK_INTERNAL); 

    // Set up timer0 for Sample Clock 
    // Timer0 overflow every 1 ms Xtal = 8 MHz 

    tmp = OPTION;     // Read option register 
    tmp = tmp & 0xC0; // Clear PSA bit. Assign Prescaler to Timer0 
    tmp = tmp | 0x02; // Assign Prescaler (001) to div by 8 
                      // Timer0 will overflow every msec. 
    #asm 
        clrwdt        // Start watch dog timer 
    #endasm 
    OPTION = tmp;     // Set option register 
} 

long int input_num(void) 
{ 
    // There is no built in routine to read an integer number through 
    // serial port. 

    // Read an integer through serial port 
    // Routine is terminated 
        // on receiving a non decimal char 
        // on receiving 4 chars 
    // Routine returns a long integer (16 bit value) 

    short exit_flag;    // Local flag to indicate a non decimal char 
    byte b; 
    byte d;             // Number of digits. 
    long int n; 

    exit_flag = 0;      // Reset the flag 
    d = 0; 
    b = 0; 
    n = 0; 

    do 
    { 
        b = getch();    // Read a char 
        if ((b >= '0') && (b <= '9')) 
        { 
            b = b - '0'; 
            n = n * 10; 
            n = n + b; 
            d = d + 1;    // Increment digit counter 
            if (d > 3)    // Exit if four digits received 
                exit_flag = 1; 
        } 
        else    // Non decimal char received 
            exit_flag = 1; 
    } while (!exit_flag);    // repeat if flag is not set 

    return n; 
} 

void read_coefficients(void) 
{ 
    // Accept the control coefficient through serial port 
    // and set the global variables 

    printf("\nEnter KP: "); 
    KP = input_num(); 

    printf("\nEnter KI: "); 
    KI = input_num(); 

    printf("\nEnter KD: "); 
    KD = input_num(); 

    // Display the coefficients to user 
    printf("\n KP: lu", KP); 
    printf("\n KI: lu", KI); 
    printf("\n KD: lu", KD); 
} 

void main(void) 
{ 
    byte tick; 
    long int ad_result; 
    long int tmp_x, tmp_y; 

    long int K1;    // First Coefficient 
    long int K2;    // Second Coefficient 
    long int K3;    // Third Coefficient 

    initialize();   // Initialize variables & setup peripherals 

    read_coefficients();  // Read the control coefficients 
                          // Coefficients are only read once. Reset 
                          // uC in order to enter new values 
                          // Code can be modified to enter the values 
                          // on the fly and store these in EEPROM 

    while (1)             // Begining of infinite loop 
    { 
        while (!TOIF);    // Wait till TOIF flag is zero 
                          // It will be set to 1 on timer0 overflow 
        TOIF = 0;         // Reset the TOIF flag 
        restart_wdt();    // Reset watch dog timer 

        set_adc_channel(0);     // Read SP_Vel 
        ad_result = Read_ADC(); 
        SP_VEL = adc_result; 

        set_adc_channel(1);     // Read MV_Vel 
        ad_result = Read_ADC(); 
        MV_VEL = ad_result; 

        ER0 = SP_VEL - MV_VEL;  // Current error 

        // Calculate output 
        // Velocity algorithm used 
        // V0 = V1 + KP*(ER0-ER1) + KI*ER0*TS + KD*(ER0-2*ER1+ER2)/TS; 
        // V0 = V1 + K1*(ER0-ER1)/8 + K2*ER0/256 + K3*(ER0-2*ER1+ER2)/256; 

        tmp_x = (ER0 - ER1);    // Proportional 
        tmp_x = KP * tmp_x; 
        tmp_x = tmp_x >> 3;     // Divide by 8 
        V0 = V1 + tmp_x; 

        tmp_x = K2 * ER0;       // Integral 
        tmp_x = tmp_x >> 8;     // Divide by 256 
        V0 = V0 + tmp_x; 

        tmp_x = ER0 + ER2;      // Derivative 
        tmp_y = 2 * ER1; 
        tmp_x = tmp_x - tmp_y; 
        tmp_y = tmp_x * K3; 
        tmp_y = tmp_y >> 8;     // Divide by 256 

        V0 = V0 + tmp_y; 

        // check the output for bounds 
        if (V0 < 0) 
            V0 = 0; 
        if (V0 > 255) 
            V0 = 255; 
        duty = V0; 

        // Shift Variables 
        V1 = V0; 
        ER2 = ER1; 
        ER1 = ER0; 

        set_pwm1_duty(duty);    // Set output duty cycle 

        // Housekeeping 
        // Check temperature flag and if overheated sound a buzzer 
        // Reset buzzer if temperature flag resets 
        if (input(OVERHEATED)) 
            output_bit(ALARM, 1); 
        else 
            output_bit(ALARM, 0); 
        // Additional tasks 
        // Enter Tasks here 
        // ... 
    } 
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -