PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   Cơ bản về vi điều khiển và PIC (http://www.picvietnam.com/forum/forumdisplay.php?f=8)
-   -   CCS-Chuyển giá trị từ chương trình chính sang chuơng trình ngắt (http://www.picvietnam.com/forum/showthread.php?t=3879)

thaithien 08-04-2009 11:49 PM

CCS-Chuyển giá trị từ chương trình chính sang chuơng trình ngắt
 
Mình viết đoạn code như sau để thực hiện ngắt trên port D:
Code:

// INTEXT.C  MPB  10-4-07
// Demo external interrupt
// RB0 low interrupts
// foregroundoutput count

#include "16F887.h"
#use delay(clock=2000000)

#int_ext
    void isrext()
    {  output_D(255);
        delay_ms(1000);
    }



void main()
{
    int x=10;

    enable_interrupts(int_ext);
    enable_interrupts(global);
    ext_int_edge(H_TO_L);

    while(1)
    { 
        output_D(x);
        x++;
        delay_ms(100);
    }
}


Bây giờ mình muốn chương trình ngắt thực hiện công việc là khi bắt đầu ngắt thì sẽ lấy giá trị hiện thời của x trong chương trình chính và đưa vào chương trình ngắt,mình sửa code lại như sau nhưng chưa chạy được:
Code:

// INTEXT.C  MPB  10-4-07
// Demo external interrupt
// RB0 low interrupts
// foregroundoutput count

#include "16F887.h"
#use delay(clock=2000000)

#int_ext
    void isrext()
    {  output_C(x);      //muc dich là xuat ra portC giá trị của x hiện thời trong ct chính
        delay_ms(1000);
    }



void main()
{
    int x=10;

    enable_interrupts(int_ext);
    enable_interrupts(global);
    ext_int_edge(H_TO_L);

    while(1)
    { 
        output_D(x);
        x++;
        delay_ms(100);
    }
}


namqn 09-04-2009 12:22 AM

Bạn không nên dùng delay_ms(1000) trong chương trình xử lý ngắt, vì các hoạt động khác trong vòng lặp chính sẽ bị dừng lại cho đến khi trở về từ ngắt, mà trong ngắt bạn lại dừng lại 1000 ms chẳng làm gì cả.

Thân,

thaithien 09-04-2009 01:24 AM

Vậy còn vấn đề biến x thì sao hả anh ?Em nghĩ là giá trị x trong chương trình chính đang chạy sẽ lưu vào một địa chỉ nhớ nào đó.làm sao mình đọc nó ra và gán vào cho biết nằm trong chương trình ngắt ?

namqn 09-04-2009 03:33 AM

Trích:

Nguyên văn bởi thaithien (Post 24563)
Vậy còn vấn đề biến x thì sao hả anh ?Em nghĩ là giá trị x trong chương trình chính đang chạy sẽ lưu vào một địa chỉ nhớ nào đó.làm sao mình đọc nó ra và gán vào cho biết nằm trong chương trình ngắt ?

Tôi không dùng CCS C nên không rõ biến x trong main sẽ được trình biên dịch xử lý ra sao khi được truy xuất trong chương trình xử lý ngắt, nhưng tôi cho rằng bạn có thể dùng biến toàn cục (nghĩa là đặt biến x ra ngoài main() và isrext() của bạn).

Thân,

cskiller 09-04-2009 11:12 AM

Code:

// INTEXT.C  MPB  10-4-07
// Demo external interrupt
// RB0 low interrupts
// foregroundoutput count

#include "16F877a.h"
#fuses HS,NOWDT       
#use delay(clock=12000000)

int x=10;     
     
#int_ext
void isrext()                         

  output_c(x);      //muc dich là xuat ra portC giá tri. cu?a x hie^.n tho+`i trong ct chính
  delay_ms(1000);
}

             
void main()

                                 
    enable_interrupts(global);
   
    set_tris_b(get_tris_b()|0x01);
    enable_interrupts(int_ext);
    ext_int_edge(H_TO_L);

    while(1)
    { 
        output_d(x);
        x++;
        delay_ms(100);
    }
}

Không có 16F887 nhưng chương trình test với 16F877A thấy OK mà.
Chú ý: Tầm cực biến x để isrext() có thể truy cập. Giá trị trên Port D sẽ thường nhỏ hơn 1 so với Port C vì lệnh x++ thực thi sau lệnh gán output_d(x) (chỉ trừ khi interrupt xảy ra ngay sau lệnh output_d(x) và trước lệnh x++, khả năng ~ 0) nên nếu muốn 2 Port xuất giá trị bằng nhau khi nhấn phím thì chuyển lệnh x++ lên trước.

ThaoBinh90 10-04-2009 10:04 AM

Trích:

Nguyên văn bởi namqn (Post 24566)
Tôi không dùng CCS C nên không rõ biến x trong main sẽ được trình biên dịch xử lý ra sao khi được truy xuất trong chương trình xử lý ngắt, nhưng tôi cho rằng bạn có thể dùng biến toàn cục (nghĩa là đặt biến x ra ngoài main() và isrext() của bạn).

Thân,

- Mình cũng nghĩ vậy đó, nếu khai báo x la biến toàn cục thì ngắt có thể hiểu được đó!

bien_van_khat 10-04-2009 10:26 AM

Trích:

Nguyên văn bởi cskiller (Post 24573)
Code:

// INTEXT.C  MPB  10-4-07
// Demo external interrupt
// RB0 low interrupts
// foregroundoutput count

#include "16F877a.h"
#fuses HS,NOWDT       
#use delay(clock=12000000)

int x=10;     
     
#int_ext
void isrext()                         

  output_c(x);      //muc dich là xuat ra portC giá tri. cu?a x hie^.n tho+`i trong ct chính
  delay_ms(1000);
}

             
void main()

                                 
    enable_interrupts(global);
   
    set_tris_b(get_tris_b()|0x01);
    enable_interrupts(int_ext);
    ext_int_edge(H_TO_L);

    while(1)
    { 
        output_d(x);
        x++;
        delay_ms(100);
    }
}


Điều gì sẽ xảy ra nếu ngắt xảy ra khi đang thực hiện biểu thức x++?

Với biến kiểu integer 8 bit, biểu thức x++ có thể được dịch thành mã máy là incf x, 1, tức là thực hiện x++ chỉ trong 1 chu kỳ máy, trong trường hợp này thì chưa có vấn đề.

Nhưng không ai đảm bảo là biểu thức đó sẽ được dịch thành chỉ 1 lệnh. Nếu x là kiểu 16 hoặc 32 bit thì chắc chắn là không thể thực hiện x++ trong 1 chu kỳ máy.

Nếu ngắt xảy ra khi đang thực hiện x++, chuơng trình phục vụ ngắt của bạn lại thay đổi giá trị của x thì sẽ gây lỗi chuơng trình và có thể rất khó phát hiện vì hiếm khi xảy ra.

Để tránh trường hợp này, với những biến dùng chung cho cả chuơng trình chính và chuơng trình con bạn phải khai báo volatile.

VD: volatile int x;

cskiller 10-04-2009 11:53 AM

Trích:

Nguyên văn bởi bien_van_khat (Post 24606)
Điều gì sẽ xảy ra nếu ngắt xảy ra khi đang thực hiện biểu thức x++?

Với biến kiểu integer 8 bit, biểu thức x++ có thể được dịch thành mã máy là incf x, 1, tức là thực hiện x++ chỉ trong 1 chu kỳ máy, trong trường hợp này thì chưa có vấn đề.

Nhưng không ai đảm bảo là biểu thức đó sẽ được dịch thành chỉ 1 lệnh. Nếu x là kiểu 16 hoặc 32 bit thì chắc chắn là không thể thực hiện x++ trong 1 chu kỳ máy.

Nếu ngắt xảy ra khi đang thực hiện x++, chuơng trình phục vụ ngắt của bạn lại thay đổi giá trị của x thì sẽ gây lỗi chuơng trình và có thể rất khó phát hiện vì hiếm khi xảy ra.

Để tránh trường hợp này, với những biến dùng chung cho cả chuơng trình chính và chuơng trình con bạn phải khai báo volatile.

VD: volatile int x;

1. Trong chương trình này, khả năng xảy ra khi đang thực thi x++ là ~0(1 vài lệnh so với delay_ms(100); chẳng thấm vào đâu) và hàm phục vụ ngắt không thực hiện tác vụ write/update biến mà chỉ read giá trị.
2. Việc khai báo volatile cho biết biến x có thể được truy cập, thay đổi giá trị từ nhiều điểm thực thị trong chương trình(nên thường dùng cho các port IO) chứ không đảm bảo việc khi thực hiện x++ sẽ đúng khi có nhiều chương trình cùng thao tác trên x. Một điểm nữa cần để ý là khai báo volatile sẽ giúp compiler sẽ thực hiện thao tác tối ưu đúng(không tự động xóa các biểu thức điều kiện sai) khi gặp biến volatile.
3. Giải pháp critical access đơn giản nhất là:
Code:

disable_interrupts(GLOBAL);  //Đảm bảo không có ngắt nào được thực thi đoạn code tiếp sau lệnh này
x++;    //x co the la so integer 8,16,32 bits
enable_interrupts(GLOBAL);


bien_van_khat 10-04-2009 06:18 PM

Trích:

Nguyên văn bởi cskiller (Post 24608)
1. Trong chương trình này, khả năng xảy ra khi đang thực thi x++ là ~0(1 vài lệnh so với delay_ms(100); chẳng thấm vào đâu) và hàm phục vụ ngắt không thực hiện tác vụ write/update biến mà chỉ read giá trị.

Không ai dám đảm bảo rằng nó sẽ ko xảy ra, cho dù xác suất là nhỏ, nếu lỗi đã có thể xảy ra thì luôn cần phải tránh.
Dĩ nhiên trong bài toán này, lỗi này ko xảy ra vì x++ chỉ thực hiện trong 1 chu kỳ máy. Và có xảy ra cũng ko gây ra chuyện gì ghê ghớm, chỉ hiện thị sai vài con led.

Trích:

2. Việc khai báo volatile cho biết biến x có thể được truy cập, thay đổi giá trị từ nhiều điểm thực thị trong chương trình(nên thường dùng cho các port IO) chứ không đảm bảo việc khi thực hiện x++ sẽ đúng khi có nhiều chương trình cùng thao tác trên x.
Mình sai chỗ này, ở đây phải dùng cách này
Trích:

3. Giải pháp critical access đơn giản nhất là:
Code:

disable_interrupts(GLOBAL);  //Đảm bảo không có ngắt nào được thực thi đoạn code tiếp sau lệnh này
x++;    //x co the la so integer 8,16,32 bits
enable_interrupts(GLOBAL);


Trích:

Một điểm nữa cần để ý là khai báo volatile sẽ giúp compiler sẽ thực hiện thao tác tối ưu đúng(không tự động xóa các biểu thức điều kiện sai) khi gặp biến volatile.
Mình chưa hiểu ý bạn?

namqn 10-04-2009 08:10 PM

Trích:

Nguyên văn bởi bien_van_khat (Post 24621)
...
Mình chưa hiểu ý bạn?

Google với cụm từ khóa "volatile in C", một vài link tốt như sau:
http://publications.gbdirect.co.uk/c..._volatile.html
http://www.netrino.com/node/80

Thân,

cskiller 10-04-2009 11:26 PM

Ok, đồng ý nếu được chúng ta nên để ý và giải quyết triệt để vấn đề về đa truy cập biến dữ liệu để đảm bảo chương trình chạy đúng trong mọi trường hợp.

Trích:

Nguyên văn bởi namqn (Post 24626)
Google với cụm từ khóa "volatile in C", một vài link tốt như sau:
http://publications.gbdirect.co.uk/c..._volatile.html
http://www.netrino.com/node/80

Thân,

Thanks.

bien_van_khat 29-04-2009 03:28 PM

"The use of volatile is poorly understood by many programmers". :D

nguyenluong 01-05-2009 10:29 AM

Trích:

Nguyên văn bởi namqn (Post 24561)
Bạn không nên dùng delay_ms(1000) trong chương trình xử lý ngắt, vì các hoạt động khác trong vòng lặp chính sẽ bị dừng lại cho đến khi trở về từ ngắt, mà trong ngắt bạn lại dừng lại 1000 ms chẳng làm gì cả.

Thân,

================================================== ===============
để delay_ms(1000) cũng được có sao đâu. Tùy theo mục đích của mình thôi, hơn nữa trong chương trình này mình chỉ sử dụng một ngắt thôi mà. Đâu sợ ngắt khác xảy ra.

nguyenluong 04-05-2009 07:00 PM

Trích:

Nguyên văn bởi thaithien (Post 24563)
Vậy còn vấn đề biến x thì sao hả anh ?Em nghĩ là giá trị x trong chương trình chính đang chạy sẽ lưu vào một địa chỉ nhớ nào đó.làm sao mình đọc nó ra và gán vào cho biết nằm trong chương trình ngắt ?

Bác nghĩ vậy có thể chưa đúng, Nếu x là biến toàn cục thì biến x trong main va trong ngắt là một. Nếu x không phải là biến toàn cục thì khác nhau, tức là như bác nói vậy, x trong chương trình main là khác, khi vô ngắt x này tự lưu lại và x trong ngắt là một biến khác. Khi thoát khỏi ngắt thì nó lại pop giá trị x nảy lưu ra tính tiếp. chào


Múi giờ GMT. Hiện tại là 02:16 AM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam