Thursday, April 3, 2014

Bài 4.(MSP430_Basic) Ngắt

Trước hết trước khi bắt đầu các bạn nếu chưa có datasheet của dùng MSP430 thì có thể download tại đây : http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=slaa559&fileType=pdf.
Lưu ý Datasheet vẫn luôn là tài liệu quan trọng nhất khi bạn tiếp cận bất cứ dòng vi điều khiển nào , nên việc thành thạo tiếng Anh và khả năng đọc Datasheet vẫn là quan trọng nhất.

Tài liệu được viết cho MSP430G2553,các chip khác có module khác mã sẽ không sử dụng được thư viện đi kèm.

Bài trước chúng ta đã được làm quen với UART và GPIO , như vậy từ bài này các bạn có thể tận dụng gần  hết tất cả các chức năng mà kit Launchpad có thể làm dc . Chỉ còn phần cuối cùng liên quan đến thạch anh 32Khz nối ngoài sẽ được mình đề cập đến trong bài Clock , sẽ viết sau này . Các bạn chú ý nên giữ lại thạch anh này vì MSP430G2553 chỉ hỗ trợ thạch anh ngoài 32Khz là cao nhất , nó rất hữu ích khi các bạn cần căn chỉnh chính xác xung nội .
Tiếp tục với bài tập hôm nay liên quan đến ngắt ngoài . Hai kỹ thuật quan trọng nhất trong lập trình nhúng là ngắt và hỏi vòng , vì vậy các bạn cần nắm vững bài tập này . Kỹ thuật hỏi vòng chính là kiểu lập trình while(…) {   if ….   } mà chúng ta đã làm trong bài GPIO .


1.Lý thuyết

Ngắt (interrupt) là quá trình dừng chương trình chính đang chạy để ưu tiên thực hiện
một chương trình khác , chương trình này được gọi là chương trình phục vụ ngắt (ISR –
Interrupt Service Routine) .
MSP430 có 2 loại ngắt là ngắt khả ngụy và ngắt không khả ngụy .
-          Ngắt không khả ngụy liên quan đến các hoạt động Reset,phát hiện lỗi xong clock , sự cố về bộ nhớ Flash.Nói chung ngắt này có mức độ ưu tiên cao nhất , ở chế độ bình thường không ảnh hưởng đến hoạt động của chương trình . Một số chế độ đặc biệt mình sẽ hướng dẫn trong loạt bài MSP430_Advance , sẽ viết sau,trình bày cách điều khiển hoạt động của các ngắt không khả ngụy này như tắt chức năng reset ở chân Reset,khởi động lại bằng phần mềm.Ngắt không khả ngụy không điều khiển bằng bit GIE trong thanh ghi điều khiển .
-          Ngắt khả ngụy là loạt ngắt liên quan trực tiếp đến hoạt động của hầu hết các chương trình cho phép thực hiện các chương trình gọi từ ngắt của các cổng Inout,ngắt từ Timer , ADC , Các giao thức truyền thông . Có hai loại ngắt khả ngụy là ngắt trong và ngắt ngoài . Ngắt khả ngụy điều khiển bằng bit GIE trong thanh ghi điều khiển.Tức là muốn hoạt động thì BIT GIE phải được set=1 . (đây là một bit trong thanh ghi trạng thái SR(đọc thêm trong sách Cơ sở lý thuyết MSP430))
o   Ngắt ngoài là các ngắt do tác động của bên ngoài lên chip VD như ngắt GPIO,ADC,Các giao thực truyền thông
o   Ngắt trong là các loại ngắt sinh ra từ bên trong chip như ngắt Timer/Counter,Watchdog.
-          Lấy ví dụ thế này,chương trình chính của bạn thực hiện nháy led P1.0
§  VD : while (1){ P1OUT^=BIT0; _delay_cycles(1000000);}
o   Bạn muốn nhấn nút P1.3 thì đèn P1.6 sáng.Bạn có thế thực hiện bằng cách hỏi vòng,
§  while (1){
                                        P1OUT^=BIT0;
_delay_cycles(1000000);
If((P1IN&BIT3)==0)P1OUT|=BIT6;//Hỏi vòng
}
o   Hoặc có thể dùng ngắt,tức là khi nhấn nút thì Module GPIO xác nhận có sự thay đổi điện áp và tự động chạy chương trình ngắt GPIO,bật led và quay lại chương trình chính.
Như vậy có thế thấy nếu hỏi vòng thì thao tác bật đèn P1.6 bị trễ một khoảng thời gian ở _delay_cycles(),còn khi dùng ngắt thì P1.6 sáng tức thì.Đây là một trong những điểm khác biệt giữa kỹ thuật hỏi vòng và ngắt,cũng gần giống việc VĐK của bạn chạy 2 chương trình cùng 1 lúc vậy(Về bản chất thì không phải)

Sau khi đã hiểu bản chất của ngắt và ứng dụng của nó,chúng ta sẽ tìm hiểu cách hoạt động trên MSP430.Bài này mình chỉ minh họa ngắt ngoài ,các loại ngắt khác sẽ được đề cập đến trong các bài về từng Module riêng .

2.Ngắt ngoài

MSP430 được thiết kế có rất nhiều ngắt ngoài(đây là 1 trong những điểm vượt trội so với các dòng cũ như AVR,PIC..).Các cổng P1 P2 của hầu hết MSP430 đều có ngắt.Việc điều khiển ngắt đươc thông qua các thanh ghi PxIE , PxIES , PxIFG .

Mỗi chân của P1 và P2 có thể làm một ngắt yêu cầu . Các chân này được thiết lập với các
thanh ghi phụ như:
-          Cho phép ngắt ( PxIE) :
Thanh ghi này cho phép ngắt trên những chân riêng rẽ.
o   Bit = 0: không cho phép ngắt.
o   Bit = 1: Cho phép ngắt.
Mỗi Bit cho phép ngắt PxIE này được liên kết với cờ ngắt PxIFG tương ứng.
Việc ghi vào thanh ghi PxOUT và PxDIR có thể ảnh hưởng đến việc điều chỉnh PxIE.

-          Thanh ghi lựa chọn ngắt cạnh ( PxIES) :
Lựa chọn loại ngắt khi xuất hiện sự biến đổi tín hiệu ( Nếu PxIE và GIE được Set)
o   Bit = 0: Ngắt cạnh lên
o   Bit = 1: Ngắt cạnh xuống
o    
-          Thanh ghi cờ ngắt ( PxIFG)
Cờ ngắt này được Set tự động theo chương trình đã được lập trình trước khi xuất hiện
một sự chuyển đổi tín hiệu. Cờ PxIFG phải sử dụng chương trình để Reset.
o   Bit = 0: Không có ngắt. 
o   Bit = 1: Có ngắt.

Để thực hiện ngắt cần 2 bước:
o   Thiết lập cấu hình Module để cho phép ngắt xảy ra và điều kiện xảy ra ngắt
o   Gọi hàm thực hiện ngắt tương ứng

Lấy ví dụ : Đèn P1.0 nháy chu kỳ 0.5Hz,nếu nhấn nút P1.3 thì đèn P1.6 đổi giá trị ngay lập tức( sáng <-> tối)
o   Thiết lập cổng vào ra,phải cài đặt P1.3 là cổng Input,có điện trở nội kéo lên để chống nhiễu,cài đặt cho phép ngắt cạnh xuống.Cài đặt cổng Output cho các đèn P1.0 và P1.6.Cuối cùng là set BIT GIE=1 bằng hàm  __bis_SR_register(GIE);(đây là một trong số các hàm set thanh ghi trạng thái SR(đọc thêm trong sách Cơ sở lý thuyết MSP430))
o   Gọi hàm thực hiện ngắt,có bố cục giống nhau giữa các hàm ngắt khác nhau
#pragma vector = (Tên hàm ngắt mặc định) //xem cuối bài
__interrupt void (Tên hàm ngắt do người dùng đặt)(void)
{
                //Thực hiện chương trình ngắt
                //Hàm xóa cờ ngắt
}

Chương trình tham khảo:



#include "msp430g2553.h"
/*         Khai báo loại chip đang dùng
 *         Thư viện này chứa các khai báo tên #define cho địa
 *         chỉ các thanh ghi
 */
void main(void)
{
            WDTCTL = WDTPW | WDTHOLD;           //Stop Watchdog
            BCSCTL1 = CALBC1_1MHZ;                    //2 thanh ghi cài đặt tần số hoạt động
            DCOCTL = CALDCO_1MHZ;                    //Ở đây là 1 Mhz
            //Cài đặt cấu hình ngắt ngoài cho P1.3
            //Như trong bài GPIO,chúng ta phải cài đặt chống nhiễu cho nút bấm P1.3
            //Vì sự thay đổi của điện áp P1.3 có thể vô tình tạo ra ngắt
            P1DIR&=~(BIT3);          //Chọn nhập
            P1REN|=BIT3;   //Cho phép trở treo
            P1OUT|=BIT3;  //Trở treo lên nguồn
            //Cài đặt ngắt
            P1IE |=BIT3;     //Cho phép ngắt ở P1.3
            P1IES |=BIT3;   //Ngắt cạnh xuống,
            //tức là khi điện áp P1.3 từ 1 ->0 thì xảy ra ngắt
            P1IFG &=~BIT3;           //Xóa cờ ngắt
            __bis_SR_register(GIE);

            //Cài đặt đèn
            P1DIR|=BIT0+BIT6;
            P1OUT&=~(BIT0+BIT6);
            while(1)
            {
                        P1OUT^=BIT0;
                        _delay_cycles(1000000);
            }
}

#pragma vector = PORT1_VECTOR
__interrupt void test(void)
{
            //Kiểm tra ngắt có phải là ở P1.3 không
            if(P1IFG&BIT3)
            {
                        //Đảo dấu đèn P1.6
                        P1OUT^=BIT6;
                        //xoa co ngat tai chan P1.1
                        P1IFG &=~BIT3;
            }
}



Bảng vector ngắt,các bạn có thể xem trong file “msp430g2553.h”


/************************************************************
* Interrupt Vectors (offset from 0xFFE0)
************************************************************/

#define VECTOR_NAME(name)       name##_ptr
#define EMIT_PRAGMA(x)          _Pragma(#x)
#define CREATE_VECTOR(name)     void (* const VECTOR_NAME(name))(void) = &name
#define PLACE_VECTOR(vector,section) EMIT_PRAGMA(DATA_SECTION(vector,section))
#define ISR_VECTOR(func,offset) CREATE_VECTOR(func); \
                                PLACE_VECTOR(VECTOR_NAME(func), offset)

#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define PORT1_VECTOR            ".int02"                    /* 0xFFE4 Port 1 */
#else
#define PORT1_VECTOR            (2 * 1u)                     /* 0xFFE4 Port 1 */
/*#define PORT1_ISR(func)         ISR_VECTOR(func, ".int02")  */ /* 0xFFE4 Port 1 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define PORT2_VECTOR            ".int03"                    /* 0xFFE6 Port 2 */
#else
#define PORT2_VECTOR            (3 * 1u)                     /* 0xFFE6 Port 2 */
/*#define PORT2_ISR(func)         ISR_VECTOR(func, ".int03")  */ /* 0xFFE6 Port 2 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define ADC10_VECTOR            ".int05"                    /* 0xFFEA ADC10 */
#else
#define ADC10_VECTOR            (5 * 1u)                     /* 0xFFEA ADC10 */
/*#define ADC10_ISR(func)         ISR_VECTOR(func, ".int05")  */ /* 0xFFEA ADC10 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define USCIAB0TX_VECTOR        ".int06"                    /* 0xFFEC USCI A0/B0 Transmit */
#else
#define USCIAB0TX_VECTOR        (6 * 1u)                     /* 0xFFEC USCI A0/B0 Transmit */
/*#define USCIAB0TX_ISR(func)     ISR_VECTOR(func, ".int06")  */ /* 0xFFEC USCI A0/B0 Transmit */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define USCIAB0RX_VECTOR        ".int07"                    /* 0xFFEE USCI A0/B0 Receive */
#else
#define USCIAB0RX_VECTOR        (7 * 1u)                     /* 0xFFEE USCI A0/B0 Receive */
/*#define USCIAB0RX_ISR(func)     ISR_VECTOR(func, ".int07")  */ /* 0xFFEE USCI A0/B0 Receive */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER0_A1_VECTOR        ".int08"                    /* 0xFFF0 Timer0)A CC1, TA0 */
#else
#define TIMER0_A1_VECTOR        (8 * 1u)                     /* 0xFFF0 Timer0)A CC1, TA0 */
/*#define TIMER0_A1_ISR(func)     ISR_VECTOR(func, ".int08")  */ /* 0xFFF0 Timer0)A CC1, TA0 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER0_A0_VECTOR        ".int09"                    /* 0xFFF2 Timer0_A CC0 */
#else
#define TIMER0_A0_VECTOR        (9 * 1u)                     /* 0xFFF2 Timer0_A CC0 */
/*#define TIMER0_A0_ISR(func)     ISR_VECTOR(func, ".int09")  */ /* 0xFFF2 Timer0_A CC0 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define WDT_VECTOR              ".int10"                    /* 0xFFF4 Watchdog Timer */
#else
#define WDT_VECTOR              (10 * 1u)                    /* 0xFFF4 Watchdog Timer */
/*#define WDT_ISR(func)           ISR_VECTOR(func, ".int10")  */ /* 0xFFF4 Watchdog Timer */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define COMPARATORA_VECTOR      ".int11"                    /* 0xFFF6 Comparator A */
#else
#define COMPARATORA_VECTOR      (11 * 1u)                    /* 0xFFF6 Comparator A */
/*#define COMPARATORA_ISR(func)   ISR_VECTOR(func, ".int11")  */ /* 0xFFF6 Comparator A */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER1_A1_VECTOR        ".int12"                    /* 0xFFF8 Timer1_A CC1-4, TA1 */
#else
#define TIMER1_A1_VECTOR        (12 * 1u)                    /* 0xFFF8 Timer1_A CC1-4, TA1 */
/*#define TIMER1_A1_ISR(func)     ISR_VECTOR(func, ".int12")  */ /* 0xFFF8 Timer1_A CC1-4, TA1 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER1_A0_VECTOR        ".int13"                    /* 0xFFFA Timer1_A CC0 */
#else
#define TIMER1_A0_VECTOR        (13 * 1u)                    /* 0xFFFA Timer1_A CC0 */
/*#define TIMER1_A0_ISR(func)     ISR_VECTOR(func, ".int13")  */ /* 0xFFFA Timer1_A CC0 */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define NMI_VECTOR              ".int14"                    /* 0xFFFC Non-maskable */
#else
#define NMI_VECTOR              (14 * 1u)                    /* 0xFFFC Non-maskable */
/*#define NMI_ISR(func)           ISR_VECTOR(func, ".int14")  */ /* 0xFFFC Non-maskable */ /* CCE V2 Style */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define RESET_VECTOR            ".reset"                    /* 0xFFFE Reset [Highest Priority] */
#else
#define RESET_VECTOR            (15 * 1u)                    /* 0xFFFE Reset [Highest Priority] */
/*#define RESET_ISR(func)         ISR_VECTOR(func, ".int15")  */ /* 0xFFFE Reset [Highest Priority] */ /* CCE V2 Style */
#endif


Download code mẫu tại  đây

Bài tiếp theo : Bài 5.(MSP430_Basic) Clock



 

1 comment:

  1. cho em hỏi, mình sử dụng ngắt đầu vào nút bắm ở 2 port khác nhau trong 1 chương trình được hong ạ?
    (em thử làm nhưng không được)

    ReplyDelete

END COMMENT FACEBOOK-->