Thông báo

Collapse
No announcement yet.

Lập trình ngắt trong PSOC

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

  • Lập trình ngắt trong PSOC

    Chào các bác

    Em mới vào nghề xin hỏi ai đã có kinh nghiệm làm về PSoc có thể chia sẻ chút ít kinh nghiệm về lập trình ngắt trong Psoc được không?. Xin các bác cho luôn 1 ví dụ đơn giản và cụ thể. Rất mong các cao thủ trợ giúp
    |

  • #2
    Lập trình ngắt à ?

    Để lập trình ngắt bạn phải biết mấy điều sau:
    - Xác nhận lựa chọn sinh ra các hàm ngắt khi genate application (cái này phải thiết lập trong IDE. Vào phần project/option/......)
    -Vào file các file ví dụ như Counter8Int.asm ở trong project của mình bạn sẽ thấy bảng vectỏ ngắt trong đó, khi chưa có chương trình điều khiển ngắt thì phần này nó để trống. Bạn có thể viết chwơng trình điều khiển ngắt vào đây, nhưng tốt nhất là nên viết ra một file khác rồi gọi nó (vì thế nên lệnh cuối cùng bao giờ cũng là RETI).
    - Trong phần chương trình chính main.asm bạn phải khai báo trình điều khiển ngắt InterruptHandler tên_hàm_ngắt ;
    -Việc viết bằng C hay Asm có một chút khác nhau khi gọi ngắt. Bạn nên tham khảo C compiler user guide để biết, chứ nói ở đây không tiện vì nó lằng nhằng lắm.

    Hôm nào rỗi tui post cái AN mô tả cái việc này lên, nó dạy kỹ lắm, đọc xong làm được liền.
    Ở đời khác thường, làm sự nghiệp phi thường...Cùng thì tự tốt lấy ta, đạt thì đem hạnh phúc cho thiên hạ.---(Gia Cát Khổng Minh)

    Comment


    • #3
      Lập trình ngắt trong PSoC cũng giống như lập trình ngắt cho các họ vi điều khiển khác tức là bạn vẫn phải viết chương trình phục vụ ngắt, đặt nó vào chỗ vecto ngắt của ngắt tương ứng hoặc đơn giản hơn, bạn dùng một lệnh ljmp (long jump) tại địa chỉ vecto ngắt để cho nó nhảy đến chương trình ngắt của bạn.
      PSOC hỗ trợ rất nhiều nguồn ngắt.
      Để khai báo một ngắt trong C bạn làm như sau
      #pragma interrupt_handler my_isr; //cái này là bắt buộc ngoài tên my_isr là tên chương trình phục vụ ngắt (có thể lấy tên bất kì hoặc lấy tên mặc định)

      void my_isr(void); //khai báo hàm phục vụ ngắt

      void main (void)
      {
      .
      .
      .
      }

      //////////////
      void my_isr(void)
      {
      .
      .
      .
      }


      Khi cấu hình xong, trong file boot.asm sẽ có bảng địa chỉ các vecto ngắt và có thể chèn một lệnh ljmp để gọi chương trình phục vu ngắt tương ứng với các vecto ngắt như sau
      AREA TOP (ROM, ABS, CON)

      [code:1] org 0 ;Reset Interrupt Vector
      jmp __Start ;First instruction executed following a Reset

      org 04h ;Supply Monitor Interrupt Vector
      halt ;Stop execution if power falls too low

      org 08h ;Analog Column 0 Interrupt Vector
      // call void_handler
      reti

      org 0Ch ;Analog Column 1 Interrupt Vector
      // call void_handler
      reti

      org 10h ;Analog Column 2 Interrupt Vector
      // call void_handler
      reti

      org 14h ;Analog Column 3 Interrupt Vector
      // call void_handler
      reti

      org 18h ;VC3 Interrupt Vector
      // call void_handler
      reti

      org 1Ch ;GPIO Interrupt Vector
      ljmp _PSoC_GPIO_ISR
      reti

      org 20h ;PSoC Block DBB00 Interrupt Vector
      // call void_handler
      reti

      org 24h ;PSoC Block DBB01 Interrupt Vector
      // call void_handler
      reti

      org 28h ;PSoC Block DCB02 Interrupt Vector
      // call void_handler
      reti

      org 2Ch ;PSoC Block DCB03 Interrupt Vector
      // call void_handler
      reti

      org 30h ;PSoC Block DBB10 Interrupt Vector
      // call void_handler
      reti

      org 34h ;PSoC Block DBB11 Interrupt Vector
      // call void_handler
      reti

      org 38h ;PSoC Block DCB12 Interrupt Vector
      // call void_handler
      reti

      org 3Ch ;PSoC Block DCB13 Interrupt Vector
      // call void_handler
      reti

      org 40h ;PSoC Block DBB20 Interrupt Vector
      // call void_handler
      reti

      org 44h ;PSoC Block DBB21 Interrupt Vector
      // call void_handler
      reti

      org 48h ;PSoC Block DCB22 Interrupt Vector
      // call void_handler
      reti

      org 4Ch ;PSoC Block DCB23 Interrupt Vector
      // call void_handler
      reti

      org 50h ;PSoC Block DBB30 Interrupt Vector
      // call void_handler
      reti

      org 54h ;PSoC Block DBB31 Interrupt Vector
      // call void_handler
      reti

      org 58h ;PSoC Block DCB32 Interrupt Vector
      // call void_handler
      reti

      org 5Ch ;PSoC Block DCB33 Interrupt Vector
      // call void_handler
      reti

      org 60h ;PSoC I2C Interrupt Vector
      // call void_handler
      reti

      org 64h ;Sleep Timer Interrupt Vector
      ljmp _sleep_timer
      reti[/code:1]

      ở trong file trên, bạn khai báo sử dụng vecto ngắt cho GPIO và sleep timer
      Khi có ngắt, nó sẽ thực hiện chương trình phục vụ ngắt. Khai báo 2 ngắt này như sau

      [code:1]#pragma interrupt_handler sleep_isr; //không có dấu gạch chân ở đầu
      #pragma interrupt_handler PSoC_GPIO_ISR;

      void sleep_isr(void);
      void PSoC_GPIO_ISR(void);

      void main (void)
      {
      //do anything here
      M8C_EnableGInt; //enable global
      INT_MSK0 |=0x60; //enable GPIO and Sleep_Timer interrupt
      while(1) //loop
      {
      .
      .
      .
      }
      }

      //////////
      void sleep_isr(void)
      {
      //do anything here
      .
      .

      }
      /////////
      void PSoC_GPIO_ISR(void)
      {
      .//do anything here
      .
      .

      }[/code:1]


      chú ý từ bản 4.2 trở lên, các địa chỉ vector ngắt trong boot.asm phải có dấu gạch chân ở đầu như (_PSoC_GPIO_ISR). Ngoài cách này cũng có thể viết mã trực tiếp vào chương trình phục vụ ngắt nhưng cách này thường không hay áp dụng cho C Compiler vì nó phức tạp hơn

      I hope that help you
      Regards
      Work is glory

      Comment


      • #4
        Bác Winter làm ơn chỉ rõ hơn về cái GPIO Int được không, cái này sử dụng làm gì và như thế nào? Cách thiết lập? giả sử tôi muốn dùng 1 bộ đếm để đo độ rộng xung chỉ khi chân Enable là cao thì phải làm thế nào?
        Thanks.

        Comment


        • #5
          với PSoC, bạn có thể dùng ngắt với bất kì một chân nào (GPIO). Có 3 chế độ ngắt là Rising Edge, Change from last read, falling edge.
          3 cái này bạn đọc ở phần GPIO interrupt trong Technical Reference
          Còn dùng ngắt để làm gì ấy à, cài này là theo thiết kế của bạn, nó cúng giống như INT0 và INT1 của 51 vậy chỉ có điều nó có 3 chế độ ngắt và chân nào cũng có thể làm ngắt được, bạn dùng con có 3 cổng thì có thể có tới 24 ngắt GPIO tuy nhiên tất cả các ngắt GPIO chỉ có 1 vecto ngắt duy nhất do đó nếu dùng Multi GPIO Interrupt thì phải phát hiện xem ngắt xảy ra là do chân nào...
          Cách thiết lập: 2 cách

          - Thiết lập trên Device Editor, phần Interconnection View, ở cửa sổ cấu hình chân P0.0......
          Cửa sổ này gồm:
          Name Port Select Drive Interrupt

          Phần Interrupt để chọn chế độ ngắt

          Cách thứ 2 là tác động lên thanh ghi. Mỗi cổng đều có một số thanh ghi như thanh ghi dữ liệu, thanh ghi điều khiển chế đôm và thanh ghi điều khiển ngắt (cái này bạn tự xem nhé)

          Sau khi đã chọn chế độ ngắt, Generate Application thì trong file boot.asm bạn sẽ nhìn thấy như sau

          .
          .
          .
          [code:1] org 1Ch ;GPIO Interrupt Vector
          ljmp PSoC_GPIO_ISR
          reti [/code:1]

          đổi nó lại thành _PSoC_GPIO_ISR hay thành tên gì tùy ý

          đến phân viết mã

          [code:1]#pragma interupt_handler _PSoC_GPIO_ISR;

          void PSoC_GPIO_ISR(void);
          void main(void)
          {
          }

          ////
          void PSoC_GPIO_ISR(void)
          {

          }[/code:1]
          ///////////////////////////////////

          Còn về đo độ rộng xung bằng Enable. Lúc này bạn có thể dùng GPIO làm tín hiệu Enable và dùng ngắt của nó để làm thời điểm đọc bộ đếm. Tín hiệu điều khiển bạn đưa vào chân Enable của Counter và Counter được khởi động (Counter_Start())và chỉ khi tín hiệu Enable High/Low thì nó sẽ chạy/dừng Counter
          Work is glory

          Comment


          • #6
            Vậy tôi muốn đưa xung vào chân P1.0 chẳng hạn nhé, rồi đưa vào enable của bộ đếm, như vậy thì thiết lập cụ thể trong GPIO đối với chân P1.0 như thế nào.
            Giả sử tôi chọn Interrupt ở P1.0 và P1.1 là Rising Edge nhé, khi đó muốn viết hàm riêng cho từng ngắt thì phải làm sao? phải đọc xem chân nào là high ah?

            Comment


            • #7
              Cám ơn rất nhiều về sự chỉ giáo của WinterInjuly. Tôi đã làm thành công và hiểu hơn về ngắt của Psoc. Nếu bác ở HCM thì tôi sẽ mời bác một bữa bia không say không về.
              Tôi xin chia sẻ luôn với mọi người. Ví dụ của tôi làm như sau:
              Tôi sử dụng PWM_8 kết nối ra một cổng của Psoc. Tại cổng này có 1 led để hiển thị
              Sử dụng Counter_8 để thực hiện lệnh ngắt. Tôi thử bằng cách thay đổi độ rộng xung của con PWM_8 rồi nạp vào Psoc

              // C main line
              //----------------------------------------------------------------------------

              #include <m8c.h> // part specific constants and macros
              #include "PSoCAPI.h" // PSoC API definitions for all User Modules

              #pragma interrupt_handler Ngat;
              void Ngat(void);
              void Ngat()
              {

              PWM8_1_WritePulseWidth(100);
              }
              void main()
              {
              Counter8_2_Start();
              PWM8_1_Start();
              Counter8_2_EnableInt();
              M8C_EnableGInt;
              }

              Với mã lệnh trên thì đèn led sẽ rất sáng. Tôi thay đổi PWM8_1_WritePulseWidth(20);. Dịch và nạp lại vào PSoc thì Led mờ đi, có nghĩa là nó đã thực hiện ngắt của couter_8
              Ban đầu khi phát mã lệnh thì vecto ngắt trong boot.asm sẽ tự sinh ra 2 tên hàm mặc định _PWM_8_1_ISR và _Couter_8_2_ISR. Để đổi tên các hàm này thành một tên tuỳ ý thích của mình, các bạn phải vào Library source -> couter8_2int.asm/PW8_1int.asm tìm dòng
              export _Counter8_2_ISR/export _PWM8_1_ISR; _Counter8_2_ISR:/_PWM_8_1_ISR: và thay các hàm mặc định đó bằng tên mình tuỳ thích. Dịch và nạp thử là thành công.
              Một lần nữa xin cám ơn Winter, nếu bác ở HCM thì thông báo lại trong mục này nhé tôi sẽ mời bác đi uống bia.
              |

              Comment


              • #8
                Xôm tụ quá hé...

                Comment


                • #9
                  nếu bác ở HCM thì thông báo lại trong mục này nhé tôi sẽ mời bác đi uống bia.
                  Hình như bác này biết tui ở Hà Nội rùi nên mới nói thế
                  *******************************************
                  Ở PSoC chúng ta có thể dùng Timer/Counter/PWM để tạo xung đầu ra có duty cycle thay đổi được, không biết bác dùng cả PWM và Counter cùng một lúc để làm gì, bác có thể nói rõ được không?

                  Với PWM chẳng hạn, nó có 2 đầu ra là Count và TC (Terminal Count). TC chỉ là đầu ra phụ, nó sẽ được kich lên mức High khi thanh ghi đếm đếm đến 0 và kéo dài trong 1 chu kì clock. Để điều chế độ rộng xung chỉ cần đầu ra Count là đủ. Nạp vào thanh ghi compare giá trị PulseWidth, sau mỗi sườn lên của xung clock giá trị trong thanh ghi đếm sẽ bị giảm đi 1 và PWM sẽ tiến hành so sánh giá trị trong thanh ghi đếm với giá trị trong thanh ghi compare (theo luật less than hoặc less than or equal), khi nào điều kiện so sánh chưa xảy ra thì xung ỏ chân COUNT còn ở mức thấp, khi nào điều kiện so sánh xảy ra thì nó sẽ được đưa lên mức cao...thay đổi giá trị này ta được xung có độ rộng xung khác nhau (cùng chu kì)
                  Trong một chu kì có thể thay đổi thanh ghi compare (pulsewidth) bất kì lúc nào--> xung có hình dạng khác nhau...
                  Work is glory

                  Comment


                  • #10
                    Vậy tôi muốn đưa xung vào chân P1.0 chẳng hạn nhé, rồi đưa vào enable của bộ đếm, như vậy thì thiết lập cụ thể trong GPIO đối với chân P1.0 như thế nào.
                    Giả sử tôi chọn Interrupt ở P1.0 và P1.1 là Rising Edge nhé, khi đó muốn viết hàm riêng cho từng ngắt thì phải làm sao? phải đọc xem chân nào là high ah?
                    Để đưa chân P1.0 vào chân Enable của bộ đếm, bác đặt nó làm Global Input, nối qua các đường Global In, đi vào các bus Row và đi vào chân Enable.
                    Khi sử dụng nhiều GPIO interrupt, trong chương trình phục vụ ngắt phải xác định ngắt đến từ chân nào. Có thể dùng cách đọc cổng hoặc cách hay hơn là đưa các đầu vào này vào làm clock cho bộ đếm (counter, timer). Các bộ đếm có period=0, khi có xung clock nó sẽ gây ngắt cho bộ đếm vì thể viết chương trình phục vụ ngắt cho bộ đếm chính là viết chương trình phục vụ ngắt cho GPIO...
                    Không biết đã đủ trả lời cho bác chưa
                    Work is glory

                    Comment


                    • #11
                      Gửi bác Winter!!
                      Cách thứ 2 của bác: ví dụ 3 chân phím ấn, bác nối 3 chân này vào cùng 1 bus của clock bộ đếm, khi ấn phím thì tạo 1 xung clock cho bộ đếm, do chu kỳ = 0 nên nó tràn và phát ra ngắt ngay lập tức.
                      Cách thứ 2 của bác, em chưa phát hiện được cái hay bởi lẽ:
                      +Tốn thêm 1 bộ đếm.
                      +Vẫn phải đọc các chân để xác định chân ấn phím. Vẫn phải làm tất cả các thao tác như sự kiện ngắt theo sườn thôi.
                      -------------------

                      Comment


                      • #12
                        Thực ra tôi dùng cả PWM và Counter là để thử gọi ngắt của cả hai xem có OK không thôi ý mà. Chẳng có gì ghê gớm cả. Bác Winter à, nhất định sẽ có một lần tôi ra HN và chúng ta gặp nhau và khi đó chúng ta cùng phiêu bạt giang hồ để tìm kiếm bóng hồng trong mộng . Rất mong sự giúp đỡ của bác trong những lần kế tiếp
                        |

                        Comment


                        • #13
                          Gửi bác Winter!!
                          Cách thứ 2 của bác: ví dụ 3 chân phím ấn, bác nối 3 chân này vào cùng 1 bus của clock bộ đếm, khi ấn phím thì tạo 1 xung clock cho bộ đếm, do chu kỳ = 0 nên nó tràn và phát ra ngắt ngay lập tức.
                          Cách thứ 2 của bác, em chưa phát hiện được cái hay bởi lẽ:
                          +Tốn thêm 1 bộ đếm.
                          +Vẫn phải đọc các chân để xác định chân ấn phím. Vẫn phải làm tất cả các thao tác như sự kiện ngắt theo sườn thôi.
                          Tui đâu có nói là nối cả 3 chân này vào 1 đường clock của bộ đếm (CT< TM< PWM) đâu, mà phải mỗi đường vào một bộ đếm chứ. Nó tốn thêm tài nguyên nhưng lại dễ dàng khi viết chương trình . Cái gì cũng có giá của nó cả
                          Work is glory

                          Comment


                          • #14
                            Gửi bác Winter

                            Phải chăng nếu ngắt GPIO thì chúng đều nằm trong 1 vector ngắt, bởi vậy để phát hiện 10 phím ấn ở 10 chân thì trong trình phục vụ ngắt này, mình phải hỏi vong tới 10 lần, nên tốn thời gian VĐK.
                            Bởi vậy, trong những ứng dụng mà bộ đếm thừa thải, ta sử dụng giải pháp này để tiết kiệm thời gian hỏi vòng, mỗi 1 bộ đếm ứng với 1 chân, Khi bộ đếm tràn thì ứng với chân đó bị ấn?
                            Phải chăng ý tưởng bác Wt là vậy ko nhỉ?
                            -------------------

                            Comment


                            • #15
                              Đúng rùi đấy, có thể có nhiều ngắt GPIO nhưng chúng chỉ có chung 1 vector ngắt do đó trong chương trình phục vụ ngắt phải xác định ngắt là do chân nào gây ra. Còn ý tưởng thì không phải của tôi, mà là của các cao thủ khác...
                              Work is glory

                              Comment

                              Về tác giả

                              Collapse

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

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

                              Collapse

                              Đang tải...
                              X