Thông báo

Collapse
No announcement yet.

Sử dụng chức năng capture của PIC

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

  • Sử dụng chức năng capture của PIC

    Bạn nào có kinh nghiệm dùng chức năng capture của PIC để đo độ rộng xung xin chia xẻ một chút kinh nghiệm.
    Càng biết nhiều càng thấy mình biết ít.

  • #2
    Để đo độ rộng xung PIC có hỗ trợ mode capture. Trong mode này PIC sử dụng một timer để hoạt động, timer này hoạt động mỗi khi có cạnh lên (hay xuống) của tín hiệu ngoài và kết thúc khi có cạnh xuống (hay lên) của tính hiệu ngoài. Giá trị timer sẽ được tự động lưu vào một thanh ghi tạm để chờ bạn lưu.
    Datasheet của PIC nói rất rõ, bạn vào www.microchip.com tải về.
    Mode này rất hay dùng để xác định tần số của xung hay dùng để xác định vận tốc của động cơ.
    Chào thân.

    Comment


    • #3
      Nguyên văn bởi PIC
      Để đo độ rộng xung PIC có hỗ trợ mode capture. Trong mode này PIC sử dụng một timer để hoạt động, timer này hoạt động mỗi khi có cạnh lên (hay xuống) của tín hiệu ngoài và kết thúc khi có cạnh xuống (hay lên) của tính hiệu ngoài. Giá trị timer sẽ được tự động lưu vào một thanh ghi tạm để chờ bạn lưu.
      Datasheet của PIC nói rất rõ, bạn vào www.microchip.com tải về.
      Mode này rất hay dùng để xác định tần số của xung hay dùng để xác định vận tốc của động cơ.
      Chào thân.
      Tín hiệu vào được đưa tới chân CPPx, việc sử dụng Capture phải được cấu hình với bộ CPPx tương ứng. Chức năng Capture hoạt động based on một timer và thường là Timer2.
      Theo nghĩa chân phương capture là bắt giữ, vậy chế độ Capture hoạt động cũng như vậy. Ngay khi phát hiện sườn lên (hoặc xuống là do ta thiết lập) trên chân CPPx, giá trị hiện tại của Timer2 sẽ được lưu trữ lại.
      Vậy, để đo độ rộng xung ta có thể làm như sau :
      Thứ nhất : dùng hai bộ CPP1 và CPP2 với cùng chức năng Capture, tín hiệu vào được đưa tới cả hai chân CPP1 và CPP2 của PIC. CPP1 thiết lập với sườn lên còn CPP2 với sườn dưới. Như vậy, khi gặp sườn lên của xung-CPP1 sẽ lưu trữ, khi gặp sườn xuống thì CPP2 sẽ lưu trữ. Kết quả thu được từ hiệu hai giá trị này sẽ cho ta độ rộng của xung cần đo tính theo chu kỳ lệnh. Để kịp thời, ta có thể sử dụng ngắt cho CPP2 để ngay khi kết thúc xung ta có thể đo giá trị sử dụng cho các mục đích khác.
      Thứ hai : ta chỉ dùng một bộ CPP1 thôi, ban đầu thiết lập bắt giữ sườn lên. Ngay sau khi xảy ra ngắt, ta lại thiết lập nó theo sườn xuống. Cũng từ hai kết quả này ta sẽ thu được độ rộng của xung.


      Vài điều trao đổi, mong các bác chỉ giáo.

      Comment


      • #4
        Đo tần số

        Qua giới thiệu của PIC và Zero2one thì cũng khá dễ hiểu. Cái này mình cũng nắm được. Bây giờ quan trọng mình muốn đo tần số, tức là phải đo cả thời gian xung ở mức cao (T1) và thời gian xung ở mức thấp (T2)
        T=T1+T2

        f=1/T


        Vậy phải cấu hình cho chế độ Capture thế nào, hai bạn có thể giải thích một cách cụ thể được không?
        Càng biết nhiều càng thấy mình biết ít.

        Comment


        • #5
          Vậy thì bạn không cần phải đo cạnh lên và cạnh xuống nữa, mà chỉ cần đo các cạnh lên, lúc đó bạn lập tức có ngay T = T1 + T2.

          Trong bài toán rời rạc, tần số hay là thời gian là như nhau, nếu bạn sử dụng nó để tiếp tục tính tóan, thì nên chuzển tất cả sang miền thời gian, còn nếu bạn dùng nó để hiển thị kết quả tần số, thì bạn thực hiện phép chia để lấy kết quả.

          Tuy nhiên, một điểm khá hay mà bạn nên lưu ý, đó là thay vì thực hiện phép chia thì bạn nên thực hiện phép nhân.

          Bạn lưu ý rằng thời gian ở đây là chu kỳ máy, chứ không phải thời gian theo đơn vị giây.

          Chúc vui.
          Falleaf
          Công ty TNHH Thương mại và Giao nhận R&P
          58/57 Nguyễn Minh Hoàng - Phường 12 - Quận Tân Bình - TP.HCM
          mail@falleaf.net - VP: (04) 36408561 - (08) 38119870

          Comment


          • #6
            Dùng 1 hay 2 capture

            * Theo falleaf nói tôi vẫn thấy có thắc mắc :

            Nếu dùng chỉ dùng CCP1 , ta chỉ đo theo sườn lên như vậy có thể làm như sau :

            - Thiết lập ngắt theo sườn lên
            - Đặt biến count=0 (đếm lần ngắt)

            Trong Ct ngắt kiểm tra xem ngắt lần thứ nhất hay lần 2:

            Nếu ngắt lần 1 thì T1=giá trị hiện thời của timer
            count=count+1;

            Nếu ngắt lần 2 thì T2 =giá trị hiện thời của timer

            gán lại count=0;

            Như vậy T=T2-T1 chứ nhỉ? vì nó là khoảng lấy khoảng thời gian giữa 2 lần xuất hiện sườn lên của xung mà.


            * Còn nếu sử dụng cả CCP1 và CCP2 và đưa xung vào cả 2 chân của CCP1 và CCP2 thì khi sườn lên xuất hiện, theo như falleaf nói liệu sẽ phân biệt thế nào, giá trị đọc ở thanh ghi của CCP1 và CCP2 sẽ là như nhau chứ nhỉ
            Càng biết nhiều càng thấy mình biết ít.

            Comment


            • #7
              Nếu chỉ quan tâm tới tần số (chu kỳ) của xung thôi thì falleaf nói chính xác. Chỉ cần hai sườn lên hoặc hai sườn xuống liên tiếp nhau mà Capture thu được thì đủ xác định được tần số.
              Ngắt capture cho phép bạn lưu tức thời giá trị của capture, nếu không khi có capture xảy ra lần nữa thì giá trị trước đó sẽ bị đè lên.
              Nếu không cần biết dutycycle của xung thì ta chi cần dùng 1 capture thôi không cần dùng hai cái như bạn ATYLA đâu.
              Còn việc thiết lập cụ thể thì tùy thuộc vào con nào, datasheet ghi rất rõ mà bạn xem hiểu liền hè.
              Chào bạn.

              Comment


              • #8
                ban can ve lai so do xung.

                Mot xung chi co 1 canh len, va mot canh xuong.

                Chu ky nhiem vu bat dau bang 1 xung len va ket thuc bang 1 xung xuong.

                Chy ky nghi bat dau bang 1 xung xuong (cua chu ky nhiem vu truoc do), va mot xung len (cua chu ky nhiem vu tiep theo sau).

                Nhu vay, chi can xac dinh khoang cach giua 2 xung len, co nghia la khoang cach ve thoi gian giua hai xung lien tiep nhau, do chinh la chu ky cua tin hieu.

                Va tu chu ky do, ban suy ra tan so.

                Ban can phai ve ra giay, khong nen ngoi tuong tuong, mat thoi gian, khong duoc ich loi gi.

                Nguoi Duc co mot cau noi: Cang nghi cang sai, tot hon la biet no chu dung nen nghi ve no.
                Falleaf
                Công ty TNHH Thương mại và Giao nhận R&P
                58/57 Nguyễn Minh Hoàng - Phường 12 - Quận Tân Bình - TP.HCM
                mail@falleaf.net - VP: (04) 36408561 - (08) 38119870

                Comment


                • #9
                  OK

                  Thực ra nguyên tắc đo chu kì (tấn số) tín hiệu là như vậy, dùng capture theo cách falleaf nói là chính xác .

                  Cách thực hiện của tôi cũng đúng, chỉ là lúc đầu chưa thống nhất về diễn đạt thôi.
                  Càng biết nhiều càng thấy mình biết ít.

                  Comment


                  • #10
                    Noi tin hieu can do vao chan CCP1 va CCP2.
                    Chon CCP1 mode falling, CCP2 rissing.
                    Dat che do ngat cho CCP1 va CCP2.
                    Dat timer1 tuy theo do chinh xac cua tin hieu ban can do
                    khai bao bien
                    long value;
                    int CCP2(void)
                    {
                    value = CCP2 - CCP1;
                    settimer1(0);
                    }

                    Khi do do rong xung se la value X thoi gian cua 1 xung clock cap cho timer1.
                    Chux thanh cong.
                    Nhà sản xuất chuyên nghiệp các sản phẩm OEM cho gia dụng và công nghiệp.

                    Biến tần
                    Máy giặt
                    Lò vi sóng
                    Bếp từ.
                    Tủ lạnh.
                    Điều hòa

                    Comment


                    • #11
                      Làm như vậy là theo cách truyền thống có hướng dẫn bác Minh Hà à, cách do tần số làm như mình làm là tốt nhất, bởi vì chỉ cần 1 chân, ngoài ra không cần dùng ngắt cũng có thể làm được. Không nên sử dụng ngắt quá nhiều, cái gì cần thì dùng, không cần thì thôi.

                      Ngay cả khi không dùng ngắt thì giá trị vẫn được lưu tại đó. Khi nào cần tính thì lôi ra tính là xong.
                      Falleaf
                      Công ty TNHH Thương mại và Giao nhận R&P
                      58/57 Nguyễn Minh Hoàng - Phường 12 - Quận Tân Bình - TP.HCM
                      mail@falleaf.net - VP: (04) 36408561 - (08) 38119870

                      Comment


                      • #12
                        Đo tấn số dùng capture

                        #include <16F876A.h>
                        #use delay(clock=4000000)
                        #fuses HS,NOWDT, NOPROTECT
                        #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)

                        int16 CCP1Value;
                        int16 CCP1OldValue;
                        BOOLEAN CCP1Captured;


                        #int_CCP1
                        CCP1_isr()
                        {
                        CCP1Value = CCP_1 - CCP1OldValue;
                        CCP1OldValue = CCP_1;
                        CCP1Captured = TRUE;
                        }
                        //--------------------------------------------------------------------------
                        void Init_ccp(void)
                        {
                        setup_ccp1(CCP_CAPTURE_RE);
                        setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
                        CCP1Value = 0;
                        CCP1OldValue = 0;
                        CCP1Captured = TRUE;
                        enable_interrupts(INT_CCP1);
                        enable_interrupts(GLOBAL);
                        }
                        //--------------------------------------------------------------------------
                        void main()
                        {
                        float Freq;
                        Init_ccp();
                        printf("Frequence test:\r\n");
                        while (TRUE) {

                        if (CCP1Captured) {

                        // F = 1/T
                        // Timer1 prescaler DIV_BY_8
                        // Pic16F876 4Mz -> 0.000001 * 8

                        Freq = 1.0/((float)CCP1Value*8e-6);
                        printf("Freq:%f\r\n",Freq);
                        CCP1Captured = FALSE;
                        }
                        }
                        }
                        Càng biết nhiều càng thấy mình biết ít.

                        Comment


                        • #13
                          Re: Đo tấn số dùng capture

                          Nguyên văn bởi ATYLA
                          #include <16F876A.h>
                          #use delay(clock=4000000)
                          #fuses HS,NOWDT, NOPROTECT
                          #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)

                          int16 CCP1Value;
                          int16 CCP1OldValue;
                          BOOLEAN CCP1Captured;


                          #int_CCP1
                          CCP1_isr()
                          {
                          CCP1Value = CCP_1 - CCP1OldValue;
                          CCP1OldValue = CCP_1;
                          CCP1Captured = TRUE;
                          }
                          //--------------------------------------------------------------------------
                          void Init_ccp(void)
                          {
                          setup_ccp1(CCP_CAPTURE_RE);
                          setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
                          CCP1Value = 0;
                          CCP1OldValue = 0;
                          CCP1Captured = TRUE;
                          enable_interrupts(INT_CCP1);
                          enable_interrupts(GLOBAL);
                          }
                          //--------------------------------------------------------------------------
                          void main()
                          {
                          float Freq;
                          Init_ccp();
                          printf("Frequence test:\r\n");
                          while (TRUE) {

                          if (CCP1Captured) {

                          // F = 1/T
                          // Timer1 prescaler DIV_BY_8
                          // Pic16F876 4Mz -> 0.000001 * 8

                          Freq = 1.0/((float)CCP1Value*8e-6);
                          printf("Freq:%f\r\n",Freq);
                          CCP1Captured = FALSE;
                          }
                          }
                          }
                          Tui có mấy ý kiến be bé, góp ý cùng bác ATYLA:
                          +Dòng lệnh: CCP1Value = CCP_1 - CCP1OldValue;
                          nếu chỉ viết như vậy thì khi bô định thời đếm đến 65535 thì sẽ tràn. Bởi vậy sẽ ko chính xác khi tính toán. Biểu thức trên sẽ bị sai. Biểu thúc trên đúng khi bộ định thời ko tràn. Vì cách lập trình gán liên tiếp này sẽ tràn.
                          +Khắc phuc bằng cách
                          #int_CCP1
                          CCP1_isr()
                          {
                          CCP1Value = CCP_1;
                          settimer1(0); //nạp giá trị = 0 vào timer
                          CCP1Captured = TRUE;
                          }
                          Nhưng cách này sẽ sai só, vài chục chu kỳ, nên phải bù = phần mềm, kiểu như:
                          #int_CCP1
                          CCP1_isr()
                          {
                          CCP1Value = CCP_1+Ofset;//Ofset là do delay khi vào ngắt+phục vụ ngắt.
                          settimer1(0); //nạp giá trị = 0 vào timer
                          CCP1Captured = TRUE;
                          }
                          #int_CCP1
                          CCP1_isr()
                          {
                          CCP1Value = CCP_1;
                          settimer1(0); //nạp giá trị = 0 vào timer
                          CCP1Captured = TRUE;
                          }

                          Một cách hay hơn là:
                          #int_CCP1
                          CCP1_isr()
                          {
                          CCP1Value = CCP_1 - CCP1OldValue;
                          CCP1OldValue = CCP_1;
                          CCP1Captured = TRUE;
                          }
                          Nhưng lại cài đặt thêm 1 timer1, khi tràn nó sẽ thông báo cho mình. Căn cứ vào đó minh có thể lam chủ được CCP1Value = CCP_1 - CCP1OldValue; một cách chính xác hơn căn cứ vào nó tràn hay ko

                          #int_CCP1
                          CCP1_isr()
                          {
                          if(đã tran timer)
                          {
                          CCP1Value =CCP_1+ (65536-CCP1OldValue ) ;
                          }else
                          {
                          CCP1Value = CCP_1 - CCP1OldValue;
                          }
                          CCP1OldValue = CCP_1;
                          CCP1Captured = TRUE;
                          }

                          Ý tưởng là như vậy, các bác cho ý kiến
                          -------------------

                          Comment


                          • #14
                            Tràn bộ định thời

                            Thực ra theo tôi bộ định thời tràn hay ko thì đâu có ảnh hưởng gì, tôi chỉ cần thêm câu lệnh:

                            if(ccp_1>ccpoldvalue)
                            {}

                            là xong.
                            Vì khi tràn 655535 sẽ chuyển về đếm từ 0, chương trình nó sẽ bỏ qua thời điểm tràn mà ko thực hiện phép trừ nữa (vẫn gửi lên PC giá trị trước đó).

                            Bác CHIBANG nghĩ sao?
                            Càng biết nhiều càng thấy mình biết ít.

                            Comment


                            • #15
                              Re: Tràn bộ định thời

                              Nguyên văn bởi ATYLA
                              Thực ra theo tôi bộ định thời tràn hay ko thì đâu có ảnh hưởng gì, tôi chỉ cần thêm câu lệnh:

                              if(ccp_1>ccpoldvalue)
                              {}

                              là xong.
                              Vì khi tràn 655535 sẽ chuyển về đếm từ 0, chương trình nó sẽ bỏ qua thời điểm tràn mà ko thực hiện phép trừ nữa (vẫn gửi lên PC giá trị trước đó).

                              Bác CHIBANG nghĩ sao?
                              1-Giả sử giá trị cppoldvalue là 3000; nhưng do thời gian capture quá dài, bởi thế ví dụ giá trị timer 1 tăng dần: 3000,3001,3002,...65535,0,1,...3000,3001, tại thời điểm này nếu có capture thì vẫn đảm bảo: if(ccp_1>ccpoldvalue){} nhưng thực tế lại khác hẳn. Đó là chưa nói chuyện nó tràn nhiều lần mà capture vẫn đảm bảo if(ccp_1>ccpoldvalue){}

                              2-Hơn nữa, cho dù thời gian capture là bé đi, bác lại thỉnh thoảng bỏ phí mất 1 giá trị khi tràn.

                              Bởi thế theo em, bác cài đặt ngắt timer đó luôn. Khi nó tràn mình biết ngay, làm 1 biến để lưu trữ số lần tràn.
                              -------------------

                              Comment

                              Về tác giả

                              Collapse

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

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

                              Collapse

                              Đang tải...
                              X