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)
-   -   dsPIC Tutorial 4-Module UART và I2C (http://www.picvietnam.com/forum/showthread.php?t=623)

namqn 01-12-2008 01:03 AM

Trích:

Nguyên văn bởi han_nang_008 (Post 20987)
em thử lại 7372800 cũng ko dc bac ah

Bây giờ bạn thử lại với một chương trình rất đơn giản, chỉ dùng PIC gửi chuỗi ký tự lên PC, và trên PC dùng một chương trình tiện ích nào đó như HyperTerminal để nhận.

Thân,

han_nang_008 15-12-2008 02:47 PM

trong ví dụ 5.2 của bác đoặn thế này
Code:

while (1) {
                if (flag) {                                                //Neu co ket qua moi thi xuat ket qua
                        idx = (ADCValue >> 8);                //Nibble cao nhat (chi co 2 bit)
                        U1TXREG = HexTable[idx];        //Chuyen thanh ky tu tuong ung
                        while (!U1STAbits.TRMT);        //Cho den khi truyen xong ky tu
                        idx = ((ADCValue >> 4) & 0x000F);        //Nibble thu hai
                        U1TXREG = HexTable[idx];        //Chuyen thanh ky tu tuong ung
                        while (!U1STAbits.TRMT);        //Cho den khi truyen xong ky tu
                        idx = (ADCValue & 0x000F);        //Nibble thap nhat
                        U1TXREG = HexTable[idx];        //Chuyen thanh ky tu tuong ung
                        while (!U1STAbits.TRMT);        //Cho den khi truyen xong ky tu
                        U1TXREG = 0x0A;                                //Cap ky tu CR, LF
                        while (!U1STAbits.TRMT);        //Cho den khi truyen xong ky tu
                        U1TXREG = 0x0D;
                        flag = 0;                                        //Xoa co bao hieu co ket qua moi
                };

em viết lại thành hàm chuyển số sang chuỗi như này
Code:

//khai báo bien toan cuc
char chuoi[4];

unsigned char HexTable[] = "0123456789";
void so_to_chuoi(int so)
{       

        int  idx;
        int temp;
        temp=so;
                        idx = ((temp >> 12) & 0x000F);                        //Nibble cao nhat (chi co 2 bit)
                        chuoi[0] = HexTable[idx];       

                          idx = ((temp >> 8) & 0x000F);                        //Nibble cao nhat (chi co 2 bit)
                        chuoi[1] = HexTable[idx];       

                        idx = ((temp >> 4) & 0x000F);                        //Nibble cao nhat (chi co 2 bit)
                        chuoi[2] = HexTable[idx];                                //Chuyen thanh ky tu tuong ung
                       
                        idx = (temp & 0x000F);                                        //Nibble thu hai
                        chuoi[3]= HexTable[idx];                                //Chuyen thanh ky tu tuong ung
               
         
}

trong hàm main em viết đoặn
so_to_chuoi(5893);
putsUART2((unsigned int*)chuoi);

rồi truyền lên PC thì thì ko thẻ nhận đúng số 5839, mà nhạn sang số khác,
đổi sang so_to_chuoi(so bat ki); thì cũng ko nhận đúng
nếu trong hàm so_to_chuoi(); em gán idx là các số cố định thì nhận dc chính xác, em suy ra là phần tách số có vấn đề, nhung em thử cackeeiur đều ko dc.
Bác xem hộ em với

bien_van_khat 15-12-2008 04:07 PM

Giải thuật trong hàm so_to_chuoi của bạn thực chất là đổi 1 số sang dạng chuỗi nhưng ở hệ cơ số 16. Bảng HexTable của bạn lại chỉ có các ký tự từ 0-9, thiếu các ký tự A-F.

VD số 5893 của bạn, khi qua hàm sẽ ra chuỗi '1705', ngoài ra chuỗi này ko được kết thúc bởi ký tự NULL, do đó hàm putsUART2 sẽ ko hoạt động đúng khi bạn truyền tham số là chuỗi này.

han_nang_008 15-12-2008 07:26 PM

mình chỉ chuyển sô gồm những chữ số ko có A- F, nên mình ko têm vào hextable,
nhưng mình có đổi lại thành HexTable[] = "0123456789ABCDEF" thì kết quả vẫn thế, bạn dựa vào đầu mà bạn biết dc truyền 5893 mà lại nhận dc 1705 thế

namqn 15-12-2008 07:41 PM

Trích:

Nguyên văn bởi han_nang_008 (Post 21403)
mình đã đổi lại thành HexTable[] = "0123456789ABCDEF" nung kết quả vẫn thế, bạn dựa vào đầu mà bạn biết dc truyền 5893 mà lại nhận dc 1705 thế

5893 = 0x1705. Code của tôi chuyển từng nibble (4 bit) của một số hexadecimal thành một ký tự tương ứng. Bạn áp dụng khi chưa hiểu rõ.

Muốn chuyển một số thập phân thành chuỗi biểu diễn giá trị của nó thì bạn phải dùng cách tương tự như hàm itoa(), có sẵn trong thư viện của một số trình biên dịch. Với MPLAB C Compiler for dsPIC thì bạn phải tự làm, cũng không khó lắm. PIClist (www.piclist.com) có các đoạn code C mẫu cho việc chuyển đổi số nguyên sang ASCII (không may là server hiện thời của piclist chạy khá chậm).

Code cho mục đích của bạn (chuyển số nguyên 16-bit sang chữ số thập phân dạng ASCII) có ở đây:
http://www.piclist.com/techref/langu...onvertbase.htm

Code trên PIClist xuất xứ từ đây (bài viết của Associate Professor Douglas W. Jones):
http://www.cs.uiowa.edu/~jones/bcd/decimal.html


Thân,

han_nang_008 15-12-2008 08:38 PM

bác namqn có thể cop đoặn code đấy cho em được ko ah, code chuyển số thập phân sang chuỗi, chuyển số nguyên 16 bit sang chuỗi với,
web của bác cho em ko vào được, phiền bác quá.
bác cho em hỏi thêm hàm làm tròn 1 số tron C30 là j hả bác, ví dụ làm tròn số 13,6 thành 14
Thank bác nhiều

namqn 15-12-2008 11:37 PM

Trích:

Nguyên văn bởi han_nang_008 (Post 21408)
bác namqn có thể cop đoặn code đấy cho em được ko ah, code chuyển số thập phân sang chuỗi, chuyển số nguyên 16 bit sang chuỗi với,
web của bác cho em ko vào được, phiền bác quá.
bác cho em hỏi thêm hàm làm tròn 1 số tron C30 là j hả bác, ví dụ làm tròn số 13,6 thành 14
Thank bác nhiều

Code chuyển số thập phân 16-bit sang chuỗi ASCII (d4..d0):
Code:

void putdec( short int n )
    {
        unsigned char d4, d3, d2, d1, d0, q;

        if (n < 0) {
            putchar( '-' );
            n = -n;
        }

        d1 = (n>>4)  & 0xF;
        d2 = (n>>8)  & 0xF;
        d3 = (n>>12) & 0xF;

        d0 = 6*(d3 + d2 + d1) + (n & 0xF);
        q = (d0 * 0xCD) >> 11;
        d0 = d0 - 10*q;

        d1 = q + 9*d3 + 5*d2 + d1;
        q = (d1 * 0xCD) >> 11;
        d1 = d1 - 10*q;

        d2 = q + 2*d2;
        q = (d2 * 0x1A) >> 8;
        d2 = d2 - 10*q;

        d3 = q + 4*d3;
        d4 = (d3 * 0x1A) >> 8;
        d3 = d3 - 10*d4;

        putchar( d4 + '0' );
        putchar( d3 + '0' );
        putchar( d2 + '0' );
        putchar( d1 + '0' );
        putchar( d0 + '0' );
    }

MPLAB C Compiler for dsPIC có các hàm làm tròn số như sau: floor()-làm tròn xuống (tức là chỉ lấy phần nguyên, 13.9 => 13), và ceil()-làm tròn lên (tức là lấy số nguyên lớn hơn gần nhất, 13.4 => 14). Bạn nhớ dùng #include <math.h> ở đầu tập tin mã nguồn.

Thân,

ham_hoc_hoi 14-01-2009 11:43 PM

bác namqn cho em hỏi vấn đề này. trên VB6 em viết cho 1 nút ấn đơn giản là khi ân nút thì truyền 1 lúc 12 byte ví dụ là chữ "XIN CHAO BAN" với 12 lênh MSComm1.Output = các kí tự tương ứng.
ở vdk em cấu hình UART như sau
Code:

      U2MODE = 0x8000;                        //Main I/O, 8-bit, no parity, 1 stop bit
        U2STA = 0x0400;                        //bit10=UTXEN, ngắt khi nhận 1 kí tự
        U2BRG = 32;                                //9600 bps @ Fcy = 5 MHz

trong hàm ngắt em viết vi dụ như sau
Code:

void  __attribute__((__interrupt__)) _U2RXInterrupt(void)
{       
        _U2RXIF = 0;
        m++;
        if (m==5)
                {        putstr(U2RXREG);}
}

thi đoặn này nhẽ ra phải hiện chữ C, nhưng lại ko hiện chữ j
nếu em thay if(m==1) thì hiện ra đúng chữ X, nhung thay if(m==2) vẫn hiện ra chứ X, còn thay if(m==3 hoặc 4 hoặc 5.....) thì ko hiện ra chữ j cả
em thay thành đoặn code sau
Code:

void  __attribute__((__interrupt__)) _U2RXInterrupt(void)
{       
        _U2RXIF = 0;
        m++;
       
                dislayLCD(m);
}

để đếm số lần ngắt thì nó hiển thị m=2, nghĩa là em truyền 1 lúc 12 byte thì chỉ xảy ra 2 lần ngắt, cho nên ở đoặn trên với if(m== sô lớn hơn 2) là ko hiển thị đuọc. Em đã đặt chế độ ngắt khi nhận dc 1 byte, vậy trong tr hợp này m phải bằng 12 chứ bác, tốc đọ truyền của vdk và PC đều là 9600.
Với đoặn trên thì từ trên PC em viết lại là ấn nút thì chỉ truyền 1 byte thôi thì ở dưới số lần ngắt có tăng lên, nhưng m chỉ bằng đến 4 là ko tăng nữa, mặc dù vẫn ấn truyền. Tr hợp này thì như nào hả bác. Mong bác giải thích cho em và chỉ em cách để làm sao mà mình truyền trên PC 1 lúc nhiều byte thì vdk nhận từng byte sẽ ngắt đúng hả bác

namqn 15-01-2009 02:24 AM

Khi có ngắt nhận ký tự ở dsPIC, bạn chỉ tăng biến đếm chứ không lấy ký tự ra khỏi bộ đệm của UART. Bạn nên tạo một bộ đệm ở dsPIC, khi có ký tự là lấy ngay ra khỏi bộ đệm (giả sử bộ đệm là buff[], trong đoạn code xử lý ngắt bạn thực hiện buff[i] = U2RXREG, i cần được khởi tạo trước đó).

Nên xóa cờ ngắt sau khi đã phục vụ xong ngắt, thay vì ngay đầu code xử lý ngắt. Cách đơn giản để phản hồi về PC của bạn là khi vào code xử lý ngắt, bạn đọc được ký tự nào thì gửi ngược ký tự đó về PC. Ví dụ, U2TXREG = buff[i].

Bộ đệm của UART trong dsPIC chỉ chứa được 4 ký tự, do đó bạn chỉ nhận được 4 ký tự đầu tiên (các ký tự sau đó sẽ bị dsPIC bỏ qua, vì lý do tràn bộ đệm, mời bạn xem lại các tài liệu đã được tôi đề cập trong tutorial). Cũng mời bạn đọc lại tutorial của tôi.

Những gì tôi vừa nêu trên đã được đề cập trong tutorial.

Thân,

ham_hoc_hoi 15-01-2009 06:03 PM

Trích:

Nguyên văn bởi namqn (Post 22166)
Khi có ngắt nhận ký tự ở dsPIC, bạn chỉ tăng biến đếm chứ không lấy ký tự ra khỏi bộ đệm của UART. Bạn nên tạo một bộ đệm ở dsPIC, khi có ký tự là lấy ngay ra khỏi bộ đệm (giả sử bộ đệm là buff[], trong đoạn code xử lý ngắt bạn thực hiện buff[i] = U2RXREG, i cần được khởi tạo trước đó).

Nên xóa cờ ngắt sau khi đã phục vụ xong ngắt, thay vì ngay đầu code xử lý ngắt. Cách đơn giản để phản hồi về PC của bạn là khi vào code xử lý ngắt, bạn đọc được ký tự nào thì gửi ngược ký tự đó về PC. Ví dụ, U2TXREG = buff[i].

Bộ đệm của UART trong dsPIC chỉ chứa được 4 ký tự, do đó bạn chỉ nhận được 4 ký tự đầu tiên (các ký tự sau đó sẽ bị dsPIC bỏ qua, vì lý do tràn bộ đệm, mời bạn xem lại các tài liệu đã được tôi đề cập trong tutorial). Cũng mời bạn đọc lại tutorial của tôi.

Những gì tôi vừa nêu trên đã được đề cập trong tutorial.

Thân,

thế để mình nhận được nhiều hơn 4 kí tự thì mình phải cóa bọ đêm đi hả bac, hay làm như thế nào ah.
Còn khi em tr 1 lúc 12 byte thì sao chỉ xảy ra có 2 lần ngắt ah

namqn 15-01-2009 06:26 PM

Trích:

Nguyên văn bởi ham_hoc_hoi (Post 22188)
thế để mình nhận được nhiều hơn 4 kí tự thì mình phải cóa bọ đêm đi hả bac, hay làm như thế nào ah.
Còn khi em tr 1 lúc 12 byte thì sao chỉ xảy ra có 2 lần ngắt ah

Bạn đọc kỹ lại bài viết của tôi. Tôi đã nói là đọc từ bộ đệm ra khi nhận được ký tự (để giải phóng bộ đệm cho việc nhận ký tự kế tiếp).

Khi bạn truyền ồ ạt 12 ký tự thì có thể giữa các ký tự có thời gian nghỉ không đủ lớn (một bạn thành viên trên diễn đàn này cũng đã gặp điều đó, tôi có đề nghị thêm vào một khoảng delay nhỏ giữa các ký tự ở phía PC thì đã giải quyết được). Ngoài phần phục vụ ngắt UART thì dsPIC còn có thể phải phục vụ các ngắt khác ở mức ưu tiên cao hơn, điều này bạn chưa cho biết.

Thân,

conglong 15-03-2009 09:59 AM

1 Attachment(s)
Thầy Nam cho em hỏi : em muốn giao tiêp PC vơi dsPIC30f2010 , bằng cách dùng PC gửi kí tự xuống dsPIC sau đó dsPIC hiện thị những kí tự vừ nhận lên màn hình LCD và gửi lại cho PC , project em làm là dựa trên code của thầy (cả TUTO LCD và UART), nhưng không hiểu sao nó không chạy, nếu không có hiện thị lên LCD thì chạy bình thường(em dùng hyper terminal) . Module LCD của em nó cũng chạy rồi . Nhưng cứ "nối" 2 module này lại là không chạy !
Em cảm ơn Thầy !
Trân trọng !

conglong 15-03-2009 10:13 AM

Thầy Nam cho em hỏi câu nữa liên quan tới C30 là: giả sử em đã có 2 project LCD và UART , mà trong project UART em muốn hiện thị LCD , vậy em có thể dung thêm lệnh preprocessor ở đầu project UART là
"#include LCD.c"
Để lấy hàm hiện thị
"LCD_puttring()"
trong LCD. c được không thầy ,
Em cảm ơn !
Trân trọng !.

namqn 15-03-2009 08:19 PM

Trích:

Nguyên văn bởi conglong (Post 23576)
Thầy Nam cho em hỏi : em muốn giao tiêp PC vơi dsPIC30f2010 , bằng cách dùng PC gửi kí tự xuống dsPIC sau đó dsPIC hiện thị những kí tự vừ nhận lên màn hình LCD và gửi lại cho PC , project em làm là dựa trên code của thầy (cả TUTO LCD và UART), nhưng không hiểu sao nó không chạy, nếu không có hiện thị lên LCD thì chạy bình thường(em dùng hyper terminal) . Module LCD của em nó cũng chạy rồi . Nhưng cứ "nối" 2 module này lại là không chạy !
Em cảm ơn Thầy !
Trân trọng !

Như thế nào là không chạy? Hoàn toàn không chạy hay chạy sai ở chỗ nào đó?

Tốc độ gửi dữ liệu của bạn ra sao? Mỗi giây một giá trị từ PC hay thế nào?

Hàm lcd_putstr() của bạn nhận đối số là một chuỗi ký tự, nhưng bạn lại gọi hàm với đối số là temp (có kiểu unsigned short). Lần trước tôi đã hướng dẫn bạn dùng hàm sprintf() để chuyển giá trị số thành một chuỗi ký tự trước khi xuất ra LCD rồi mà.

Thân,

namqn 15-03-2009 08:23 PM

Trích:

Nguyên văn bởi conglong (Post 23578)
Thầy Nam cho em hỏi câu nữa liên quan tới C30 là: giả sử em đã có 2 project LCD và UART , mà trong project UART em muốn hiện thị LCD , vậy em có thể dung thêm lệnh preprocessor ở đầu project UART là
"#include LCD.c"
Để lấy hàm hiện thị
"LCD_puttring()"
trong LCD. c được không thầy ,
Em cảm ơn !
Trân trọng !.

Bạn có thể kết hợp nhiều tập tin mã nguồn vào một project, những hàm nào nằm ở module biên dịch (tập tin mã nguồn) khác thì cần được khai báo trước khi sử dụng (thường dùng tập tin header để gộp các khai báo biến, prototype của hàm, ...).

Nếu bạn dùng "#include LCD.c" thì trình biên dịch chỉ đơn giản bê nguyên nội dung của "LCD.c" đặt vào tập tin mã nguồn hiện tại của bạn thôi. Tôi không cho đây là cách làm hay. Không rõ bạn có được học về lập trình C trong chương trình đại học hay không?

Thân,


Múi giờ GMT. Hiện tại là 11:20 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