PIC16F887
PIC16F887是一款8位元微控制器,支援多種通訊介面和多種週邊裝置,如計時器、計數器和類比數位轉換器等。下面是使用PIC16F887製作PID控制器所需的零件和相關連結腳位:
PIC16F887微控制器
LCD 16x2顯示器
電位計
電位計電路
電源供應器
USB TTL轉換器
以下是PID控制器的程式碼,您可以根據自己的需要進行修改:
#include <xc.h>
// 設定運算時脈頻率
#pragma config FOSC = INTOSCIO // 內部振盪器
#pragma config WDTE = OFF // 監看狗定時器關閉
#pragma config PWRTE = ON // 延時器啟動
#pragma config BOREN = OFF // 失壓檢測關閉
#pragma config LVP = OFF // 能量驅動程式關閉
// 設定顯示器腳位
#define RS RB0
#define EN RB1
#define D4 RB2
#define D5 RB3
#define D6 RB4
#define D7 RB5
// 設定PID參數
#define Kp 1.0
#define Ki 0.5
#define Kd 0.2
// 宣告變數
int set_point, current_point, error, last_error, integral, derivative, output;
// 設定計時器初值
void timer_init() {
T1CONbits.T1CKPS = 0b11; // 設定計時器時脈頻率為1/8
T1CONbits.TMR1ON = 1; // 啟動計時器
}
// 讀取電位計數值
int read_pot() {
ADCON0bits.ADON = 1; // 啟動類比轉換器
ADCON0bits.CHS = 0b0000; // 選擇AN0通道
__delay_us(5); // 等待轉換完成
ADCON0bits.GO_nDONE = 1; // 開始進行轉換
while (ADCON0bits.GO_nDONE); // 等待轉換完成
return ADRESH << 8 | ADRESL; // 返回轉換結果
}
// 初始化LCD顯示器
void lcd_init() {
TRISB = 0x00; // 設定RB0-RB5腳位為輸出模式
__delay_ms(100); // 等待LCD初始化完成
LCD_command(0x02); // 將光標移至左上角
LCD_command(0x28); // 選擇16x2顯示模
LCD_command(0x0C); // 顯示器開啟,光標隱藏
LCD_command(0x06); // 光標自動右移
LCD_command(0x01); // 清除顯示器內容
}
// 傳送命令給LCD顯示器
void LCD_command(unsigned char cmd) {
RS = 0; // 選擇命令模式
PORTB = (cmd >> 4) & 0x0F; // 傳送高4位元
EN = 1; // 啟動顯示器
__delay_us(1); // 延時1微秒
EN = 0; // 關閉顯示器
PORTB = cmd & 0x0F; // 傳送低4位元
EN = 1; // 啟動顯示器
__delay_us(1); // 延時1微秒
EN = 0; // 關閉顯示器
__delay_us(100); // 延時100微秒
}
// 傳送資料給LCD顯示器
void LCD_data(unsigned char data) {
RS = 1; // 選擇資料模式
PORTB = (data >> 4) & 0x0F; // 傳送高4位元
EN = 1; // 啟動顯示器
__delay_us(1); // 延時1微秒
EN = 0; // 關閉顯示器
PORTB = data & 0x0F; // 傳送低4位元
EN = 1; // 啟動顯示器
__delay_us(1); // 延時1微秒
EN = 0; // 關閉顯示器
__delay_us(100); // 延時100微秒
}
// 將整數轉換為字串
void int_to_string(int num, char* str) {
int i, sign;
if ((sign = num) < 0) // 處理負數
num = -num;
i = 0;
do {
str = num % 10 + '0'; // 取最後一位數字
} while ((num /= 10) > 0); // 移除最後一位數字
if (sign < 0) // 如果是負數,加上負號
str = '-';
str = '\0'; // 加上結束符號
// 反轉字串
int j = 0, k = i - 1;
while (j < k) {
char temp = str;
str = str;
str = temp;
j++;
k--;
}
}
// 主程式
void main() {
OSCCON = 0b01110010; // 設定內部振盪器頻率為8MHz
ANSEL = 0b00000001; // 設定AN
TRISA = 0b00000001; // 設定RA0為輸入
TRISB = 0b00000000; // 設定RB為輸出
TRISC = 0b00000000; // 設定RC為輸出
PORTB = 0b00000000; // 初始值為0
PORTC = 0b00000000; // 初始值為0
// 初始化LCD顯示器
LCD_init();
// 設定PID控制器參數
double Kp = 1.0, Ki = 0.5, Kd = 0.2;
double setpoint = 25.0; // 目標溫度
double dt = 0.1; // 取樣時間
double error, last_error, integral = 0, derivative, output;
double temp, voltage;
int adc_value;
char str;
// 設定ADC模組
ADCON0 = 0b00000001; // 選擇AN0輸入,啟動ADC模組
ADCON1 = 0b00000000; // 右對齊,選擇Vref+為VDD,Vref-為VSS
__delay_us(10); // 等待ADC模組啟動完成
while (1) {
// 讀取溫度值
ADCON0bits.GO = 1; // 啟動ADC轉換
while (ADCON0bits.GO); // 等待ADC轉換完成
adc_value = ADRESH << 8 | ADRESL; // 組合ADC轉換結果
voltage = adc_value * 5.0 / 1024.0; // 轉換為電壓
temp = (voltage - 0.5) * 100.0; // 轉換為溫度
error = setpoint - temp; // 計算誤差
integral += error * dt; // 累計積分
derivative = (error - last_error) / dt; // 計算微分
output = Kp * error + Ki * integral + Kd * derivative; // 計算控制輸出
last_error = error; // 儲存上一次誤差值
// 限制控制輸出在0到5V之間
if (output > 5.0)
output = 5.0;
else if (output < 0)
output = 0;
// 設定PWM
CCP1CONbits.DC1B = ((int)(output / 0.0195)) & 0x03;
CCPR1L = (int)(output / 0.0195) >> 2;
// 顯示溫度和控制輸出值
LCD_command(0x80); // 設定顯示器光標位置
LCD_data('T');
LCD_data('e');
LCD_data('m');
LCD_data('p');
LCD_data(':');
sprintf(str, "%3.1f", temp);
LCD_string(str);
LCD_data(0xDF); // 顯示溫度符號
LCD_data('C');
LCD_command(0xC0); // 設定顯示器光標位置
LCD_data('O');
LCD_data('u');
LCD_data('t');
LCD_data('p');
LCD_data('u');
LCD_data('t');
LCD_data(':');
sprintf(str, "%3.1f", output);
LCD_string(str);
LCD_data('V');
__delay_ms(100); // 等待100ms
}
}
以上是一個簡單的PID控制器的範例,使用PIC16F887微控制器控制一個PWM輸出,用於控制加熱器的溫度。
程式碼中包含了設定IO腳位、LCD顯示器、ADC模組和PID控制器參數的部分,以及控制輸出和顯示溫度和控制輸出值的主要部分。
建議使用相關的開發板或模擬器進行實際的測試和調試。
頁:
[1]