PDA

View Full Version : Cách sử dụng nhiều ADC! giúp em


cuongthinh
07-05-2009, 04:36 PM
http://i634.photobucket.com/albums/uu70/cuongthinh/PFCBoostconverter.jpg
Em đang lập trình dsp30F4011 để thực hiện mạch này. Hiện em đang có một số vướng mắc này mong các anh chỉ giáo ạ:
- Em dung 3 cái ADC:
+ AN2 để phản hồi điện áp ra (tần số trích mẫu 10Hz),
+ AN0 để phản hồi điện áp sau chỉnh lưu Vg (và tính điện áp trung bình của Vg),
+ AN1 để phản hồi dòng điện (tần số 2kHz). Hiện em chưa biết phải sử dụng khối ADC theo cách nào để có thể thực hiện lấy mãu theo các tần số khác nhau như vậy.
- Em cũng chưa biết cách lập trình để có thể dùng 3 ADC với 3 nhiệm vụ khác nhau như trên, các anh có thể cho em một vài ví dụ lập trình sử dụng nhiều ADC được không, có sử dụng ngắt ADC, chế độ kích hoạt chuyển đổi bằng timer ấy ạ
Em cảm ơn nhìu

tungnh
08-05-2009, 11:40 AM
http://i634.photobucket.com/albums/uu70/cuongthinh/PFCBoostconverter.jpg
Em đang lập trình dsp30F4011 để thực hiện mạch này. Hiện em đang có một số vướng mắc này mong các anh chỉ giáo ạ:
- Em dung 3 cái ADC:
+ AN2 để phản hồi điện áp ra (tần số trích mẫu 10Hz),
+ AN0 để phản hồi điện áp sau chỉnh lưu Vg (và tính điện áp trung bình của Vg),
+ AN1 để phản hồi dòng điện (tần số 2kHz). Hiện em chưa biết phải sử dụng khối ADC theo cách nào để có thể thực hiện lấy mãu theo các tần số khác nhau như vậy.
- Em cũng chưa biết cách lập trình để có thể dùng 3 ADC với 3 nhiệm vụ khác nhau như trên, các anh có thể cho em một vài ví dụ lập trình sử dụng nhiều ADC được không, có sử dụng ngắt ADC, chế độ kích hoạt chuyển đổi bằng timer ấy ạ
Em cảm ơn nhìu
Thực chắt đây là mạch PFC, bạn có thể tham khảo tại đây :
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en536650
Bạn có thể tham khảo thêm ở mục 10-bit ADC trong cuốn dsPic30F_reference_manual.

cuongthinh
08-05-2009, 03:33 PM
Em có thâm khảo cái code mẫu của nó rồi, tuy nhiên nó viết bằng ASM, mà em mới làm quen với con này chưa có điều kiện tìm hiểu vè asm cho dòng này, với lại em quen lập trình bằng C rùi, nên em muốn thuật toán lập trình dùng C. Anh làm rùi thì chỉ giáo em với. Có ví dụ về xử Lý ADC kiểu này thì cho em càng tốt ạ

TANDEM
08-05-2009, 11:52 PM
Đoạn code và hình vẽ này có thể giúp gì được bạn không?
#include <16F877a.h>
#include <DEF_16F877a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device 16F877*=16 ADC=8
#use delay(clock=4000000)
#use rs232(baud=19200,parity=n,xmit=pin_C6,rcv=pin_C7)
Int8 adc;
main()
{
setup_adc(adc_clock_internal);
setup_adc_ports(AN0_AN1_AN3);
while(true)
{
set_adc_channel(0);
adc=read_adc(adc_start_and_read);
delay_us(10);
output_B(adc);
set_adc_channel(1);
adc=read_adc(adc_start_and_read);
delay_us(10);
output_D(adc);
}
}

cuongthinh
12-05-2009, 08:48 AM
Em lập trình cho mạch trên như sau:


//Dung thach anh ngoai 10MHz

#include <p30f4011.h>
#include <dsp.h>
_FOSC(CSW_FSCM_OFF & XT_PLL8);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF);
//------------------------------------------------------------------------------
//Cac hang so cua chuong trinh
#define PWM_PORT PORTE //Cac tin hieu PWM nam o cong E
#define PWM_TRIS TRISE //Thanh ghi 3 trang thai cho cac tin hieu PWM
#define PWM_LAT LATE //Thanh ghi chot cac tin hieu PWM
#define Fcy 2000000 //Tan so thuc thi lenh 20Mbps
#define Fpwm 20000 //Tan so PWM = 20 kHz
//Cac prototype cho cac chuong trinh con
void Init_PORTS(void);
void Init_MCPWM(void);
void Init_AN0(void);
void Init_AN1(void);
void Init_AN2(void);
void PID_Init(float kp,float ki,float kd,float refer,fractional measu);
void Init_TMR1 (void);
void Init_TMR2 (void);
void Init_TMR3 (void);

//Khai bao cac bien
int count0, count1, count2, n;
fractional Vo, Iac, Vavg, Vpi, sum, Iref, Vcom, Vac;
tPID fooPID;

fractional abcCoefficient[3] __attribute__ ((section (".xbss, bss, xmemory")));
fractional controlHistory[3] __attribute__ ((section (".ybss, bss, ymemory")));
fractional kCoeffs[] = {0,0,0};

int main (void) {
Init_PORTS();
Init_MCPWM();
Init_TMR1();
Init_TMR2();
Init_TMR3();
if (count2==4){
Init_AN2();
PID_Init(27,0.04211,0,1,Vo); // V_refer = 1V
Vpi = fooPID.controlOutput;
}
if (count0==2){
Init_AN0();
sum = sum+ADCBUF0;
Iref = 0x1999 * Vpi * Vcom * Vac;
}
if (count1==2){
Init_AN1();
PID_Init(27,0.04211,0,Iref,Iac); // V_refer = Iref
PDC1 = (unsigned int)(Fract2Float(fooPID.controlOutput) * PTPER *2);
}
if (n==100){
Vavg = sum/n;
Vcom = 1/(Vavg*Vavg);
n=0;
}
while(1);
}

void Init_AN0(void) {
ADCON1 = 0; //Tat Module ADC
ADPCFG = 0xFFF8; //Cac chan khac la digital, chan AN0, AN1, AN2 la analog
ADCON1 = 0x02E0; //auto convert
//Dinh dang du lieu ra Q15
ADCON2 = 0;
ADCHS = 0; //Kenh 0 doc tin hieu giua AN2 va AVss
ADCSSL = 0; //Khong quet cac ngo vao
ADCON3 = 0x0103; //Dung 1 TAD cho lay mau, dung clock he thong,
//TAD = 2xTcy = 100 ns
_ADIF = 0; //Xoa co ngat ADC
_ADIE = 0; //Khong Cho phep ngat ADC
_ADON = 1; //Bat module ADC
while (_DONE == 0) Nop();
Vac = ADCBUF0;
}

//Chuong trinh con khoi tao module chuyen doi A/D, doc ngo vao AN1, phan hoi tin hieu Iac
//Tan so trich mau 2khz

void Init_AN1(void) {
ADCON1 = 0;
ADPCFG = 0xFFF8; //Cac chan khac la digital, chan AN0, AN1, AN2 la analog
ADCON1 = 0x02E0, //auto convert
//Dinh dang du lieu ra Q15
ADCON2 = 0;
ADCHS = 0x0001; //Kenh 0 doc tin hieu giua AN1 va AVss
ADCSSL = 0; //Khong quet cac ngo vao
ADCON3 = 0x0103; //Dung 1 TAD cho lay mau, dung clock he thong,
//TAD = 2xTcy = 100 ns
_ADIF = 0; //Xoa co ngat ADC
_ADIE = 1; //Khong cho phep ngat ADC
_ADON = 1; //Bat module ADC
_ASAM = 1; //Khoi dong che do tu dong lay mau
while (_DONE==0) Nop();
Iac = ADCBUF0;
}
//Chuong trinh con khoi tao module chuyen doi A/D, doc ngo vao AN2, Phan hoi Vo
//Tan so trich mau 10Hz
void Init_AN2(void) {
_ADON = 0;
ADPCFG = 0xFFF8; //Cac chan khac la digital, chan AN0, AN1, AN2 la analog
ADCON1 = 0x02E0; //Auto convert
//Dinh dang du lieu ra Q15
ADCON2 = 0;
ADCHS = 0x0002; //Kenh 0 doc tin hieu giua AN2 va AVss
ADCSSL = 0; //Khong quet cac ngo vao
ADCON3 = 0x0103; //Dung 1 TAD cho lay mau, dung clock he thong,
//TAD = 2xTcy = 100 ns
_ADIF = 0; //Xoa co ngat ADC
_ADIE = 0; //Khong cho phep ngat ADC
_ADON = 1; //Bat module ADC
_ASAM = 1; //Khoi dong che do tu dong lay mau
while(_DONE==0) Nop();
Vo = ADCBUF0;
}

//Chuong trinh con khoi tao cac PORT
void Init_PORTS( void )
{
LATB = 0x0000; // Xoa cong B
TRISB = 0x0007; // RB0 to RB2 are input ports

LATC = 0x0000; // Xoa cong C
TRISC = 0x0000; // Cong C la ngo ra

LATD = 0x0000; // Xoa cong D
TRISD = 0xD70F; // Cong D la ngo ra

LATE = 0x0000; // Xoa cong E
TRISE = 0x0001; // RE0 la ngo ra

LATF = 0x0000; // Xoa cong F
TRISF = 0x0000; // Cong F la ngo ra
}
//Chuong trinh con khoi tao Timer o muc xung 20 Mips
//Timer1 dieu khien trich mau cho AN0 (phan hoi Vac voi tan so 10kHz)
void Init_TMR1(void) {
TMR1 = 0; //Xoa so dem trong TMR1
PR1 = 1000; //Nguong tran la 0.05ms (cu 2 xung thi trich mau mot lan)
_T1IF = 0; //Xoa co ngat cua Timer 1
T1CON = 0x8000; //Dung fcy lam clock, prescale = 1:1, bat Timer 1
_T1IE = 1; //Cho phep ngat Timer 1
}
//Timer2 dieu khien trich mau AN1 (Phan hoi Iac voi tan so 2kHz)
void Init_TMR2(void) {
TMR2 = 0; //Xoa so dem trong TMR2
PR2 = 5000; //Nguong tran la 0.25ms (2 xung trich mau mot lan )
_T2IF = 0; //Xoa co ngat cua Timer 2
T2CON = 0x8000; //Dung fcy lam clock, prescale = 1:1, bat Timer 2
_T2IE = 1; //Cho phep ngat Timer 2
}
//Timer3 dieu khien trich mau AN2 (Phan hoi Iac voi tan so 100Hz)
void Init_TMR3(void) {
TMR3 = 0; //Xoa so dem trong TMR3
PR3 = 50000; //Nguong tran la 2,5ms (4 xung trich mau mot lan)
_T3IF = 0; //Xoa co ngat cua Timer 3
T3CON = 0x8000; //Dung fcy lam clock, prescale = 1:1, bat Timer 3
_T3IE = 1; //Cho phep ngat Timer 3
}

//Chuong trinh con khoi tao module PWM
void Init_MCPWM(void) {
PTPER = Fcy/Fpwm - 1; //Dat thanh ghi chu ky voi tan so PWM = 20 kHz
SEVTCMP = PTPER;
PWMCON1 = 0x070F; //Chi dung cac chan PxL, mot cach doc lap
OVDCON = 0xFF00; //Khong dung overdrive
PDC1 = 1000; //Dat duty = 50% cho chu ki dau tien
PTCON = 0x8000; //Kich hoat module PWM
}

//Chuong trinh con khoi tao khoi PI
void PID_Init(float kp,float ki,float kd,float refer, fractional measu)
{
fooPID.abcCoefficients = &abcCoefficient[0]; /*Set up pointer to derived coefficients */
fooPID.controlHistory = &controlHistory[0]; /*Set up pointer to controller history samples */
PIDInit(&fooPID); /*Clear the controler history and the controller output */
kCoeffs[0] = Q15(kp);
kCoeffs[1] = Q15(ki);
kCoeffs[2] = Q15(kd);
PIDCoeffCalc(&kCoeffs[0], &fooPID); /*Derive the a,b, & c coefficients from the Kp, Ki & Kd */
fooPID.controlReference = Q15(refer) ;
fooPID.measuredOutput = measu ;
PID(&fooPID); // Thuc hien tinh toan
}

//Chuong trinh xu ly ngat Timer 1
void _ISR _T1Interrupt(void) {
_T1IF = 0; //Xoa co ngat
if (count0==3) count0=1;
else count0 = count0 + 1;
}

//Chuong trinh xu ly ngat Timer 2
void _ISR _T2Interrupt(void) {
_T2IF = 0; //Xoa co ngat
if (count1==3) count1=1;
else count1 = count1 + 1;
}

//Chuong trinh xu ly ngat Timer 3
void _ISR _T3Interrupt(void)
{
_T3IF = 0; //Xoa co ngat
if (count2==5) count2=1;
else count2 = count2 + 1;
}

Em dùng 3 timer để tạo tần số gọi chương trình ADC. Khi em dịch chương trình thấy báo lỗi như sau

main.o(.text+0x70): In function `main':
E:\PFC Toan\Chuong trinh\main.c:56: undefined reference to `Fract2Float'
main.o(.text+0x224): In function `PID_Init':
E:\PFC Toan\Chuong trinh\main.c:182: undefined reference to `PIDInit'
main.o(.text+0x2d2):E:\PFC Toan\Chuong trinh\main.c:186: undefined reference to `PIDCoeffCalc'
main.o(.text+0x314):E:\PFC Toan\Chuong trinh\main.c:189: undefined reference to `PID'
Link step failed.

Em kô hiểu tại sao lại báo lỗi phần hàm PID như thế, tại sao lại kô sử dung được `Fract2Float'.
Cách anh làm ơn giúp em với

cuongthinh
12-05-2009, 04:10 PM
Sao ko có anh nào chỉ cho em vậy? E dang làm đồ án về cái PFC này chỉ vướng cái này nữa mà chưa giải quyết được. Có ai ra tay giúp em với

tungnh
13-05-2009, 05:09 PM
Em lập trình cho mạch trên như sau:

Em dùng 3 timer để tạo tần số gọi chương trình ADC. Khi em dịch chương trình thấy báo lỗi như sau

Em kô hiểu tại sao lại báo lỗi phần hàm PID như thế, tại sao lại kô sử dung được `Fract2Float'.
Cách anh làm ơn giúp em với

bạn tham khảo phần ví dụ về PID ở đường dẫn sau :C:\Program Files\Microchip\MPLAB C30\examples\dsPIC30F\CE019_PID
bạn thấy phần linker script người ta tạo một file gld là linkerscript.gld như sau:
SEARCH_DIR(..\..\..\..\lib)
SEARCH_DIR(..\..\..\..\support\gld)
INPUT(-ldsp)
INPUT(-lpic30)
INPUT(-lm)
INPUT(-lc)
INCLUDE p30f4011.gld
Tôi cũng không biết họ link kiểu gì, nhưng khi tôi đặt project của tôi vào thư mục PFC đặt trong đường dẫn : C:\Program Files\Microchip\MPLAB C30\examples\dsPIC30F\
thì kết quả là không con lỗi như của bạn nữa. Nếu bạn chưa có cách nào thì cứ làm tạm theo cách của tôi.

cuongthinh
15-05-2009, 08:18 AM
Anh tungnh cũng làm PFC số rồi ạ, anh xem với cái sơ đồ như trên chương trình của em có lỗi gì không sao em test thử mà không thấy có xung ra ở chân PWM. sau một hồi mày mò, xem xét em vẫn chưa tìm được lỗi sai ở đâu, mong anh và các cao thủ ra tay giúp đỡ!

tungnh
15-05-2009, 05:18 PM
Anh tungnh cũng làm PFC số rồi ạ, anh xem với cái sơ đồ như trên chương trình của em có lỗi gì không sao em test thử mà không thấy có xung ra ở chân PWM. sau một hồi mày mò, xem xét em vẫn chưa tìm được lỗi sai ở đâu, mong anh và các cao thủ ra tay giúp đỡ!
Tôi góp ý cho bạn về code bạn viết nhé:
Thứ nhất : chắc bạn chưa hiểu về PI. Bởi hệ thống PI phải là liên tục , mà trong đoạn code của bạn không để hàm điều khiển trong vòng while hay ngắt. Tôi khuyên bạn nên thực hiện khâu PI trong ngắt ADC.
Thứ 2
Không ai người ta cấu hình ADC nhiều lần như bạn,Tôi gợi ý cho bạn thế này : thực chất với bài toán này không phải bạn lấy mẫu với tần số khác nhau với mỗi chân ANx mà lấy kết quả việc chuyển đối AD với mỗi chân là không đồng thới. Để làm điều này bạn thực hiện quét kênh với mỗi các ANx khác nhau.
ví dụ bạn chọn kênh 0 gồm các chân AN3,AN4 và AN0,AN1,AN2, ở kênh 1,2,3 chẳng hạn,kênh 0 là kênh quét, đầu tiên là cho AN3 quét trước . sau đó bạn cấu hình cho việc ngắt sau số lần lấy mẫu và chuyển đổi ví dụ ADCON2bits.SMPI =1 ( ngắt sau lấn sample/convert thứ hai) . Ta chọn AN3 quét trước ,sau lần sample/convert đầu tiến ta có kết quả của AN3,AN0,AN1,AN2 lần lượt là ADCBUF0,1,2,3 và sau lần sample/convert thứ hai , tức AN4 quét kết quả của AN4,AN0,AN1,AN2 là ADCBUF4,5,6,7. Như vậy là các chân AN0,1,2 có 2 kết quả trong khi đó AN3,4 chỉ có 1. Bạn có thể tham khảo ở dspic30f_reference_manual để hiểu .

cuongthinh
15-05-2009, 10:37 PM
Em cảm ơn anh, đúng là em chưa biết cách lập trình cho 3 cái ADC nên ngay từ đầu thread em đã đặt ra câu hỏi. Cũng do việc xử lý ADC không tốt nên em đành phải làm thủ công như thế, rồi dẫn đến việc phải gọi hàm PI bằng các biến đếm. Em đã tìm hiểu mấy cái tutorial của anh Nam nhưng kô thấy nhắc đến việc quét kênh ADC như anh nói. Em sẽ về tìm hiểu thêm, hy vọng sẽ lập trình xong sớm, sắp phải nộp đồ án rồi mà vẫn chưa lập trình xong! Híc!