PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   dsPIC - Bộ điều khiển tín hiệu số 16-bit (http://www.picvietnam.com/forum/forumdisplay.php?f=29)
-   -   dsPIC30F4011 RS232 RS485 nhờ mọi người giúp!!! (http://www.picvietnam.com/forum/showthread.php?t=2504)

hpecom 24-06-2008 12:23 AM

dsPIC30F4011 RS232 RS485 nhờ mọi người giúp!!!
 
1 Attachment(s)
Kính gửi anh Nam và các bạn,

Em dùng dsPIC30F4011 và dsPIC2010 giao tiếp RS485. dsPIC30F4011 vừa giao tiếp RS485 vừa giao tiếp RS232 với PC.

_ Tình trạng lỗi như sau: + với dsPIC30F4011 nếu dùng kết nối RS485 thì tín hiệu truyền từ PIC lên chập chờn, lúc được lúc không lúc thì nhiễu loạn, nếu sờ tay vào dây nối giữa dsPIC và Max485 thì nhiễu càng nhiều. Toàn nhận được các ký tư <0> và các số ngẫu nhiên đủ thứ.
Với RS232 thì chạy tốt, khi sờ tay vào dây nối giữa dsPIC và RS232 thì không xuất hiện các giá trị trên.
+ Đối với dsPIC30F2010 thì làm việc tốt cả với RS232 và RS485.
Dưới đây là Schematic và code em sửa từ Tutorial của anh Nam.

Mong rằng các bạn đã gặp tình huống này thì chia sẻ kinh nghiệm xử lý cho mình và mọi người cùng biết.

Xin cảm ơn và chào đoàn kết.

namqn 24-06-2008 09:05 PM

Trước hết, cần nối các chân AVDD và AVSS vào những điện thế thích hợp. Ngay cả khi chúng ta không dùng module ADC, vẫn cần phải nối những chân này đến nguồn. Đơn giản vì chúng ta không biết cấu trúc bên trong của dsPIC như thế nào, nên không thể khẳng định rằng thả nổi hai chân này sẽ không gây ảnh hưởng gì đến các module lân cận nó.

Và các cặp chân nguồn luôn luôn cần tụ bypass (decoupling) để đảm bảo hoạt động ổn định, thường dùng tụ gốm/kẹo (ceramic) 100 nF (104) cho mục đích này.

Thân,

hpecom 25-06-2008 01:32 AM

Chào anh Nam và các bạn,

Em đã cắm tụ mà vẫn không xử lý được hiện tượng trên, em dùng điện trở 10K treo chân Tx của dsPIC lên nguồn thì thấy không còn tình trạng trên, nhưng lại sinh một tình trạng mới khi viết code truyền. Đoạn code em viết như sau:
Code:

#include        <p30f4011.h>

        _FOSC(CSW_FSCM_OFF & XT_PLL4);//FRC_PLL4
        _FWDT(WDT_OFF);
        _FBORPOR(PBOR_OFF & MCLR_EN);
        _FGS(CODE_PROT_OFF);

//------------------------------------------------------------------------------
//Cac hang so cua chuong trinh (gia tri tuc thoi dung trong chuong trinh)
#define        Fcy                4000000                //Tan so thuc thi lenh (Thach anh 4MHz)
#define        baud        9600                        //Toc do baud cua RS232
#define _ISR_PSV __attribute__((interrupt, auto_psv))

//Cac prototype cho cac chuong trinh con
void Init_PORTS(void);
void Init_ADC10(void);
void Init_TMR1(void);
void Init_UART1(void);
//void Init_UART2(void);
unsigned int CRC_Calc(int* pMes);

//Cac bien toan cuc
unsigned int gFlag_1,gFlag_2;
unsigned char gFwd[]={0x01,0x06,0x01,0x50,0x00,0x01,0x49,0xE7};
unsigned char gRev[]={0x01,0x06,0x01,0x50,0x00,0x02,0x09,0xE6};
unsigned char gStop[]={0x01,0x06,0x01,0x50,0x00,0x00,0x88,0x27};
unsigned char gSpe[]={0x01,0x06,0x00,0x80,0x03,0x89,0x0A};
unsigned char gRec[10]={0,1,2,3,4,5,6,7,8,9};
unsigned char gRPos=0;
unsigned char gTPos=0;
unsigned char gRCount=0;
unsigned char gCmd=0;
int gEE_Return;
//------------------------------------------------------------------------------
//Chuong trinh chinh
int main(void) {
        Init_PORTS();                        //Khoi tao cac cong I/O
        Init_TMR1();                        //Khoi tao Timer 1
        Init_UART1();                        //Khoi tao module UART1
        //Init_UART2();                        //Khoi tao module UART2
        _LATB3=0;                                //Cho phep nhan Data
        while (1)
        {        if(gFlag_1)
                {        gFlag_1=0;
                        _LATB0^=1;
                        _LATB3=1;                                                //Cho phep gui Data
                        while(gTPos!=gRPos)
                        {        //U1TXREG = gRec[1];                        //Neu bo dong nay
                                //while (!U1STAbits.TRMT);        //va bo dong nay thi lenh truyen ben duoi khong duoc thuc hien
                                U1TXREG = gRec[gTPos];
                                while (!U1STAbits.TRMT);
                                if(++gTPos>9) gTPos=0;
                        };
                        _LATB3=0;                                                //Cho phep nhan Data
                }
        };
}
//============================================================================
//Function tinh CRC
//============================================================================
unsigned int CRC_Calc(int* pMes)
{        unsigned int mCRC_Reg=0xFFFF;
        unsigned char mHighByte;
        unsigned char mLowByte;
        return 1;       
}
//Chuong trinh con khoi tao cac cong I/O, de xuat cac tin hieu PWM, va doc tin
//hieu dieu chinh cua bien tro tai AN0
void Init_PORTS(void) {
        TRISB = 0x0000;                        //Chan RB0 la ngo vao analog AN0, cac chan khac
                                                        //la ngo ra
        LATD = 0;                        //Xoa thanh ghi chot cong D
        TRISD = 0xFFFE;
        //LATE=0;
        //TRISE=0xFF;
}
//Chuong trinh con khoi tao Timer 1, tran sau moi 1 giay o muc xung 8 Mips
void Init_TMR1(void) {
        TMR1 = 0;                                //Xoa so dem trong TMR1
        PR1 = 0x3D09;                        //Nguong tran la 1 giay ung voi clock = 32 MHz
        _T1IF = 0;                                //Xoa co ngat cua Timer 1
        T1CON = 0x8030;                        //Dung fcy lam clock, prescale = 1:256
        _T1IE = 1;                                //Cho phep ngat khi Timer 1 tran
}
//Chuong trinh con khoi tao module UART1
void Init_UART1(void) {
        U1MODE = 0x8000;                //Main I/O, 8-bit, no parity, 1 stop bit
        //U1MODE = 0x8400;                //ALT I/O, 8-bit, no parity, 1 stop bit
        U1STA = 0x0400;                        //bit10=UTXEN
        U1BRG = (((Fcy/baud)/16)-1);        //38400 bps @ Fcy = 8 MHz
        _U1RXIF = 0;
        _U1RXIE=1;
}
//Chuong trinh xu ly ngat Timer 1
//void _ISR _T1Interrupt(void)
void _ISR_PSV _T1Interrupt(void)
{        _LATD0^=1;
        _T1IF = 0;                                //Xoa co ngat
}
//Chuong trinh xu ly ngat truyen thong UART
void _ISR_PSV _U1RXInterrupt(void)
{        gFlag_1 = 1;
        while(U1STAbits.URXDA)
        {        gRec[gRPos]=U1RXREG;
                if (++gRPos>9)        gRPos=0;
                if(++gRCount>9) gRCount=0;
        };
        _U1RXIF = 0;
}

Nếu bỏ 2 dòng lệnh 71 và 72 thì 2 dòng lệnh 73 và 74 không được thực hiện, mặc dù khi có dữ liệu đến thì dsPIC vẫn xảy ra ngắt UART.
Khi có 2 dòng lệnh này thì cả hai dòng dưới cũng được thực hiện. Dữ liệu truyền không còn bị nhiễu như trước.
Mong anh và mọi người trợ giúp!!!

Chúc mọi người một ngày mới tốt đẹp!

namqn: bạn chú thích thẳng dòng 71 và 72 là những dòng nào trong code.

namqn 25-06-2008 02:10 AM

Bạn chú thích thẳng vào code đã post vị trí hai dòng đó, vì copy code đã post vào trình soạn thảo cho thấy dòng 71 chỉ có chú thích chứ không chứa lệnh.

Thân,

hpecom 25-06-2008 03:22 PM

Xin lỗi anh vì em copy thiếu phần title của chương trình!
Dạ, nó nằm trong vòng lặp While() thứ 2 của hàm Main(), đó là 2 dòng lệnh này anh ạ:
Code:

//U1TXREG = gRec[1];                //Neu bo dong nay
//while (!U1STAbits.TRMT);        //va bo dong nay thi lenh truyen ben duoi khong duoc thuc hien

Nếu em bỏ dấu comment thì cả hai lệnh truyền sẽ được thực hiện. Còn để như hiện tại thì nó sẽ không được truyền.
Em vẫn chưa tìm ra được nguyên nhân.

namqn 25-06-2008 05:45 PM

Theo sơ đồ phần cứng của bạn, chân PWM1L/RE0 điều khiển chiều truyền/nhận của MAX485. Và trong code hiện tại không có lệnh thao tác trạng thái của chân này. Như vậy trạng thái của các chân DE và /RE (đã nối vào nhau) của MAX485 là không xác định trước, và dễ bị nhiễu nếu chân RE0 là ngõ vào, vì chỉ được treo bởi một điện trở 10 k lên 5 V.

Thân,

hpecom 26-06-2008 12:33 AM

Dạ em đã sửa lại code.
Em thử nhiều lần thì phát hiện rằng: trong vòng lặp While() thứ 2 của hàm Main() nếu số lần truyền là số chẵn thì không bị mất dữ liệu, còn nếu số lần truyền là số lẻ thì sẽ mất ký tự cuối cùng, không biết điều này có liên quan gì đến việc cấu hình không vậy anh?

Code:

#include        <p30f4011.h>

        _FOSC(CSW_FSCM_OFF & XT_PLL4);//FRC_PLL4
        _FWDT(WDT_OFF);
        _FBORPOR(PBOR_OFF & MCLR_EN);
        _FGS(CODE_PROT_OFF);

//----------------------------------------------------------------------------
//Cac hang so cua chuong trinh (gia tri tuc thoi dung trong chuong trinh)
#define        Fcy                4000000                        //Tan so thuc thi lenh (Thach anh 4MHz)
#define        baud        9600                        //Toc do baud cua RS232
#define _ISR_PSV __attribute__((interrupt, auto_psv))
//----------------------------------------------------------------------------
//Cac prototype cho cac chuong trinh con
void Init_PORTS(void);
void Init_ADC10(void);
void Init_TMR1(void);
void Init_UART1(void);
//void Init_UART2(void);
//----------------------------------------------------------------------------
//Khai bao bien toan cuc
unsigned int CRC_Calc(int* pMes);

unsigned int gFlag_1,gFlag_2;
unsigned char gFwd[]={0x01,0x06,0x01,0x50,0x00,0x01,0x49,0xE7};
unsigned char gRev[]={0x01,0x06,0x01,0x50,0x00,0x02,0x09,0xE6};
unsigned char gStop[]={0x01,0x06,0x01,0x50,0x00,0x00,0x88,0x27};
unsigned char gSpe[]={0x01,0x06,0x00,0x80,0x03,0x89,0x0A};
unsigned char gRec[10]={0,1,2,3,4,5,6,7,8,9};
unsigned char gRPos=0;
unsigned char gTPos=0;
unsigned char gRCount=0;
unsigned char gCmd=0;
int gEE_Return;
//============================================================================
//CHUONG TRINH CHINH
//Kiem tra co gFlag (co bao UART1 nhan du lieu)
//Truyen ky tu nhan duoc
//============================================================================
int main(void) {
        Init_PORTS();                        //Khoi tao cac cong I/O
        Init_TMR1();                        //Khoi tao Timer 1
        Init_UART1();                        //Khoi tao module UART1
        //Init_UART2();                        //Khoi tao module UART2
        _LATE0=0;                                //Cho phep nhan Data
        while (1)
        {        if(gFlag_1)
                {        gFlag_1=0;
                        _LATB0^=1;
                        _LATE0=1;                                                //Cho phep gui Data
                       
                        /* Thuc hien truyen du lieu ra cong UART1
                        _ Neu truyen 2n ky tu thi khong mat Data
                        _ Neu truyen (2n+1) ky tu thi mat ky tu cuoi cung
                        */
                        while(gTPos!=gRPos)
                        {        U1TXREG = gRPos;                                //
                                while (!U1STAbits.TRMT);
                                U1TXREG = gTPos;                                //
                                while (!U1STAbits.TRMT);
                                U1TXREG = gRCount;                                //
                                while (!U1STAbits.TRMT);
                                U1TXREG = gCmd;                                        //
                                while (!U1STAbits.TRMT);
                                U1TXREG = gRec[gRPos];                        //
                                while (!U1STAbits.TRMT);
                                U1TXREG = gRec[gTPos];                        //
                                while (!U1STAbits.TRMT);                //
                                if(++gTPos>9) gTPos=0;
                        };
                        _LATE0=0;                                                //Cho phep nhan Data
                }
        };
}
//============================================================================
//Function tinh CRC
//============================================================================
unsigned int CRC_Calc(int* pMes)
{        unsigned int mCRC_Reg=0xFFFF;
        unsigned char mHighByte;
        unsigned char mLowByte;
        return 1;       
}
//============================================================================
//Proc khoi tao cac cong I/O
//============================================================================
void Init_PORTS(void) {
        TRISB = 0x0000;                        //RB0 la ngo ra
        LATD = 0;                                //Xoa thanh ghi chot cong D
        TRISD = 0xFFFE;
        LATE=0;
        TRISE=0x0000;                        //PortE la Digital Output
}
//============================================================================
//Proc khoi tao va setup Timer1 (Ngat sau 1S)
//============================================================================
void Init_TMR1(void) {
        TMR1 = 0;                                //Xoa so dem trong TMR1
        PR1 = 0x3D09;                        //Nguong tran la 1 giay (=4000000/256)
        _T1IF = 0;                                //Xoa co ngat cua Timer 1
        T1CON = 0x8030;                        //Dung fcy lam clock, prescale = 1:256
        _T1IE = 1;                                //Cho phep ngat khi Timer 1 tran
}
//============================================================================
//Proc khoi tao module UART1
//Baud rate = 9600, 8 bit Data, no Parity, 1 bit stop
//============================================================================
void Init_UART1(void) {
        U1MODE = 0x8000;                //Main I/O, 8-bit, no parity, 1 stop bit
        //U1MODE = 0x8400;                //ALT I/O, 8-bit, no parity, 1 stop bit
        U1STA = 0x0400;                        //bit10=UTXEN
        U1BRG = (((Fcy/baud)/16)-1);        //38400 bps @ Fcy = 8 MHz
        _U1RXIF = 0;
        _U1RXIE=1;
}
//============================================================================
//Proc Xu ly ngat Timer1
//============================================================================
void _ISR_PSV _T1Interrupt(void)
{        _LATD0^=1;
        _T1IF = 0;                                //Xoa co ngat
}
//============================================================================
//Proc Xu ly ngat khi UART1 nhan Data
//Dung mang 10 ky tu lam bo dem (+4 ky tu bo dem cua dsPIC)
//============================================================================
void _ISR_PSV _U1RXInterrupt(void)
{        gFlag_1 = 1;
        _LATB1^=1;
        while(U1STAbits.URXDA)
        {        gRec[gRPos]=U1RXREG;
                if (++gRPos>9)        gRPos=0;
                if(++gRCount>9) gRCount=0;
        };
        _U1RXIF = 0;
}

Trong code trên em cho truyền 6 ký tự, kết quả nhận được đầy đủ nhưng giá trị nhận được không như mong muốn: Lệnh truyền thứ 5 và thứ 6 là em truyền 2 ký tự cuối cùng nhận được. Nhưng sao chương trình truyền toàn giá trị 0.
Chương trình xử lý ngắt có sai không anh?

namqn 26-06-2008 01:20 AM

À, bạn chưa cho biết đang thử nghiệm theo kiểu nào? Bạn đang gửi trả những gì nhận được từ dsPIC về nó hay sao?

Thân,

hpecom 26-06-2008 08:43 AM

Hiện tại em dùng PC (có RS232-RS485 converter) để thử nghiệm việc truyền nhận.
Em nhận các ký tự truyền từ PC xuống dsPIC và dsPIC truyền trả lại PC những ký tự nó đã nhận được.
Và em đã tìm ra lỗi: Nguyên nhân do em không có khoảng delay sau khi truyền có lẽ MAX485 chưa truyền xong em đã nâng DE/RE lên 1 nên mất ký tự cuối cùng.
Nhưng em không hiểu sao khi mình truyền 2, 4, 6. ký tự thì lại không bị mất và mình nên delay khoảng bao lâu là tốt nhất vậy anh?

namqn 26-06-2008 11:00 PM

Trích:

Nguyên văn bởi hpecom (Post 17057)
Hiện tại em dùng PC (có RS232-RS485 converter) để thử nghiệm việc truyền nhận.
Em nhận các ký tự truyền từ PC xuống dsPIC và dsPIC truyền trả lại PC những ký tự nó đã nhận được.
Và em đã tìm ra lỗi: Nguyên nhân do em không có khoảng delay sau khi truyền có lẽ MAX485 chưa truyền xong em đã nâng DE/RE lên 1 nên mất ký tự cuối cùng.
Nhưng em không hiểu sao khi mình truyền 2, 4, 6. ký tự thì lại không bị mất và mình nên delay khoảng bao lâu là tốt nhất vậy anh?

Nếu gửi dữ liệu từ PC xuống dsPIC và dsPIC trả lại dữ liệu thì nên thiết kế cơ chế bắt tay.

MAX485 chỉ chuyển mức tín hiệu từ RS-232 (so với 0 V) thành RS485 (vi sai) thôi, nhưng dsPIC cần điều khiển các chân DE và /RE một cách thích hợp.

Về code ở trên, có thể giải thích những gì đang diễn ra như sau:

Vì các bit <7:6> của thanh ghi U1STA bằng '00', mỗi ký tự nhận được tại UART1 của dsPIC sẽ tạo 1 ngắt, do đó vòng lặp while () trong code xử lý ngắt chẳng có tác dụng gì ngoài việc chỉ đọc ký tự đó vào bộ đệm nhận rồi trở về, sau khi bật cờ gFlag_1. Khi đó vòng lặp chính trong main() có thể phát hiện ra đã thu được một ký tự và dsPIC bắt đầu phát một loạt ký tự về PC, việc phát là ổn vì code kiểm tra trạng thái của bộ đệm phát, và chỉ thoát khỏi vòng lặp kiểm tra khi đã phát xong ký tự. Phía PC thu được như thế nào lại là chuyện khác.

Trong quá trình dsPIC đang phát loạt ký tự về PC, nếu PC cũng phát tiếp một ký tự nữa thì không rõ chuyện gì sẽ xảy ra, vì không rõ hành vi của bộ chuyển đổi RS-232/RS-485 bên phía PC.

Câu hỏi của bạn về truyền 2, 4, 6 ký tự lại không bị mất là không rõ ràng, vì không rõ dsPIC phát hay PC phát? Ở đây thực chất có 2 kênh truyền nhưng chỉ có một đường truyền, do đó cần xác định rõ ràng.

Khi dsPIC phát và PC thu, dsPIC có thể đặt trạng thái cho MAX485 nối vào nó để làm việc đó. Khi PC phát và dsPIC thu, thông thường dsPIC không biết lúc nào sẽ xảy ra việc truyền thông, nên nó thường phải đặt trạng thái cho MAX485 nối vào nó ở chế độ thu. Tuy nhiên, như đã nêu ở trên, vẫn có khả năng PC thử phát 1 ký tự vào đường truyền đang được dùng để phát từ dsPIC về PC.

Hành vi của phía chủ động phát là PC đến lúc này vẫn chưa rõ.

Thân,

hpecom 27-06-2008 12:26 AM

Dạ, vì em đang thử nghiệm xem UART hoạt động thế nào nên em cho PC chỉ truyền 1 ký tự để dsPIC xảy ra ngắt trên UART1. Khi dsPIC nhận được ký tự thì dsPIC truyền ngược lại nhiều ký tự cho PC (trong code em truyền 6 ký tự), số kỵ tự này là lẻ thì PC không nhận được ký tự cuối cùng anh ạ.


Em cảm ơn anh!

namqn 27-06-2008 01:28 AM

Phía PC bạn dùng công cụ gì để theo dõi việc truyền nhận? Dựa vào đâu bạn khẳng định khi phát loạt 6 ký tự từ dsPIC thì 2 ký tự sau cùng đều là 0 (lý do của câu hỏi này là các ký tự có mã ASCII < 0x20 đều thuộc loại không thể hiển thị được, vì chúng là các mã điều khiển)?

Nếu bạn dùng dsPIC phát liền một mạch các loạt ký tự với độ dài của loạt ký tự khác nhau thì sao (cứ thử phát 3, 4, 5, 6, ... ký tự liên tiếp thì kết quả thế nào)?

Thân,

hpecom 27-06-2008 11:18 AM

Dạ, em sử dụng Terminal V1.9b. Em nhận dữ liệu dạng Hex nên chắc chắn là giá trị 0 anh ạ. Trong 6 giá trị em truyền thì 2 giá trị cuối là các giá trị nhận được từ PC.

Nếu em không nhận dữ liệu từ PC mà tự cho dsPIC phát thì không vấn đề gì anh ạ, vì lúc đó nối thẳng DE/RE lên 5V.

em đợi tin Anh!

namqn 27-06-2008 06:11 PM

Trích:

Nguyên văn bởi hpecom (Post 17077)
Dạ, em sử dụng Terminal V1.9b. Em nhận dữ liệu dạng Hex nên chắc chắn là giá trị 0 anh ạ. Trong 6 giá trị em truyền thì 2 giá trị cuối là các giá trị nhận được từ PC.

Nếu em không nhận dữ liệu từ PC mà tự cho dsPIC phát thì không vấn đề gì anh ạ, vì lúc đó nối thẳng DE/RE lên 5V.

em đợi tin Anh!

Nếu như vậy thì phải đặt vấn đề dữ liệu phát từ PC có gì bất thường. Bạn có thể dùng 8 LED nối với 1 port nào đó của dsPIC hay không? Nếu được thì thử phát từ PC từng ký tự, hiển thị toàn bộ 8-bit thu được ra LED, mỗi ký tự được phát cách nhau vài giây để bạn có thời gian kiểm tra dữ liệu mà dsPIC đã thu được.

Thân,

hpecom 27-06-2008 08:36 PM

Vâng em sẽ báo cáo kết quả với anh.
Còn một việc nữa mà em vẫn băn khoăn là chân Tx. Hôm trước nó có hiện tượng nhiễu giống như bị bỏ lửng, em treo một điện trở 10K lên 5V thì nó không bị nhiễu nữa nhưng em thấy làm thế không đúng vì bình thường chân Tx đâu có ai treo lên như vậy. Mong anh và mọi người chỉ bảo

Em cảm ơn anh!


Múi giờ GMT. Hiện tại là 03:49 AM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam