RP Store Tìm linh kiện theo mã, gửi BOM nhận báo giá Gửi BOM

Nhờ các bác giải quyết một vấn đề về ngắt

Collapse
X
 
  • Giờ
  • Show
Clear All
new posts
  • hanhthien184
    Nhập môn đệ tử
    • Oct 2007
    • 4

    #1

    Nhờ các bác giải quyết một vấn đề về ngắt

    Em sử dụng dsPIC33FJ256GP710 cấu hình hoạt động ở 40MIPS.
    Hàm phục vụ ngắt (ngắt ngoài INT4) của em như sau:
    Code:
        void interrupt_int4() org 0x80 {        //When ADS is asserted
                addr_select = PORTA;
                addr_select &= 0x3F;
                if (addr_select == 0)
                {
                LATD = ADC_1;                   //ADC_1
                LATFbits.LATF0 = 0;             //LRDYi active
                LATFbits.LATF0 = 1;             //LRDYi inative
                }
                else if (addr_select == 2)
                {
                LATD = ADC_2;                   //ADC_2
                LATFbits.LATF0 = 0;             //LRDYi active
                LATFbits.LATF0 = 1;             //LRDYi inative
               }
               else
                {
               LATD = addr_select;
               LATFbits.LATF0 = 0;             //LRDYi active
               LATFbits.LATF0 = 1;             //LRDYi inative
               }
              IFS3bits.INT4IF = 0;              //ensure interrupt not pending
              }
    Yêu cầu của trình phục vụ ngắt này phải thực hiện trong thời gian rất ngắn (khoảng 0.5us).
    Tuy nhiên khi viết chương trình với C (MikroC) thì nó tự động push tất cả các thanh ghi làm việc nên mất khá nhiều chu kỳ lệnh:
    View assembly của chương trình trên ta thấy:
    Code:
    $0200	$	_interrupt_int4:
    $0200	$F80036			PUSH	RCOUNT
    $0202	$781F80			PUSH	W0
    $0204	$200020			MOV	#2, W0
    $0206	$09000C			REPEAT	#12
    $0208	$781FB0			PUSH	[W0++]
    ;INT_TEST.c,15 :: 		void interrupt_int4() org 0x80 {        //When ADS is asserted
    ;INT_TEST.c,16 :: 		addr_select = PORTA;
    $020A	$801610			MOV	PORTA, W0
    $020C	$8A2000			MOV	W0, _addr_select
    ;INT_TEST.c,17 :: 		addr_select &= 0x3F;
    $020E	$2003F1			MOV	#63, W1
    $0210	$244000			MOV	#@_addr_select, W0
    $0212	$608090			AND	W1, [W0], W1
    $0214	$8A2001			MOV	W1, _addr_select
    ;INT_TEST.c,18 :: 		if (addr_select == 0)
    $0216	$508060			SUB	W1, #0, W0
    $0218	$3A000A			BRA NZ	L_interrupt_int4_0, L_interrupt_int4_0
    ;INT_TEST.c,20 :: 		LATD = ADC_1;                   //ADC_1
    $021A	$822010			MOV	_ADC_1, W0
    $021C	$8816B0			MOV	W0, LATD
    ;INT_TEST.c,21 :: 		LATFbits.LATF0 = 0;             //LRDYi active
    $021E	$2FFFE1			MOV	#65534, W1
    $0220	$202E20			MOV	#@LATFbits+0, W0
    $0222	$608810			AND	W1, [W0], [W0]
    ;INT_TEST.c,22 :: 		LATFbits.LATF0 = 1;             //LRDYi inative
    $0224	$200011			MOV	#1, W1
    $0226	$202E20			MOV	#@LATFbits+0, W0
    $0228	$708810			IOR	W1, [W0], [W0]
    ;INT_TEST.c,23 :: 		}
    $022A	$040258			GOTO	L_interrupt_int4_1
    $022E	$	L_interrupt_int4_0:
    ;INT_TEST.c,24 :: 		else if (addr_select == 2)
    $022E	$822001			MOV	_addr_select, W1
    $0230	$508062			SUB	W1, #2, W0
    $0232	$3A000A			BRA NZ	L_interrupt_int4_2, L_interrupt_int4_2
    ;INT_TEST.c,26 :: 		LATD = ADC_2;                   //ADC_2
    $0234	$822020			MOV	_ADC_2, W0
    $0236	$8816B0			MOV	W0, LATD
    ;INT_TEST.c,27 :: 		LATFbits.LATF0 = 0;             //LRDYi active
    $0238	$2FFFE1			MOV	#65534, W1
    $023A	$202E20			MOV	#@LATFbits+0, W0
    $023C	$608810			AND	W1, [W0], [W0]
    ;INT_TEST.c,28 :: 		LATFbits.LATF0 = 1;             //LRDYi inative
    $023E	$200011			MOV	#1, W1
    $0240	$202E20			MOV	#@LATFbits+0, W0
    $0242	$708810			IOR	W1, [W0], [W0]
    ;INT_TEST.c,29 :: 		}
    $0244	$040258			GOTO	L_interrupt_int4_3
    $0248	$	L_interrupt_int4_2:
    ;INT_TEST.c,32 :: 		LATD = addr_select;
    $0248	$822000			MOV	_addr_select, W0
    $024A	$8816B0			MOV	W0, LATD
    ;INT_TEST.c,33 :: 		LATFbits.LATF0 = 0;             //LRDYi active
    $024C	$2FFFE1			MOV	#65534, W1
    $024E	$202E20			MOV	#@LATFbits+0, W0
    $0250	$608810			AND	W1, [W0], [W0]
    ;INT_TEST.c,34 :: 		LATFbits.LATF0 = 1;             //LRDYi inative
    $0252	$200011			MOV	#1, W1
    $0254	$202E20			MOV	#@LATFbits+0, W0
    $0256	$708810			IOR	W1, [W0], [W0]
    ;INT_TEST.c,35 :: 		}
    $0258	$	L_interrupt_int4_3:
    $0258	$	L_interrupt_int4_1:
    ;INT_TEST.c,36 :: 		IFS3bits.INT4IF = 0;              //ensure interrupt not pending
    $0258	$2FFBF1			MOV	#65471, W1
    $025A	$2008A0			MOV	#@IFS3bits+0, W0
    $025C	$608810			AND	W1, [W0], [W0]
    ;INT_TEST.c,37 :: 		}
    $025E	$	L_end__interrupt_int4:
    $025E	$2001A0			MOV	#26, W0
    $0260	$09000C			REPEAT	#12
    $0262	$78104F			POP	[W0--]
    $0264	$78004F			POP	W0
    $0266	$F90036			POP	RCOUNT
    $0268	$064000			RETFIE
    ?Có cách nào cải thiện được tốc độ của ngắt (có thể không push các thanh ghi không cần thiết trong trình phục vụ ngắt)bằng MikroC là tốt nhất (hoặc chuyển sang C30 cũng được)
    vì chương trình của em rất lớn nên nếu chuyển tất cả sang ASM thì không đủ thời gian thực hiện.
    =>Các bác nào có hướng giải quyết nào hay giúp em với.
  • hanhthien184
    Nhập môn đệ tử
    • Oct 2007
    • 4

    #2
    Vấn đề ngắt tiếp theo ...

    Cũng với chương trình ngắt phía trên:
    +Khai báo biến toàn cục:
    Code:
     unsigned int ADC_1;
     unsigned int ADC_2;
    +Trình phục vụ ngắt:
    Code:
    void interrupt_int4() org 0x80 {                //When ADS is asserted
               addr_select = PORTA;
               addr_select &= 0x3F;
               if (addr_select == 0)
                {
                 LATD = ADC_1;                   //ADC_1
                 }
                 else if (addr_select == 2)
                   {
                    LATD = ADC_2;                   //ADC_2
                    }
                    else
                       {
                        LATD = addr_select;
                       }
               IFS3bits.INT4IF = 0;           //ensure interrupt not pending
           }
    Nhưng khi thay đổi giá trị của ADC_1 và ADC_2 trong hàm main()
    ví dụ:
    Code:
     ADC_1 = 0xAA;
     ADC_2 = 0xBB;
    thì LATD không đưa ra giá trị đúng khi có ngắt ngoài INT4.
    Vấn đề ở đây là gì ??? Các bác giúp em với

    Comment

    • namqn
      Trưởng lão PIC bang
      • Feb 2006
      • 3020

      #3
      Nguyên văn bởi hanhthien184 View Post
      Em sử dụng dsPIC33FJ256GP710 cấu hình hoạt động ở 40MIPS.
      Hàm phục vụ ngắt (ngắt ngoài INT4) của em như sau:
      ...
      ?Có cách nào cải thiện được tốc độ của ngắt (có thể không push các thanh ghi không cần thiết trong trình phục vụ ngắt)bằng MikroC là tốt nhất (hoặc chuyển sang C30 cũng được)
      vì chương trình của em rất lớn nên nếu chuyển tất cả sang ASM thì không đủ thời gian thực hiện.
      =>Các bác nào có hướng giải quyết nào hay giúp em với.
      MPLAB C Compiler for PIC24 MCUs and dsPIC DSCs (MPLAB C30 cũ) dịch các trình phục vụ ngắt thông minh hơn, chỉ push/pop những thanh ghi nào được sử dụng trong trình phục vụ ngắt. Nó cũng dịch những lệnh bật/tắt bit tốt hơn, chỉ dùng những lệnh bật/tắt bit đã có trong tập lệnh của PIC24/dsPIC.

      Bạn cũng có thể viết các đoạn code/chương trình con bằng hợp ngữ và truy xuất chúng từ C.

      Theo tôi, mikroC for dsPIC chỉ dùng để làm quen với PIC24/dsPIC thôi, còn viết code cho các project nghiêm túc thì không nên dùng.

      Thân,
      Biển học mênh mông, sức người có hạn.

      Đang gặp vấn đề cần được giúp đỡ? Hãy dành ra vài phút đọc luồng sau:
      http://www.picvietnam.com/forum/showthread.php?t=1263

      Comment

      • namqn
        Trưởng lão PIC bang
        • Feb 2006
        • 3020

        #4
        Nguyên văn bởi hanhthien184 View Post
        Cũng với chương trình ngắt phía trên:
        +Khai báo biến toàn cục:
        Code:
         unsigned int ADC_1;
         unsigned int ADC_2;
        +Trình phục vụ ngắt:
        Code:
        void interrupt_int4() org 0x80 {                //When ADS is asserted
                   addr_select = PORTA;
                   addr_select &= 0x3F;
                   if (addr_select == 0)
                    {
                     LATD = ADC_1;                   //ADC_1
                     }
                     else if (addr_select == 2)
                       {
                        LATD = ADC_2;                   //ADC_2
                        }
                        else
                           {
                            LATD = addr_select;
                           }
                   IFS3bits.INT4IF = 0;           //ensure interrupt not pending
               }
        Nhưng khi thay đổi giá trị của ADC_1 và ADC_2 trong hàm main()
        ví dụ:
        Code:
         ADC_1 = 0xAA;
         ADC_2 = 0xBB;
        thì LATD không đưa ra giá trị đúng khi có ngắt ngoài INT4.
        Vấn đề ở đây là gì ??? Các bác giúp em với
        Nếu LATD không hề mang giá trị hợp lý nào trong số ADC_1, ADC_2, và addr_select, thì có nghĩa là trình phục vụ ngắt không được chạy.

        Theo tôi thì nên dùng switch case thay cho các if lồng nhau.

        Thân,
        Biển học mênh mông, sức người có hạn.

        Đang gặp vấn đề cần được giúp đỡ? Hãy dành ra vài phút đọc luồng sau:
        http://www.picvietnam.com/forum/showthread.php?t=1263

        Comment

        • hanhthien184
          Nhập môn đệ tử
          • Oct 2007
          • 4

          #5
          Cám ơn anh Nam đã giúp đỡ !!! .Em sẽ nghiên cứu để chuyển sang C30.
          Về vấn đề hàm ngắt INT4:
          -Ban đầu khi em chưa sử dụng biến ADC_1 và ADC_2 mà đưa luôn giá trị ra PORTD:
          Code:
          void interrupt_int4() org 0x80 {                //When ADS is asserted
                     addr_select = PORTA;
                     addr_select &= 0x3F;
                     if (addr_select == 0)
                      {
                       LATD = 0xAA;               
                       }
                       else if (addr_select == 2)
                         {
                          LATD = 0xBB;                  
                          }
                          else
                             {
                              LATD = addr_select;
                             }
                     IFS3bits.INT4IF = 0;           //ensure interrupt not pending
                 }
          thì giá trị đưa ra ở trên PORTD là hợp lý.Nghĩa là ngắt có xảy ra và addr_select là chính xác.
          Vấn đề ở đây có lẽ là do cách mình khai báo biến:
          Code:
           unsigned int ADC_1;
           unsigned int ADC_2;
          Các giá trị ADC_1 và ADC_2 được lấy từ chuyển đổi ADC trên hai kênh(trong hàm main).
          1>Liệu có sự thay đổi nào của ADC_1 và ADC_2 khi nhảy vào trong hàm ngắt
          2>cách gán giá trị trong hàm ngắt như sau có vấn đề:
          Code:
          LATD = ADC_1;      
          LATD = ADC_2;
          Nhờ bác cho ý kiến giúp em...

          Comment

          • namqn
            Trưởng lão PIC bang
            • Feb 2006
            • 3020

            #6
            Ở post #2 bạn đặt các giá trị hằng số vào ADC_1 và ADC_2 và cho biết kết quả không đúng khi có ngắt ngoài, nhưng ở post #4 bạn lại cho biết giá trị của ADC_1 và ADC_2 có được từ việc chuyển đổi A/D. Liệu có khả năng khi bạn thử đặt các giá trị 0xAA và 0xBB vào ADC_1 và ADC_2 thì thao tác chuyển đổi A/D lại ghi các giá trị khác vào ADC_1 và ADC_2 hay không?

            Bạn tham khảo ví dụ 5.1 trong tutorial 5 cho dsPIC của tôi. Tôi đã dùng đúng cách mà bạn đang dùng để đọc ngõ vào analog và cập nhật các thanh ghi PDC bằng kết quả chuyển đổi A/D. Tôi cũng dùng biến unsigned int, và không hề có điều gì bất thường xảy ra.

            Thân,
            Biển học mênh mông, sức người có hạn.

            Đang gặp vấn đề cần được giúp đỡ? Hãy dành ra vài phút đọc luồng sau:
            http://www.picvietnam.com/forum/showthread.php?t=1263

            Comment

            • hanhthien184
              Nhập môn đệ tử
              • Oct 2007
              • 4

              #7
              Cảm ơn anh Nam đã giúp đỡ.
              Em đã giải quyết được vấn đề ngắt này,và chỉnh lại code cho hợp lý:
              Code:
              //--- External Interrupt routine (INT4 - ADS)---
                void interrupt_int4() org 0x80 {                //When ADS is asserted
                   addr_select = PORTA;
                   addr_select &= 0x3F;
                   switch (addr_select) {
                     case 0:  LATD = ADC_1; break;
                     case 2:  LATD = ADC_2; break;
                     default: LATD = 0xDD;
                     }
                   IFS3bits.INT4IF = 0;           //ensure interrupt not pending 
                }
              Trong đó ADC_1 và ADC_2 được lấy từ chuyển đổi hai kênh ADC.
              (Ở phía trên em cho ADC_1 = 0xAA và ADC_2 = 0xBB chỉ là để test )
              Vấn đề của em là do tín hiệu ngắt ngoài được lấy từ PC,dữ liệu cũng được truyền về PC (và còn một số vấn đề khác của phần cứng)nên ban đầu ko rõ nguyên nhân.Vì tín hiệu ngắt ngoài ko ổn định nên giá trị nhận được ko chinh xác.Còn lại hàm ngắt và chuyển đổi ADC ko có vấn đề gì.
              Last edited by hanhthien184; 13-05-2008, 11:20 PM.

              Comment

              Working...