- UID
- 373967
- 帖子
- 8844
- 主題
- 2609
- 精華
- 0
- 積分
- 999
- 楓幣
- 0
- 威望
- 976
- 存款
- 34672
- 贊助金額
- 0
- 推廣
- 0
- GP
- 1205
- 閱讀權限
- 50
- 在線時間
- 453 小時
- 註冊時間
- 2023-1-12
- 最後登入
- 2024-11-17
|
製作使用PIC16F877A微控制器的PID控制器
需要以下零件:
PIC16F877A微控制器
LCD顯示器
4x4矩陣按鈕
轉換器(例如:ADC0804)
電阻和電容(用於製作低通濾波器和電源電路)
直流電源供應器
電路板
電路連接線
訊號發生器
以下是PIC16F877A微控制器的腳位連結:
RA0 – 轉換器輸入
RA1 – 轉換器輸入
RA2 – 轉換器輸入
RA3 – 轉換器輸入
RA4 – 轉換器輸入
RA5 – 鍵盤輸入
RA6 – LCD顯示器數據線
RA7 – LCD顯示器數據線
RB0 – 轉換器輸入
RB1 – 轉換器輸入
RB2 – 轉換器輸入
RB3 – 轉換器輸入
RB4 – LCD顯示器選擇器
RB5 – LCD顯示器選擇器
RB6 – LCD顯示器選擇器
RB7 – LCD顯示器選擇器
RC0 – LCD顯示器使能信號
RC1 – LCD顯示器使能信號
RC2 – LCD顯示器使能信號
RC3 – LCD顯示器使能信號
RC4 – 訊號發生器輸入
RC5 – 訊號發生器輸入
RC6 – 訊號發生器輸入
RC7 – 訊號發生器輸入
以下是PID控制器的基本程式碼,可在MPLAB IDE中編譯和上傳到PIC16F877A微控制器中:
#include <pic.h>
#define RS RC0
#define EN RC1
#define D4 RC2
#define D5 RC3
#define D6 RC4
#define D7 RC5
#define Kp 1.0
#define Ki 0.5
#define Kd 0.2
void lcd_init();
void lcd_cmd(unsigned char);
void lcd_data(unsigned char);
void lcd_string(unsigned char *);
void delay_ms(unsigned int);
unsigned char read_adc(unsigned char);
void main() {
unsigned char setpoint = 0, process_variable = 0, error = 0, previous_error = 0;
float integral = 0, derivative = 0, output = 0;
char buffer[16];
A0 = 1; // 將A/D轉換器輸入通道設置為RA0
A1 = 1;
A2 = 1;
A3 = 1;
A4 = 1;
TRISB = 0xF0; // 設置RB0-RB3為輸入,RB4-RB7為輸出
TRISC = 0x00; // 設置RC0-RC7為輸出
lcd_init(); // 初始化LCD顯示器
while(1) {
// 讀取設定點和過程變量
setpoint = read_adc(0);
process_variable = read_adc(1);
// 計算誤差和積分
error = setpoint - process_variable;
integral += error;
derivative = error - previous_error;
previous_error = error;
// 計算PID輸出
output = Kp * error + Ki * integral + Kd * derivative;
// 顯示PID輸出和其他信息
lcd_cmd(0x01); // 清屏
lcd_string("Setpoint: ");
sprintf(buffer, "%d", setpoint);
lcd_string(buffer);
lcd_cmd(0xC0); // 移到第二行
lcd_string("PV: ");
sprintf(buffer, "%d", process_variable);
lcd_string(buffer);
lcd_string(" ");
lcd_cmd(0x94); // 移到第三行
lcd_string("Output: ");
sprintf(buffer, "%.2f", output);
lcd_string(buffer);
delay_ms(1000); // 延遲1秒
}
}
void lcd_init() {
lcd_cmd(0x02); // 返回首位
lcd_cmd(0x28); // 4位數據線,2行顯示,5x8點陣字型
lcd_cmd(0x0C); // 顯示器開啟,光標不顯示
lcd_cmd(0x06); // 光標右移,字符不移動
}
void lcd_cmd(unsigned char cmd) {
RS = 0; // 選擇命令模式
D4 = ((cmd >> 4) & 0x01);
D5 = ((cmd >> 5) & 0x01);
D6 = ((cmd >> 6) & 0x01);
D7 = ((cmd >> 7) & 0x01);
EN = 1;
delay_ms(1);
EN = 0;
D4 = (cmd & 0x01);
D5 = ((cmd >> 1) & 0x01);
D6 = ((cmd >> 2) & 0x01);
D7 = ((cmd >> 3) & 0x01);
EN = 1;
delay_ms(1);
EN = 0;
}
void lcd_data(unsigned char data) {
RS = 1; // 選擇數據模式
D4 = ((data >> 4) & 0x01);
D5 = ((data >> 5) & 0x01);
D6 = ((data >> 6) & 0x01);
D7 = ((data >> 7) & 0x01);
EN = 1;
delay_ms(1);
EN = 0;
D4 = (data & 0x01);
D5 = ((data >> 1) & 0x01);
D6 = ((data >> 2) & 0x01);
D7 = ((data >> 3) & 0x01);
EN = 1;
delay_ms(1);
EN = 0;
}
void lcd_string(char *str) {
while(*str) {
lcd_data(*str++);
}
}
int read_adc(unsigned char channel) {
unsigned int result;
ADCON0 = (channel << 2) | 0x01; // 選擇通道,啟動A/D轉換器
delay_us(10);
GO_DONE = 1; // 啟動轉換
while(GO_DONE); // 等待轉換完成
result = ADRESH;
result = (result << 8) | ADRESL;
return result;
}
void delay_ms(unsigned int ms) {
unsigned int i, j;
for(i = 0; i < ms; i++) {
for(j = 0; j < 1000; j++);
}
}
void delay_us(unsigned int us) {
unsigned int i;
for(i = 0; i < us; i++) {
_delay(5); // 使用5個指令進行延遲
}
}
void _delay(unsigned char n) {
while(n--);
}
最後是PID控制器的主要程式碼:
void pid_control() {
int current_value = read_adc(0); // 讀取目前的測量值
int error = set_point - current_value; // 計算誤差值
integral += error; // 累加誤差值
int derivative = error - last_error; // 計算誤差變化率
last_error = error; // 更新上一次的誤差值
int output = Kp * error + Ki * integral + Kd * derivative; // 計算輸出值
output = constrain(output, 0, 255); // 限制輸出值在0~255之間
PWM = output; // 設定PWM輸出
}
上述程式碼中的read_adc函式會讀取ADC轉換器的值,這個值是模擬信號經過轉換器轉換後得到的數字,代表著模擬信號的大小。
接下來計算誤差值、累加誤差值、計算誤差變化率,並根據PID公式計算輸出值。
最後將輸出值限制在0~255之間,並設定PWM輸出。 |
|