PDA

View Full Version : xin giúp đỡ về chương trình PID cho pic 16f877a


mrnumb2010
07-04-2009, 12:53 PM
Hiện mình đang gặp vấn đề về chương trình điều khiển điều khiển cho mô hình đồ án. Đồ án của mình như sau : Sử dụng vi điều khiển để điều khiển nam châm điện hút một vật (có gắn nam châm vĩnh cửu) treo "lơ lửng " theo phương đứng với 1 khoảng cách cho trước.Vị trí của vật được xác định nhờ 1 cảm biến từ trường.Cảm biến này đưa về giá trị áp (tuyến tính)
tùy theo vị trí của vật dựa trên hiệu ứng hall.Khi không có từ trường thì điện áp của chân ra luôn là 50% điện áp cấp cho nó (với vdd= 5v thì áp ra là 2.5v).Khi có từng trường (nam châm vĩnh cửu gắn trên vật) thì điện áp ra sẽ thay đổi tuyến tính. Phần cứng của mình như sau:
-Mạch điều khiển : gồm có vi điều khiển pic 16f877a và các chân in/out đưa ra : chân an0 đọc giá trị analog từ cảm biến xác định khoảng cách. chân an1 đọc điện áp so sánh(là vdd của pic = 5v) .Từ việc so sánh giá trị áp này có thể xác định khoảng cách của vật cần điều khiển.
-Mạch công suất mình sử dụng con LM18200 với 3 chân điền khiển
chân brake(thắng) nối với pin 15 của pic
chân pwm nối với pin 16 (ccp2) của pic
chân direction nối với pin 18 của pic
Mình sắp xếp sao cho khi đưa vật lại gần thì áp ra của cảm biến giảm theo (giảm từ 2.5v ->0v)
Vị trí cân bằng mình set là v=1.4v (khi vật ở khoảng 1.5cm thì điện áp của cảm biến bắt đều thay đổi, nhưng do giới hạn của lực từ do nam châm điện tạo ra nên mình đặt ở khoảng cách gần hơn- nam châm điện cấp nguồn 12v)
Giải thuật của mình như sau: khi điện vật ở vị trí set thì tắt nam châm, khi vật ở xa (phía dưới) thì cho nam châm hút, khi vật lại gần thì cho nam châm đẩy.
Mình đã viết chương trình chạy thừ (dạng on/off) thì chỉ có thể treo được khoảng 2s và mất ổn định rất nhanh( vật dao động liên tục và rớt xuống) .
Vậy các bác ai có từng làm về điều khiển (theo mình nghĩ phải dùng pid) thì cho mình xin ý kiến với.Hiện giờ mình chưa làm được nên rất lo lắng.
Đây là chương trình mình đã viết bằng ccsc


#include <16F877A.h>

#fuses HS,NOWDT,NOPROTECT,NOLVP
#device ADC=8
#use delay(clock=20000000)
#use fast_IO(B)
#define max_pwm 1023
#define min_pwm 128

float k ;

float analog;

float vref;
float target;

float e;
int16 value1;
signed int16 pw_duty;


unsigned long kp =10; //he so ti le

void adc();
void pwm2(int16 value1);
void pid();

void convert();

void main()
{

while (true)
{

adc();
//doc adc
// xet dieu kien
convert ();


if ( k==0.28) // nam cham tat neu o vi tri can bang
{
output_high(PIN_C0);
output_high(PIN_C3);
pwm2(pw_duty);

}
else if (k<0.28)//nam cham day
{
output_low(PIN_C0);
output_high(PIN_C3);
pwm2(pw_duty);

}
else if (k>0.28) //nam cham hut
{
output_low(PIN_C0);
output_low(PIN_C3);
pwm2(pw_duty);
}

}

}
void pwm2(int16 value1)
{
setup_ccp2(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,255,1);
set_pwm2_duty(value1);
}

void adc()
{
Setup_ADC(ADC_clock_DIV_8);
Setup_ADC_ports(all_analog);
set_adc_channel(0);
delay_us(10);
analog=(float)read_adc();

set_adc_channel(1);
delay_us(10);
vref=(float)read_adc(); //doc gia tri ap tham khao = vdd cua pic
target = vref/2; //vi tri set
k=(analog/vref);
e = target - analog ; //sai so cua vi tri

if (e<0)
pw_duty =-kp*e;
else if (e>0)
pw_duty = (kp*e);
else
pw_duty = 0;
}
void convert()

{ if (pw_duty<min_pwm)

pw_duty = min_pwm ;

else if (pw_duty> max_pwm)

pw_duty = max_pwm ;
else

pw_duty = pw_duty;
}


Rất monh nhận đượcc sự giúp đỡ của các bác.