Thông báo

Collapse
No announcement yet.

Một chút thắc mắc về USART của AVR

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Một chút thắc mắc về USART của AVR

    Mình đang làm việc với AVR ATMEGA32, mới dùng nên có nhiều cái chưa có kinh nghiệm nên muốn hỏi các bạn vài câu mong nhận được giải đáp:

    1. Lệnh printf() có dùng được không? Mình dùng CodeVision. Nếu dùng được thì phải làm những gì để sử dụng được lệnh này (phải cài đặt USART như thế nào?)

    2. Thông thường, muốn gửi và nhận data qua serial thì ta đọc và ghi vào UDR nhưng nêu là dữ liệu lớn hơn 8bit thì lại phải cắt ra làm 2 để gửi và nhận lần lượt. Vậy, ai có cách nào đơn giản hơn không? Chứ nếu cách này thì dễ nhầm quá.

    3. Nếu mình muốn gửi và nhận một mảng gồm khoảng 200 phần tử kiểu int thì có bạn nào có cách hay mà đơn giản để thực hiện không?

    Đó là 3 câu hỏi mà mình đang thắc mắc. Các bạn giúp mình nhé.

    Cảm ơn nhiều.
    Lai như lưu thuỷ hề, thệ như phong
    Bất tri hà xứ lai hề, hà sở chung

  • #2
    1. Lệnh printf dùng được phải #include <stdio.h>
    Cài đặt:
    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: On
    // USART Transmitter: On
    // USART Mode: Asynchronous
    // USART Baud rate: 38400
    UCSRA=0x00;
    UCSRB=0xD0;
    UCSRC=0x86;
    UBRRH=0x00;
    UBRRL=0x0C;
    2. Muốn dùng vddk truyền số kiểu int ko cách nào khác phải truyền 2 lần, hi_byte và lo_byte và ko có gì là nhầm được cả
    void put_int(unsigned int dulieu)
    {
    unsigned char hi_bye, lo_byte;
    hi_byte = (unsigned char)(dulieu>>8);
    lo_byte = (unsigned char)dulieu;
    putchar(hi_byte);
    putchar(lo_byte);
    }
    3. Nếu dùng ATMEGA32 mà muốn truyền 200 biến kiểu int thì ko được, phải dùng RAM ngoài mà con này ko hỗ trợ (dũng con khác đi), còn ko thì chúng phải được lưu sẵn trong flash, hoặc EEPROM...
    |

    Comment


    • #3
      Nguyên văn bởi hightech_uc Xem bài viết
      3. Nếu dùng ATMEGA32 mà muốn truyền 200 biến kiểu int thì ko được, phải dùng RAM ngoài mà con này ko hỗ trợ (dũng con khác đi), còn ko thì chúng phải được lưu sẵn trong flash, hoặc EEPROM...
      Bạn có thể lý giải tại sao không được?

      Theo mình đọc datasheet, ATMEGA32 có 2Kbyte SRAM trong. Nếu mình có mảng 200 phần tử kiểu int thì nó tốn ít nhất 400byte bộ nhớ. Như vậy mình nghĩ là có thể dùng ATMEGA32 được chứ?

      Cảm ơn đã trả lời.

      Nhân đây, hỏi thêm cậu câu nữa. Nếu dùng lệnh printf() để truyền ra cổng Serial một dữ liệu có độ dài hơn 8bit thì có phải chia đôi dữ liệu đó như cách bình thường không? Hình như thằng printf() này đảm nhiệm luôn phần đó rồi đúng không?
      Lai như lưu thuỷ hề, thệ như phong
      Bất tri hà xứ lai hề, hà sở chung

      Comment


      • #4
        Nguyên văn bởi Vo_Duy_Thanh Xem bài viết
        Bạn có thể lý giải tại sao không được?

        Theo mình đọc datasheet, ATMEGA32 có 2Kbyte SRAM trong. Nếu mình có mảng 200 phần tử kiểu int thì nó tốn ít nhất 400byte bộ nhớ. Như vậy mình nghĩ là có thể dùng ATMEGA32 được chứ?

        Cảm ơn đã trả lời.

        Nhân đây, hỏi thêm cậu câu nữa. Nếu dùng lệnh printf() để truyền ra cổng Serial một dữ liệu có độ dài hơn 8bit thì có phải chia đôi dữ liệu đó như cách bình thường không? Hình như thằng printf() này đảm nhiệm luôn phần đó rồi đúng không?
        Dùng printf() là được. Bạn xem thêm phần 'Help' mục 'Library/Standard IO' sẽ rõ. Mà dùng printf() thì tốn bộ nhớ lắm, lại dài dòng khó hiểu, cứ chia đôi dữ liệu ra làm 2 byte có phải dễ dàng hơn không!

        for(i=0;i<200;i++)
        {
        putchar(mang[i]/256); delay();
        putchar(mang[i]%256); delay();
        }
        !e

        Comment


        • #5
          Lại thắc mắc nữa . Mình dùng 2 loại lệnh sau:

          1.printf("%d",Mang[i]); // Gửi toàn bộ phần tử thứ i ra cổng serial dưới dạng số int


          2. UDR = Mang[i]/256; //gửi lần lượt
          UDR = Mang[i]%256;

          Kết quả câu lệnh 1 (theo mình mô phỏng trên Proteus) thì nó ra đúng giá trị của phần tử Mang[i] (tức là ví dụ Mang[i] có giá trị là 405 thì mô phỏng hiện lên trên cái Virtual Terminal hiện lên số 405)

          Kết quả câu lệnh 2 chỉ hiện lên chữ f, hoặc số 3 hoặc dấu tam giác trỏ ngược xuống nhưng rất giống nhau, giống nhau cho tất cả các phần tử của mảng.

          Các bạn giải thích hộ mình được không?
          Lai như lưu thuỷ hề, thệ như phong
          Bất tri hà xứ lai hề, hà sở chung

          Comment


          • #6
            Nguyên văn bởi Vo_Duy_Thanh Xem bài viết
            Lại thắc mắc nữa . Mình dùng 2 loại lệnh sau:

            1.printf("%d",Mang[i]); // Gửi toàn bộ phần tử thứ i ra cổng serial dưới dạng số int


            2. UDR = Mang[i]/256; //gửi lần lượt
            UDR = Mang[i]%256;

            Kết quả câu lệnh 1 (theo mình mô phỏng trên Proteus) thì nó ra đúng giá trị của phần tử Mang[i] (tức là ví dụ Mang[i] có giá trị là 405 thì mô phỏng hiện lên trên cái Virtual Terminal hiện lên số 405)

            Kết quả câu lệnh 2 chỉ hiện lên chữ f, hoặc số 3 hoặc dấu tam giác trỏ ngược xuống nhưng rất giống nhau, giống nhau cho tất cả các phần tử của mảng.

            Các bạn giải thích hộ mình được không?
            Câu lệnh 1, theo mình hiểu thì nó đã 'chặt' số 405 thành 3 byte chứa 4, 0 và 5. Sau đó cộng thêm mã ASCII (của số 0) rồi gửi vể máy tính, khi này ta sẽ nhận đc các kí tự '4', '0' và '5' viết liền lại là chuỗi "405"

            Câu lệnh 2 thì lại là cách làm trực tiếp, vdk truyền gì thì m.tính nhận vậy, bạn muốn thấy đc chuỗi "405" thì phải giải mã hex->ASCII. Bạn lập trình bằng Codevision, sau khi biên dịch và nạp trực tiếp vào ic, thì chạy "Run the Terminal" ngay trên phần mềm Codevision. Kết quả trực tiếp từ vdk truyền về máy tính sẽ hiển thị ngay trên trang giao diện này. Nhấn nút ASCII/Hex để thấy máy tính hiển thị khác nhau cho CÙNG MỘT CON SỐ
            !e

            Comment


            • #7
              Nguyên văn bởi zemen Xem bài viết
              Câu lệnh 1, theo mình hiểu thì nó đã 'chặt' số 405 thành 3 byte chứa 4, 0 và 5. Sau đó cộng thêm mã ASCII (của số 0) rồi gửi vể máy tính, khi này ta sẽ nhận đc các kí tự '4', '0' và '5' viết liền lại là chuỗi "405"

              Câu lệnh 2 thì lại là cách làm trực tiếp, vdk truyền gì thì m.tính nhận vậy, bạn muốn thấy đc chuỗi "405" thì phải giải mã hex->ASCII. Bạn lập trình bằng Codevision, sau khi biên dịch và nạp trực tiếp vào ic, thì chạy "Run the Terminal" ngay trên phần mềm Codevision. Kết quả trực tiếp từ vdk truyền về máy tính sẽ hiển thị ngay trên trang giao diện này. Nhấn nút ASCII/Hex để thấy máy tính hiển thị khác nhau cho CÙNG MỘT CON SỐ
              Khỏi cần qua mô phỏng làm chi cho rối rắm!
              !e

              Comment


              • #8
                Lại "moi" cái topic này lên rồi ....

                Hiện tại em đang dùng AT16 giao tiếp với máy tính. Em muốn hỏi các bác rằng:
                Làm cách nào để nhận được 1 chuỗi kí tự được đẩy từ máy tính xuống.
                Ví dụ: OK26, trong đó OK là dấu hiệu của tín hiệu , và 26 là data mình cần thu thập.

                Mong các bác chỉ giáo!

                Hiện tại em đã làm như thế này nhưng chưa đạt được kết quả như ý muốn:
                1. Chờ tín hiệu trong bộ đệm có tín hiệu: rx_counter
                2. Nhảy đến, lưu dữ liệu vào text[5] ..
                3. Hiển thị ...

                KHông biết e đã làm sai ở đâu nhỉ?
                |

                Comment


                • #9
                  Bạn thử đoạn code này xem sao.
                  Trên terminal bạn nhập 'o' + Enter + 26 + Enter.

                  Kết quả là

                  o
                  o
                  16
                  52

                  Bạn có thể đọc thêm luồng này sẽ rỏ hơn:Tại đây

                  #include <mega32.h>
                  #include <stdio.h>
                  #include <stdlib.h>
                  #include<string.h>

                  /************************************************** **/

                  char str[10],chuoi[10],chuoidaxuly[10];
                  float so;


                  while (1)
                  {

                  gets(str,10); // khi có newline thì hàm này nhận chuổi mới.
                  puts(str);
                  if(strchr(str,'o'))
                  {

                  gets(str,10);
                  {
                  strcpy(chuoi,str);
                  so=atof(chuoi);
                  so=so*2;
                  ftoa(so,0,chuoidaxuly);
                  puts(chuoidaxuly);
                  }

                  }
                  };
                  }
                  Last edited by lehanhla; 28-04-2009, 21:42.
                  Phone: 0909319477
                  Email:

                  Comment


                  • #10
                    To Brilliant !

                    Trong thực tế khi truyền dữ liệu qua cổng COM hoặc bất kì hình thức truyền thông nào khác, người ta không bao giờ truyền riêng dữ liệu. Để đảm bảo tính bảo mật, tính đúng đắn của dữ liệu thì người ta thường đóng gói dữ liệu thành các frame. Các frame này thường chia thành một số các trường ví dụ như:
                    <header><code><length><data><checksum>
                    Số lượng và nội dung của các trường này do bên truyền và bên nhận quy định với nhau.
                    Mỗi khi truyền, bên truyền sẽ đóng gói dữ liệu theo đúng frame. Mỗi khi nhận, bên nhận kiểm tra và chỉ nhận đúng những gì đóng gói đúng frame, còn lại sẽ bị bỏ qua

                    Thân mến,
                    For a better world

                    Comment


                    • #11
                      Mình đã thực hiện được phép truyền nhận được dữ liệu dưới dạng chuỗi rồi!

                      Có lẽ em nên làm theo cách của bác Toan.LV, làm như vậy sẽ đảm bảo được độ chính xác cao. Nhưng điều em băn khoăn là trong bài của em thì việc e đưa ra 2 khung truyền, mà mỗi khung đó lại có thể có sự thay đổi về số lượng byte nội dung truyền. Vậy làm thế nào để đảm bảo được bảo toàn dữ liệu.


                      Để e làm đã, rồi sẽ hỏi tiếp các bác trong ít thời gian nữa!
                      Last edited by Brilliant; 28-04-2009, 17:59.
                      |

                      Comment


                      • #12
                        Đã hoàn thành với khung truyền đầu tiên. Nhưng hiện em đã có 2 dạng dữ liệu cần truyền đi. E nói đơn giản thế này nhé.

                        Nội dung khung truyền của 2 khung như sau:
                        + Nội Dung 1: ví dụ em muốn truyền đi số 25. đã test và ok
                        + Nội dung 2: e muốn truyền xuống VDDK 5 tham số. Vậy phải làm thế nào để nhận dạng được 3 tham số đó .

                        E định làm với mức độ đưa vào nội dung truyền như sau:

                        QGiáTrị1WGiáTrị2EGiáTrị3RGiáTrị4TGiáTrị5

                        trong đó các từ khóa QWERT làm nhiệm vụ làm "cái mốc" cho các giá trị sau.

                        Làm như vậy thì việc nhận dạng các giá trị tuơng đối khó khăn ở VDDK. có pác nào có cao kiến thì cho em lời chỉ dẫn cái. Thanks
                        |

                        Comment


                        • #13
                          - Việc đóng gói dữ liệu nhằm đảm bảo một sự thỏa hiệp giữa bên phát và bên thu, để cho bên thu nhận được đúng dữ liệu mà bên phát đã gửi đi.
                          - Về định dạng của frame đóng gói (thường gọi là giao thức truyền thông) thì cả bên phát và bên thu đã quy định và ngầm hiểu với nhau, bên thu chỉ nhận những dữ liệu đóng gói trong các frame hợp lệ (bên thứ 3 nếu không biết giao thức sẽ không gửi được dữ liệu cho bên thu).
                          - Về ý định của bạn:
                          QGiáTrị1WGiáTrị2EGiáTrị3RGiáTrị4TGiáTrị5
                          Đây là trong trường hợp bạn làm chơi với số lượng byte truyền rất ít, nên có thể thực hiện được, nhưng trong thực tế số lượng byte truyền đi là hàng vài chục byte, vài trăm byte, thậm chí nhiều hơn như vậy thì rất khó thực hiện. Hơn nữa frame truyền phải quy định thống nhất để truyền nhiều nội dung khác nhau trong nhiều lần, cách làm của bạn như vậy không phù hợp.
                          - Tôi thử lấy một ví dụ thế này để bạn hình dung: Bạn muốn truyền 10 byte code của LED 7 thanh xuống lưu vào một mảng trong bộ nhớ của VDK để hiển thị. Ngoài ra bạn cũng muốn truyền xuống 32 byte dữ liệu khác lưu vào một vùng nhớ khác để đưa ra hiển thị trên ma trận LED. Vậy làm thế nào để bạn phân biệt được đâu là dữ liệu cho LED 7 thanh, đâu là dữ liệu cho ma trận LED để nhận đúng và lưu vào đúng vùng nhớ của chúng. bạn có thể thực hiện thế này:
                          - Quy định một frame có các trường như sau:
                          <header><code><length><data><checksum>

                          -Trường <header> rất quan trọng, nó là điểm khởi đầu để VDK nhận biết đó là một frame dữ liệu, nên bạn phải quy định sao cho nó là duy nhất. Vì đôi khi dữ liệu bạn cần truyền có thể trùng với header. Số byte header càng ít thì khả năng trùng càng cao. Giả sử tôi chọn luôn header là "QWERT" như bạn chọn.
                          - Trường <code>: Bạn quy định các mã khác nhau cho các công việc khác nhau, ví dụ tôi quy định code = 0xFF sẽ là dữ liệu dành cho LED 7 thanh còn code = 0x00 sẽ là dữ liệu dành cho LED ma trận chẳng hạn.
                          - Trường <length>: dùng để nêu độ dài của các byte dữ liệu, chẳng hạn length = 0x0A (10) với LED 7 thanh và 0x20 (32) với LED ma trận
                          - Trường <data>: bạn hãy liệt kê dữ liệu mà bạn muốn truyền ở trường này
                          - trường checksum: Bạn quy định một phép toán nào đấy liên quan đến các byte trong frame truyền để tính ra một byte và đặt làm checksum, gửi kèm với dữ liệu. Khi VDK nhận được, nó sẽ căn cứ vào các byte nhận được mà tính lại checksum và so sánh với checksum bên phát gửi để biết dữ liệu có đúng hay không. Phép toán tùy bạn quy định ví dụ checksum = tổng của tất cả các byte hoặc checksum = xor của tất cả các byte ...

                          - Sau khi quy định frame xong, bạn được 2 frame như sau:
                          Frame 1 cho LED 7 thanh:
                          <QWERT><0xFF><0x0A><10 byte><checksum>
                          Frame 2: cho LED matran:
                          <QWERT><0x00><0x20><32 byte><checksum>

                          - Bây giờ gửi các frame này từ máy tính xuống, VDK sẽ kiểm tra header, checksum và các thông tin liên quan, nếu đúng nó sẽ nhận dữ liệu. Và khi nhận rồi nó kiểm tra trường code và biết mình phải dùng dữ liệu vừa nhận để làm gì.

                          Việc quy định frame truyền như thế nào, và các thuật toán đóng gói, bóc tách dữ liệu như thế nào hoàn toàn là do bạn, vì thế mình có rất nhiều lựa chọn.

                          Thân mến,
                          For a better world

                          Comment


                          • #14
                            Nguyên văn bởi Toan.Lv Xem bài viết
                            - Sau khi quy định frame xong, bạn được 2 frame như sau:
                            Frame 1 cho LED 7 thanh:
                            <QWERT><0xFF><0x0A><10 byte><checksum>
                            Frame 2: cho LED matran:
                            <QWERT><0x00><0x20><32 byte><checksum>
                            Trước tiên cảm ơn bác về những kinh nghiệm quý báu. Những gì bác nói em hiểu hết ...và dừng lại ở chỗ này. E đồng ý với bác chỗ này. Và e cũng sẽ làm như thế!

                            Và khó khăn của em giờ là thủ thuật nhận dữ liệu, với CodeVision thì em có sử dụng hàm nhận dữ liệu theo line: gets() ...nhưng hiện tại đang khó khăn với hàm này ở phần tham số: độ dài của chuỗi text.

                            char *gets(char *str, unsigned char len)

                            inputs, using getchar, the character string str terminated by the new line character.
                            The new line character will be replaced with 0.
                            The maximum length of the string is len. If len characters were read without encountering the new line character, then the string is terminated with 0 and the function ends.
                            The function returns a pointer to str.
                            E giả sử với cùng 1 khung truyền thì giả sử với 1 giá trị nào đó: 2.35 thì số lượng byte dùng là 4 byte, còn với 2.351 thì số lượng byte dùng là 5 byte. Như vậy câu hỏi đặt ra là: làm thế nào để xác định được phần giá trị mà mình cần quan tâm.

                            với phần mã hóa nội dung: Q2.35W15.26E36.5 làm thế nào để nhận được các giá trị của nóllafafnn lượt là: 2.35, 15.26, 36.5 ....và với trường hợp khi thay đổi 2.35 thành 2.351 thì xử lí thế nào!
                            |

                            Comment


                            • #15
                              Và khó khăn của em giờ là thủ thuật nhận dữ liệu, với CodeVision thì em có sử dụng hàm nhận dữ liệu theo line: gets() ...nhưng hiện tại đang khó khăn với hàm này ở phần tham số: độ dài của chuỗi text.
                              - Bạn không nên sử dụng hàm gets (getchar - nếu bạn dùng codevision) để nhận dữ liệu, hàm này sử dụng phương pháp thăm dò (polling) nên khi nó chưa nhận được dữ liệu thì CPU sẽ luôn phải chờ trong hàm đó --> mất thời gian, đôi khi nó chờ mãi rồi chít luôn trong đó không ra được.
                              - Bạn nên sử dụng ngắt cổng nối tiếp để nhận dữ liệu. Mỗi lần ngắt VDK nhận được một byte, như vậy đối với độ dài chuỗi dữ liệu bạn quy định một biến đếm, mỗi lần ngắt bạn tăng biến đếm lên 1, sau n lần ngắt thì chuỗi dữ liệu của bạn có độ dài là n byte.
                              E giả sử với cùng 1 khung truyền thì giả sử với 1 giá trị nào đó: 2.35 thì số lượng byte dùng là 4 byte, còn với 2.351 thì số lượng byte dùng là 5 byte. Như vậy câu hỏi đặt ra là: làm thế nào để xác định được phần giá trị mà mình cần quan tâm.
                              Khi truyền dữ liệu thì bản thân VDK và máy tính nó không hiểu bạn truyền cái gì đâu, nó chỉ biết làm những gì bạn ra lệnh cho nó thôi. Còn việc dữ liệu bạn truyền đi là 235 hay 2.35 thì đó là do bạn quy định và tự hiểu cách xử lý khi truyền và nhận thôi. Ví dụ bạn muốn truyền 2.35 qua cổng COM thì bạn quy định truyền 3 byte: byte đầu là phần nguyên, byte thứ 2 là số thập phân thứ 1 sau dấu phẩy, byte 3 là số thập phân thứ 2 sau dấu phẩy. Đến khi nhận, bạn được 1 chuỗi 3 byte, trong đầu bạn đã ngầm hiểu ý nghĩa của từng byte rồi, và nếu hiển thị lên thì bạn sẽ thêm dấu "," vào giữa byte 1 và hai byte sau là được.
                              - Vì vậy việc quy định frame truyền và xử lý dữ liệu như thế nào hoàn toàn là do thuật toán của bạn, bạn bảo thế nào thì VDK nó làm thế. Bạn chỉ cần quy định thế nào để khi nhận dữ liệu mình xác định đúng giá trị cần truyền là được.

                              Thân mến,
                              For a better world

                              Comment

                              Về tác giả

                              Collapse

                              Vo_Duy_Thanh Tìm hiểu thêm về Vo_Duy_Thanh

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X