- UID
- 373967
- 帖子
- 9008
- 主題
- 2609
- 精華
- 0
- 積分
- 1003
- 楓幣
- 0
- 威望
- 980
- 存款
- 35891
- 贊助金額
- 0
- 推廣
- 0
- GP
- 1205
- 閱讀權限
- 70
- 在線時間
- 460 小時
- 註冊時間
- 2023-1-12
- 最後登入
- 2024-12-22
|
製作PID系統所需的零件:
PIC18F4550 微控制器
16x2 字元LCD 液晶顯示器
輸入裝置,如電位計或光感測器
輸出裝置,如電機或LED
電源供應器
電晶體、電容、電阻、二極體等元件
PIC18F4550有40個腳位,其中一些腳位需要與其他元件連接,以下是與PID系統相關的腳位:
RA0 - 輸入訊號
RA1 - 輸入訊號
RA2 - 輸入訊號
RA3 - 輸入訊號
RB0 - 輸出訊號
RB1 - 輸出訊號
RB2 - 輸出訊號
RB3 - 輸出訊號
RB4 - 輸出訊號
RB5 - 輸出訊號
RB6 - 輸出訊號
RB7 - 輸出訊號
RC0 - LCD 顯示器
RC1 - LCD 顯示器
RC2 - LCD 顯示器
RC3 - LCD 顯示器
RC4 - LCD 顯示器
RC5 - LCD 顯示器
VDD - 電源正極
VSS - 電源負極
PID控制器的程式碼:
以下是PID控制器的範例程式碼,可作為參考使用:
// Include libraries
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
// Configuration bits
#pragma config FOSC = INTOSCIO // Internal oscillator
#pragma config WDTEN = OFF // Watchdog timer off
#pragma config LVP = OFF // Low voltage programming off
// Define constants
#define _XTAL_FREQ 8000000 // Set oscillator frequency
#define Kp 1.0 // Proportional gain
#define Ki 0.5 // Integral gain
#define Kd 0.2 // Derivative gain
#define SETPOINT 100 // Desired setpoint
// Declare variables
int error = 0;
int previous_error = 0;
int integral = 0;
int derivative = 0;
int output = 0;
// Function prototypes
void init_pwm();
void init_adc();
void init_lcd();
int read_adc();
void write_lcd(char* str);
void compute_pid();
void main() {
// Initialize peripherals
init_pwm();
init_adc();
init_lcd();
while (1) {
// Read ADC value
int value = read_adc();
// Compute PID
error = SETPOINT - value;
compute_pid();
// Set PWM duty cycle
CCPR1= output;
}
}
// Initialize PWM module
void init_pwm() {
TRISCbits.TRISC2 = 0; // Set RC2 as output
PR2 = 249; // Set period to 1ms (Fosc/4/((PR2+1)*32))
T2CONbits.T2CKPS = 0b11; // Set prescaler to 1:32
T2CONbits.TMR2ON = 1; // Turn on Timer2
CCP1CONbits.CCP1M = 0b1100; // Set CCP1 as PWM mode
CCP1CONbits.DC1B = 0; // Set LSBs of PWM duty cycle to 0
}
// Initialize ADC module
void init_adc() {
TRISA = 0xFF; // Set PORTA as input
ADCON0bits.ADON = 1; // Turn on ADC module
ADCON1bits.ADFM = 1; // Set result format to right justified
ADCON1bits.ADCS = 0b101; // Set conversion clock to Fosc/16
}
// Initialize LCD module
void init_lcd() {
TRISCbits.TRISC0 = 0; // Set RC0 as output
TRISCbits.TRISC1 = 0; // Set RC1 as output
TRISDbits.TRISD0 = 0; // Set RD0 as output
TRISDbits.TRISD1 = 0; // Set RD1 as output
TRISDbits.TRISD2 = 0; // Set RD2 as output
TRISDbits.TRISD3 = 0; // Set RD3 as output
TRISDbits.TRISD4 = 0; // Set RD4 as output
TRISDbits.TRISD5 = 0; // Set RD5 as output
__delay_ms(100); // Wait for LCD to power up
PORTCbits.RC0 = 0; // Set RS to command mode
PORTCbits.RC1 = 0; // Set RW to write mode
PORTDbits.RD4 = 1; // Set DB4 to 1
PORTDbits.RD5 = 1; // Set DB5 to 1
PORTDbits.RD6 = 0; // Set DB6 to 0
PORTDbits.RD7 = 0; // Set DB7 to 0
PORTDbits.RD2 = 1; // Enable display
__delay_us(1); // Wait for enable pulse width
PORTDbits.RD2 = 0; // Disable display
__delay_us(40); // Wait for command execution time
// Set function mode (8-bit, 2-line, 5x7 font)
PORTCbits.RC0 = 0; // Set RS to command mode
PORTCbits.RC1 = 0; // Set RW to write mode
PORTDbits.RD4 = 0; // Set DB4 to 0
PORTDbits.RD5 = 0; // Set DB5 to 0
PORTDbits.RD6 = 1; // Set DB6 to 1
PORTDbits.RD7 = 0; // Set DB7 to 0
PORTDbits.RD2 = 1; // Enable display
__delay_us(1); // Wait for enable pulse width
PORTDbits.RD2 = 0; // Disable
__delay_us(40); // Wait for command execution time
// Set display on/off control (display on, cursor off, blink off)
PORTCbits.RC0 = 0; // Set RS to command mode
PORTCbits.RC1 = 0; // Set RW to write mode
PORTDbits.RD4 = 0; // Set DB4 to 0
PORTDbits.RD5 = 0; // Set DB5 to 0
PORTDbits.RD6 = 0; // Set DB6 to 0
PORTDbits.RD7 = 0; // Set DB7 to 0
PORTDbits.RD2 = 1; // Enable display
__delay_us(1); // Wait for enable pulse width
PORTDbits.RD2 = 0; // Disable display
__delay_us(40); // Wait for command execution time
// Set entry mode (increment cursor, no display shift)
PORTCbits.RC0 = 0; // Set RS to command mode
PORTCbits.RC1 = 0; // Set RW to write mode
PORTDbits.RD4 = 0; // Set DB4 to 0
PORTDbits.RD5 = 0; // Set DB5 to 0
PORTDbits.RD6 = 0; // Set DB6 to 1
PORTDbits.RD7 = 1; // Set DB7 to 0
PORTDbits.RD2 = 1; // Enable display
__delay_us(1); // Wait for enable pulse width
PORTDbits.RD2 = 0; // Disable display
__delay_us(40); // Wait for command execution time
// Clear display and return cursor to home position
PORTCbits.RC0 = 0; // Set RS to command mode
PORTCbits.RC1 = 0; // Set RW to write mode
PORTDbits.RD4 = 0; // Set DB4 to 0
PORTDbits.RD5 = 0; // Set DB5 to 0
PORTDbits.RD6 = 0; // Set DB6 to 0
PORTDbits.RD7 = 1; // Set DB7 to 0
PORTDbits.RD2 = 1; // Enable display
__delay_us(1); // Wait for enable pulse width
PORTDbits.RD2 = 0; // Disable display
__delay_us(1640); // Wait for command execution time
}
// Convert ADC result to temperature in Celsius
float adc_to_temperature(unsigned int adc_result) {
float voltage = adc_result * 5.0 / 1023.0; // Convert ADC result to voltage
float temperature = (voltage - 0.5) * 100.0; // Convert voltage to temperature
return temperature;
}
int main() {
init_pwm(); // Initialize PWM module
init_adc(); // Initialize ADC module
init_lcd(); // Initialize LCD module
float Kp = 20; // Proportional gain
float Ki = 1; // Integral gain
float Kd = 50; // Derivative gain
float setpoint = 25; // Setpoint temperature
float error = 0; // Error term
float integral = 0; // Integral term
float derivative = 0; // Derivative term
float last_error = 0; // Last error term for derivative term calculation
float pid_output = 0; // PID output
while (1) {
// Read temperature sensor and convert result to temperature in Celsius
unsigned int adc_result = read_adc();
float temperature = adc_to_temperature(adc_result);
// Calculate error term
error = setpoint - temperature;
// Calculate integral term (discrete approximation using trapezoidal rule)
integral += (error + last_error) / 2.0 * 0.1; // Sampling time = 100 ms
// Calculate derivative term (discrete approximation using backward difference)
derivative = (error - last_error) / 0.1; // Sampling time = 100 ms
// Calculate PID output
pid_output = Kp * error + Ki * integral + Kd * derivative;
// Limit PID output to PWM duty cycle range (0-100%)
if (pid_output > 100) {
pid_output = 100;
} else if (pid_output < 0) {
pid_output = 0;
}
// Update PWM duty cycle
CCPR1L = (unsigned char)(pid_output * 2.55); // Convert percentage to PWM duty cycle
// Update LCD display
char buffer[16]; // Buffer for LCD display
sprintf(buffer, "Temp: %3.1f C", temperature);
lcd_set_cursor(0, 0);
lcd_write_string(buffer);
sprintf(buffer, "Setpoint: %3.1f C", setpoint);
lcd_set_cursor(0, 1);
lcd_write_string(buffer);
// Update last error term for next iteration
last_error = error;
__delay_ms(100); // Wait for next iteration
}
return 0;
} |
|