洪嵐峰 發表於 2023-4-27 06:19:26

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]
查看完整版本: PIC16F887