Nhiệm vụ bộ PID :
· Nếu sai lệch e(t) chưa bằng 0 thì qua thành phần tích phân , tín hiệu
điều chỉnh vẫn được bộ PID tạo ra.
· Nếu sự thay đổi của e(t) càng lớn do
khâu tích phân hiệu chỉnh
làm tăng độ sai số lên, thông qua thành phần vi phân phản ứng
thích hợp của u(t) sẽ càng nhanh.
Cách tính giải hệ thống PID ra hàm truyền toán học
Chọn
Kp trước: thử bộ điều khiển P với đối tượng thật (hoặc mô phỏng), điều chỉnh Kp
sao cho thời gian đáp ứng đủ nhanh, chấp nhận overshot nhỏ.
Thêm thành phần
D để loại vọt lố, tăng Kd từ từ, thử
nghiệm và chọn giá trị thích hợp. Giá trị sai số có thể sẽ xuất hiện.
Thêm
thành phần I để giảm giá trị sai số . Nên tăng Ki từ bé đến lớn để giảm giá
trị sai số đồng thời không để cho vọt lố xuất hiện trở lại.
Phần 1: Code CCS
Mã CCS:
#include <PIDtocdodongco.h>
/* Phan Hoang Thinh MSSV:
14130721 */
// # include <16F887.h>
#fuses HS NOWDT, NOPROTECT, NOLVP, NOBROWNOUT
// # sử dụng fast_io (d)
#include <string.h>
#include <stdlib.h>
#include <math.h>
// # include <lcd.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
// # sử dụng delay (clock = 20000000)
RS232 #use (baud = 9600, parity = N, xmit = PIN_C6, RCV = PIN_C7, bit = 8)
//DINH NGHIA CAC CHAN
NUT NHAN HOAC 02 CHAN ENCODER
#define SW1 PIN_B0
//NGAT NGOAI
#define SW2 PIN_B4
//DINH NGHIA CHAN TU
CAM BIEN LM35
#define LM35 PIN_A1
//DINH NGHIA CHAN DIEU
KHIEN DONG CO DUNG L298
#define DIR1 PIN_C0 // IN1
#define PWM PIN_C2
//CHAN DIEU RONG XUNG, ENA
#define dir2 PIN_C1 // IN2
//DINH NGHIA CAC
BIEN
//BIEN NHAN DU LIEU
unsigned int16 saisoKp = 0, saisoKi = 0;
nổi xoa_saiso, tong_saiso;
unsigned int16 saisoKp1 = 0, saisoKi1 = 0;
float
xoa_saiso1,tong_saiso1;
char
c_start,c_stop,c_tem; //bien tam luu ma bat dau và ket thúc
char s1[9]; //bi?n t?m
luu d? li?u nh?n du?c t? máy tính
int k; // bi? N ch? S? cho m? ng d? li? u nh? n du? c
int biennhan; // bi?n
báo hi?u dã nh?n d? li?u xong
// int bien_goidongco;
// MOTOR BIÊN MA
char smthuan [] = "mt"; // dongcoquaythuan
int co_thuan; // bi?n
báo tr?ng thái d?ng co quay thu?n
char smnghich [] = "mn"; // dongcoquaynghich
int co_nghich; //bi?n
báo tr?ng thái d?ng co quay ngh?ch
char smstop [] = "ms"; // dongcongungchay
// luu y: neu nhan ma
@td+"xxx"+x
char smpwm [] = "td"; // ma_nap_pwm
// PID
char ppid [] = "kp"; // ma Kp
char ipid [] = "ki"; // ma Ki
char dpid [] = "kd"; // ma Kd
//Bien luu PID
long sppid;
long sipid;
long sdpid;
// CŨNG PWM
long ppwm; // bi?n luu
giá tr? %PWM nh?n du?c t? máy tính
int ngat;//báo tr?ng
thái ng?t ngoài
int dem_t; // bi? N luu s? l? nd? m timer1
///////////////////////////////////////////////////////////////////////////////
//CHUONG TRINH NGAT
RS232
//NEU DUNG MA SE LUU
VAO S1, BIEN NHAN = 1,
//NEU KHONG DUNG MA
BIEN NHAN = 0
#int_rda
khoảng trống RDA_isr (void)
{
c_tem=getc();//NHAN TUNG KI TU
if (c_tem == '@') // xet ki tu bat dau "@"
{
c_start = c_tem;
k = 0;
s1 [k] = c_start;
}
if (c_tem=='x') //xet ki tu ket thuc
"x"
{
c_stop = c_tem;
s1 [k] = c_stop;
}
if (c_start == '@' && c_stop == 'x')
{
k = 0;
biennhan=1;//bao hieu da nhan dung ma
dau-cuoi
c_start = 0;
c_stop = 0;
}
khác
{
s1[k]=c_tem;
a ++;
if (k> = 9) {k = 0;}
}
}
///////////////////////////////////////////////////////////////////////////////
//NGAT TIMER 1
# INT_TIMER1
khoảng trống ngattimer1 ()
{
// timer: DIV_BY_8
set_timer1(4856); //
timer bat dau dem tu 4856 tuc la:
//// 4*8*[(2^16-1)-4856]
// T_interrupt = ----------------------- x 1 = 97 ms
// 20MHz
dem_t++; //moi lan
tang khi timer 1 tran, tuong ung voi 100.000 us
}
///////////////////////////////////////////////////////////////////////////////
//CHUONG TRINH DIEU
KHIEN MOTOR
//CHUONG TRINH NHAN
%PWM TU MAY TINH
/****************************************************************/
khoảng trống nappwm ()
{
char SPWM [3];
spwm[0]=s1[4]; //lay
giá tri %PWM tu bien nhan theo quy dinh
SPWM [1] = s1 [5];
SPWM [2] = s1 [6];
PWM = atoi (PWM);
printf ( "% s% Lu% s \ n \ r", "@ Toc làm:", ppwm, "% x"); // gui PWM%
}
/****************************************************************/
làm mất hiệu lực napKp ()
{
ppid char [4];
ppid[0]=s1[4]; //lay
giá tri %PWM tu bien nhan theo quy dinh
PPID [1] = S1 [5];
PPID [2] = S1 [6];
AppID = atoi (PID);
// sppid = (float) ppid;
printf ( "% s% Lu% s \ n \ r", "@ Kp:", sppid, "x"); // gui PWM%
}
/****************************************************************/
làm mất hiệu lực napKi ()
{
ipid [3] char;
ipid[0]=s1[4]; //lay
giá tri %PWM tu bien nhan theo quy dinh
ipid [1] = S1 [5];
ipid [2] = S1 [6];
tẻ nhạt = atoi (ipid);
printf ( "% s% Lu% s \ n \ r", "@ Ki:", sipid, "x"); // gui PWM%
}
/****************************************************************/
làm mất hiệu lực napKd ()
{
char dpid [3];
dpid[0]=s1[4]; //lay
giá tri %PWM tu bien nhan theo quy dinh
dpid [1] = S1 [5];
dpid [2] = S1 [6];
sdpid = atoi (DPID);
printf ( "% s% Lu% s \ n \ r", "@ Kd:", sdpid, "x"); // gui PWM%
}
/***************Chuong
trinh tinh PID********************/
/*************************************************************/
//CHUONG TRINH MOTOR
STOP
khoảng trống motostop ()
{
set_pwm1_duty (0);
// output_bit (PWM, 0);
output_bit(DIR1,0); //
motor ngung khi Dir 1 và 2 = 0
output_bit (DIR2,0);
setup_ccp1 (CCP_OFF); // Ngung xu t PWM?
co_thuan=0; //reset
tr?ng thái ch?y thu?n ngh?ch
co_nghich=0;
printf ( "% s \ n \ r", "@ mstopx");
nổi stop_DC = 0;
printf ( "% s% 3.0f% s \ n \ r", "@ PID", stop_DC, "x");
}
//CHUONG TRINH MOTOR
CHAY THUAN
khoảng trống quaythuan ()
{
nổi pwm_t;
// nổi tinhpid; F = Kp * err +
pwm_t=(float)ppwm*512/100;
//xung do 100% PWM thi duoc 512.0
// tinhpid = (float) sppid * pwm_t;
setup_ccp1(CCP_PWM);
//cho phep xuat PWM kenh 1
output_bit (DIR1,1); // ch? N hu? Ng quay
output_bit (DIR2,0);
set_pwm1_duty ((int16) pwm_t);
// nổi = set_pwm1_duty ((int16) pwm_t) hihi;
nổi tocdo_pid;
nổi tocdo_t = (pwm_t * 60F) / 100; // 307
nổi tocdo = (pwm_t * 60F) / 102; // 301
/****************************************************************/
nổi kpt_t, kit_t, kdt_t;
kpt_t = (float) (sppid) / 100; // 40
kit_t = (float) (sipid) / 100; // 5
kdt_t=(float)(sdpid)/100;//0
saisoKp = saisoKi;
saisoKi = tocdo_t-tocdo;
xoa_saiso = saisoKi-saisoKp;
tong_saiso = saisoKp + saisoKi;
nổi ab, ac, quảng cáo;
ab = kpt_t * saisoKi;
ac = kit_t * tong_saiso;
ad=kdt_t*xoa_saiso;
tocdo_pid = tocdo + ab + ac + quảng cáo;
/****************************************************************/
// set_pwm1_duty ((int16) pwm_t); // nap xung PWM
co_thuan=1;
printf ( "% s \ n \ r", "@ mthuanx");
/**************************/
// xungthinh = set_pwm1_duty ((int32) pwm_t); // nap xung PWM
// printf ( "% s% f% s \ r \ n", "@ DC", saisoKi, "x"); // vong / giay
printf ( "% s +% 3.0f% s \ n \ r", "@ PID", tocdo_pid, "x");
printf ( "% s +% 3.0f% s \ r \ n", "@ DC", tocdo, "x"); // vong / giay
// printf ( "% s +% 3.0f% s \ n \ r", "@ PID", tocdo_t, "x");
/*****************************/
}
//CHUONG TRINH MOTOR
CHAY THUAN
khoảng trống quaynghich ()
{
nổi pwm_n;
pwm_n = (float) ppwm * 512/100;
setup_ccp1 (CCP_PWM);
output_bit (DIR1,0);
output_bit (DIR2,1);
set_pwm1_duty ((int16) pwm_n);
nổi tocdo1_pid;
nổi tocdo_n = (pwm_n * 60F) / 100; // 307
nổi tocdo_dat = (pwm_n * 60F) / 102; // 301
/****************************************************************/
saisoKp1 = saisoKi1;
saisoKi1 = tocdo_n-tocdo_dat;
xoa_saiso1 = saisoKi1-saisoKp1;
tong_saiso1 = saisoKp1 + saisoKi1;
nổi kpn_t;
nổi kin_t;
kdn_t nổi;
kpn_t = (float) (sppid) / 100; // 40
kin_t = (float) (sipid) / 100; // 5
kdn_t = (float) (sdpid) / 100; // 0
nổi AB1, AC1, AD1;
AB1 = kpn_t * saisoKi1;
AC1 = kin_t * tong_saiso1;
ad1=kdn_t*xoa_saiso1;
tocdo1_pid = tocdo_dat AC1 + + + AB1 AD1;
/*********************************************************************/
co_nghich=1;
printf ( "% s \ n \ r", "@ mnghichx");
/****************************/
// nổi tocdo = (pwm_n * 60F) / 100;
printf ( "% s -% 3.0f% s \ r \ n", "@ PID", tocdo1_pid, "x"); // vong / giay
printf ( "% s -% 3.0f% s \ r \ n", "@ DC", tocdo_dat, "x"); // vong / giay
/***********************/
}
///////////////////////////////////////////////////////////////////////////////
//CHUONG TRINH XOA
BIEN NHAN
khoảng trống xoanhan ()
{
int j;
for (j = 0; j <= 9; j ++) {s1 [j] = 0;}
}
///////////////////////////////////////////////////////////////////////////////
//CHUONG TRINH CON XET
MA NHAN DUOC
khoảng trống xetma ()
{
if ((biennhan) && (Ngát == 0))
{
if (strncmp (strstr (s1, smthuan), smthuan, 2) == 0) {quaythuan ();} // nau = “mt”
if (strncmp (strstr (s1, smnghich), smnghich, 2) == 0) {quaynghich ();} // nau = “mn”
if (strncmp (strstr (s1, smstop), smstop, 2) == 0) {motostop ();} // nau = “ms”
if (strncmp (strstr (s1, smpwm), smpwm, 2) == 0) // nau = “td”
{Nappwm ();}
if (strncmp (strstr (s1, ppid), ppid, 2) == 0) // nau = “kp”
{NapKp ();}
if (strncmp (strstr (S1, ipid), ipid, 2) == 0) // con = "ki"
{NapKi ();}
if (strncmp (strstr (s1, dpid), dpid, 2) == 0) // nau = “kd”
{NapKd ();
if (co_thuan) {quaythuan ();}
if (co_nghich)
{quaynghich();}
}
xoanhan();
biennhan = 0;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//CHUONG TRINH CHINH
void main ()
{
ext_int_edge(H_TO_L );
//quy dinh ngat ngoài tích cuc muc thap = canh xuong
enable_interrupts(INT_RDA);//cho
phep ngat truyen thong
enable_interrupts(INT_TIMER1);
// cho phép ngat timer1
enable_interrupts(GLOBAL);
//cho phép ngat toàn cuc
setup_timer_2(T2_DIV_BY_16,127,1);//cài
dat timer2
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8); // cài dat timer1
set_timer1 (4865);
delay_ms (10);
while (true)
{
xetma();//goi chuong
trình xét mã nhan duoc tu máy tính
}
}
Giao diện Visual Basic :
Mã Visual:
nhập khẩu Hệ thống
nhập khẩu System.ComponentModel
nhập khẩu System.IO.Ports
Công Lớp Form_PidDongCo
không bodemnhan
không tocdo
Dim tocdo_pid
Private Sub Form_PidDongCo_Load (người gửi Như Object , e Như EventArgs ) Xử lý MyBase Load
Baotrangthai.Text = "Mời bạn mở cổng COM"
MoCongCOM.Enabled = Đúng
DongCOM.Enabled = False
goi.Enabled = False
Nhan.Enabled = False
End Sub
Private Sub MoCongCOM_Click (người gửi Như Object , e Như EventArgs ) Xử lý MoCongCOM.Click
Nếu (SerialPort1.IsOpen) Sau đó,
Exit Sub
End If
với SerialPort1
.PortName = "COM1"
.BaudRate = 9600
.Parity = IO.Ports. chẵn lẻ .None
.StopBits = IO.Ports. StopBits .Một
.DataBits = 8
.ReceivedBytesThreshold = 1
End Với
Thử
SerialPort1.Open ()
MoCongCOM.Enabled = False
DongCOM.Enabled = Đúng
goi.Enabled = Đúng
Nhan.Enabled = True
Baotrangthai.Text = "Cổng COM đã mở"
Catch ex Như ngoại lệ
End Try
End Sub
Private Sub DongCOM_Click (người gửi Như Object , e Như EventArgs ) Xử lý DongCOM.Click
SerialPort1.Close ()
MoCongCOM.Enabled = Đúng
DongCOM.Enabled = False
goi.Enabled = False
Nhan.Enabled = False
Baotrangthai.Text = "Mời bạn mở cổng COM"
End Sub
Private Sub Thoat_Click(sender As Object, e As EventArgs) Handles Thoat.Click
If MsgBox("Bạn có muốn thoát khỏi chương
trình?",
MsgBoxStyle .YesNo + MsgBoxStyle .Question, "Exit" ) =
MsgBoxResult .Yes Sau đó,
Gần()
EndIf
End Sub
Private Sub DataReceived (người gửi Như Object , e Như SerialDataReceivedEventArgs ) Xử lý SerialPort1.DataReceived
Dim v_start Như Integer
Dim v_stop Như Integer
Dim v_tocdopid Như Integer
Dim v_tocdo Như Integer
Thử
CheckForIllegalCrossThreadCalls = False
bodemnhan + = SerialPort1.ReadExisting
Nếu bodemnhan.Contains ( "@" ) Sau đó,
Nếu
bodemnhan.EndsWith ( "x" ) Sau đó,
SerialPort1.DiscardInBuffer ()
v_start = bodemnhan.IndexOf ( "@" )
v_stop = bodemnhan.IndexOf ( "x" )
Nếu bodemnhan.Contains ( "PID" ) Sau đó,
v_tocdopid = bodemnhan.IndexOf ( "PID" )
tocdo_pid = bodemnhan.Substring (v_tocdopid + 3, v_stop - (v_tocdopid + 2) - 1) + "Vọng / s"
ElseIf bodemnhan.Contains ( "DC" ) Sau đó,
v_tocdo = bodemnhan.IndexOf ( "DC" )
tocdo = bodemnhan.Substring (v_tocdo + 2, v_stop - (v_tocdo + 1) - 1) + "Vọng / s"
khác
Onhansukien.Text = bodemnhan.Substring (v_start + 1, v_stop - 1 - v_start)
EndIf
bodemnhan = ""
EndIf
EndIf
Catch ex Như ngoại lệ
End Try
End Sub
Private Sub Laymau_Tick (người gửi Như Object , e Như EventArgs ) Xử lý Laymau.Tick
Thử
Nếu SerialPort1.IsOpen Sau đó,
nhandongco_pid.Text = tocdo_pid
txt_dongcothucte.Text = tocdo
EndIf
Catch ex Như ngoại lệ
End Try
End Sub
Private Sub Nhan_Click(sender As Object, e As EventArgs) Handles Nhan.Click
Laymau.Start ()
End Sub
Private Sub SetTocDo_Click (người gửi Như Object , e Như EventArgs ) Xử lý SetTocDo.Click
SerialPort1.Write ( "@ td +" + caidattocdo.Text + "x" )
End Sub
Private Sub quaynghich_Click (người gửi Như Object , e Như EventArgs ) Xử lý quaynghich.Click
SerialPort1.Write ( "@mnx" )
End Sub
Private Sub quaythuan_Click (người gửi Như Object , e Như EventArgs ) Xử lý quaythuan.Click
SerialPort1.Write ( "@mtx" )
End Sub
Private Sub button_stop_Click (người gửi Như Object , e Như EventArgs ) Xử lý button_stop.Click
SerialPort1.Write ( "@msx" )
End Sub
Private Sub Goi_pid_Click (người gửi Như Object , e Như EventArgs ) Xử lý Goi_pid.Click
SerialPort1.Write ( "@ kp +" + txt_kp.Text + "x" )
SerialPort1.Write ( "@ ki +" + txt_kp.Text + "x" )
SerialPort1.Write ( "@ kd +" + txt_kp.Text + "x" )
End Sub
Private Sub goi_Click (người gửi Như Object , e Như EventArgs ) Xử lý goi.Click
SerialPort1.Write ( "@" + ogoi.Text + "x" )
End Sub
End Lớp