冰楓論壇

 找回密碼
 立即註冊
搜索
查看: 774|回覆: 0
打印 上一主題 下一主題

[討論] PIC18F4550

[複製鏈接]

2609

主題

0

好友

1003

積分

金牌會員

Rank: 6Rank: 6

UID
373967
帖子
9008
主題
2609
精華
0
積分
1003
楓幣
0
威望
980
存款
35891
贊助金額
0
推廣
0
GP
1205
閱讀權限
70
在線時間
460 小時
註冊時間
2023-1-12
最後登入
2024-12-22

2023端午節紀念勳章 2023中秋節紀念勳章 2023聖誕節紀念勳章

跳轉到指定樓層
1
發表於 2023-4-27 06:48:37 |只看該作者 |倒序瀏覽
製作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;
}
收藏收藏0 推0 噓0


把本文推薦給朋友或其他網站上,每次被點擊增加您在本站積分: 1鑰匙
複製連結並發給好友,以賺取推廣點數
簡單兩步驟,註冊、分享網址,即可獲得獎勵! 一起推廣文章換商品、賺$$
高級模式
B Color Image Link Quote Code Smilies |上傳

廣告刊登意見回饋關於我們管群招募本站規範DMCA隱私權政策

Copyright © 2011-2024 冰楓論壇, All rights reserved

免責聲明:本網站是以即時上載留言的方式運作,本站對所有留言的真實性、完整性及立場等,不負任何法律責任。

而一切留言之言論只代表留言者個人意見,並非本網站之立場,用戶不應信賴內容,並應自行判斷內容之真實性。

小黑屋|手機版|冰楓論壇

GMT+8, 2024-12-22 17:29

回頂部