Vì thế chương trình này được viết theo hệ điều hành thời gian thực real_time operating system cho phép sắp xếp danh mục đồng thời nhiều tác vụ trong hệ thống nguồn sử dụng chương trình R
Trang 1Chương 3:
GIỚI THIỆU:
Để tăng hiệu quả làm việc cũng như yêu cầu nhất thiết của chương trình là phải thực hiện đồng thời nhiều công việc hoặc nhiều tác vụ Vì thế chương trình này được viết theo hệ điều hành thời gian thực (real_time operating system) cho phép sắp xếp danh mục đồng thời nhiều tác vụ trong hệ thống nguồn sử dụng chương trình RTX-Tiny(RTX51) của phần mềm Keil
Ưu điểm của việc xây dựng chương trình theo kiểu này là hoạt động của các công việc khác nhau trong chương trình có thể hoạt động độc lập, không gây ảnh hưởng với nhau về mặt thời gian xử lý Nếu vì một lý do không mong muốn nào đó mà một tác vụ trong hệ thống chương trình không thực hiện được hoặc thời gian thực hiện quá lớn, hoặc có một vài vòng lặp vô tận trong chương trình thì hệ thống không bị “treo” mà các tác vụ khác vẫn có thể hoạt động bình thường
1 Giới thiệu phần mềm Keil:
Không như các chương trình viết cho vi xử lý trước đây, chương trình trong luận văn này không dùng ngôn ngữ hợp ngữ (assemler) mà được viết bằng ngôn ngữ lập trình C và liên kết với chương trình C51-compile của phần mềm Keil để dịch sang ngôn ngữ máy Đây là phần mềm chuyên dùng sử dụng
Trang 2ngôn ngữ lập trình C để lập trình cho các loại vi xử lý được sản xuất bởi nhiều hãng khác nhau trên thế giới, chương trình này chứa tất cả các hàm C mở rộng cần thiết cho vi điều khiển được sử dụng Tiện ích của cách viết này là ngôn ngữ lập trình C là ngôn ngữ lập trình cấp cao hơn và gần gủi với người sử dụng hơn ngôn ngữ máy tính assembler Ngoài ra, cấu trúc chương trình viết bằng C cũng gọn hơn và dễ quản lý hơn với các câu lệnh và vòng lặp đơn giản, điều này thật sự có lợi khi ta muốn nâng cấp hay mở rộng chương trình
Song song với những tiện ích trên, chương trình C51 của phần mềm Keil còn hổ trợ cho ta một số hàm cơ bản như các hàm vào/ ra (ví dụ như: hàm xuất nhập ký tự đơn getchar(),putchar(); hàm xuất nhập chuỗi ký tự gets(), puts()), các hàm thời gian thực của chương trình RTX51 Tiny … và một số hàm khác giúp hệ thống hoạt động hoàn hảo hơn
Bên cạnh đó, chương trình biên dịch và chương trình chạy mô phỏng trên máy tính (chương trình Debug) của phần mềm Keil là một thuận lợi rất lớn Nó giúp cho người lập trình có thể quan sát chương trình một cách chính xác với các bước thực hiện và từng lệnh chạy trong chương trình, có cả mã chương trình viết bằng ngôn ngữ C và chương trình dịch sang mã Assembler tương ứng do chương trình C51-compiler thực hiện Ngoài ra, với phần mềm này ta còn có thể theo dõi được sự thay đổi giá trị của các biến cần quan sát, các hàm ngắt, các giá trị vào/ra tại các chân Port, các giá trị dữ liệu truyền qua SBUF và cả các giá trị timer v.v
2 Giới thiệu chương trình tuần hoàn theo thời gian biểu của TRX51 tiny:
Trang 3RTX51 của phần mềm Keil được viết theo hệ điều hành thời gian thực giúp chương trình có thể thực hiện đa nhiệm (multi-tasking), cho phép một vài tác vụ hoặc vài vòng lặp vô tận được thực hiện gần như song song nhau trong chương trình
Tuy nhiên các tác vụ trong chương trình này không xảy ra đồng thời mà
do việc sắp xếp các tác vụ theo các múi thời gian được chia nhỏ, tức tại một thời điểm chỉ một công việc được thực hiện mà thôi Đồng hồ của CPU có thể được chia thành nhiều múi thời gian và chương trình sẽ tuần tự sắp xếp mỗi múi thời gian cho một tác vụ Mỗi tác vụ được phép thực hiện trong khoảng thời gian tối đa định trước và sau đó chương trình sẽ chuyển sang một tác vụ khác đã sẵn sàng thực hiện, chương trình cứ thế lặp lại tuần tự Vì mỗi múi thời gian được chia rất nhỏ, thường chỉ vài mili giây hoặc nhỏ hơn nên chương trình luôn được quét qua liên tục và vì thế các tác vụ dường như xảy ra đồng thời Nếu tại một thời điểm nào đó mà không có một tác vụ nào thực hiện thì tác vụ được khởi động kế tiếp sẽ ở trạng thái sẵn sàng (ready) hoặc trang thái nghỉ (time-out)
RTX51 sử dụng các thủ tục thời gian được ngắt bởi phần cứng của timer
8051 Chu kỳ ngắt được xây dựng và sử dụng theo đồng hồ của RTX51
RTX51 không yêu cầu có một hàm Main trong chương trình Nó sẽ tự động gọi và thực hiện chương trình bắt đầu từ tác vụ 0 Nếu ta sử dụng hàm Main trong chương trình, ta phải khởi động RTX51 sử dụng hàm os_create_task và hàm os_start_system trong RTX51
Trang 4Khi rơi vào trạng thái nghỉ (timer out), thay vì tạm dừng thực hiện một tác vụ và đứng chờ một lần quét khác, ta có thể sử dụng hàm os_wait để tín hiệu RTX51có thể bắt đầu chuyển sang thực hiện một tác vụ khác Hàm này thực hiện việc trì hoãn tác vụ hiện hành và đợi cho đến khi có một sự kiện được định trước xảy đến Trong khoảng thời gian nghỉ này bất cứ một tác vụ nào khác cũng có thể được thực hiện
Sử dụng thời gian nghỉ (time-out) với RTX51:
Một sự kiện đơn giản nhất mà ta có thể đợi với hàm os_wait là khoảng thời gian nghỉ theo nhịp đồng hồ của RTX51 Sự kiện này có thể được sử dụng trong những tác vụ mà có yêu cầu delay Trong vài trường hợp nó được sử dụng như một switch, mà switch này chỉ cần được kiểm tra sau những khoảng thời gian nhất định Điều được minh họa trong ví dụ sau:
#include <rtx51tny.h>
int counter0;
int counter1;
void job0 (void) _task_ 0 { os_create ( 1 ) ;
while ( 1 ) { counter0 ++;
os_wait (K_TMO, 3,0);
}
Trang 5}
void job1 (void) _task_ 1
{ while (1)
{ counter1++;
os_wait (K_TMO, 5, 0);
}
}
trong ví dụ trên, job0 có thể thực hiện trước job1 Nhưng hiện tại, sau khi tăng counter0, job0 gọi hàm os_wait để tạm dừng 3khoảng chia thời gian Ngay lúc này, RTX51 chuyển sang tác vụ kế tiếp, cụ thể là job1,sau khi job1 tăng counter1, nó cũng gọi hàm os_wait để tạm dừng 5 khoảng chia thời gian Lúc này, RTX51 không có tác vụ nào khác để thực hiện, vì thế nó rơi vào trạng thái không làm gì cả và đợi hết 3 khoảng chia thời gian trôi qua trước khi tiếp tục thực hiện job1
Kết quả của ví dụ này là counter0 cứ tăng sau mỗi 3 khoảng thời gian và counter1 cứ tăng sau mỗi 5 khoảng chia thời gian
Sử dụng tín hiệu với RTX51:
Ta có thể dùng hàm os-wait để tạm dừng một tác vụ trong khi đợi
một tín hiệu từ một tác vụ khác Điều này có thể sử dụng cho hai hay nhiều tác vụ ngang bằng nhau Đợi một tín hiệu làm việc có nghĩa là: Nếu một tác vụ đang đợi một tín hiệu ,và cờ tín hiệu là 0, tác vụ này sẽ
Trang 6được trì hoãn cho đến khi có tín hiệu gởi đến Nếu cờ tín hiệu đã lên 1 khi
1 tác vụ hỏi, cờ này sẽ được xoá, và tác vụ đó lại tiếp tục thực hiện Điều này được minh hoạ trong ví dụ sau:
#include <rtx51tny.h>
int counter0;
int counter1;
void job0 (void) _task_ 0 { os_create ( 1 ) ;
while ( 1 ) { if ( ++counter0 == 0 ) os_send_signal ( 1 ) ; }
}
void job1 (void) _task_ 1
{ while (1)
{ os_wait (K_SIG, 0, 0);
counter1++;
}
}
Trang 7Trong ví dụ trên, job1 sẽ đợi cho đến khi nó nhận được tín hiệu từ một hoặc vài tác vụ khác gởi đến Khi nhận được tín hiệu, nó sẽ tăng counter1 và lại đợi một tín hiệu khác job0 liên tục tăng counter0 nó tràn đến 0 Khi điều đó xảy ra, job 0 gởi một tín hiệu đến job1 và chương trình RTX51 đánh dấu job1 là sẵn sàng thực hiện Tuy nhiên, job1 sẽ không được thực hiện trong suốt thời gian RTX51 nhận nó cho đến khi chuyển sang một múi thời gian kế tiếp
Sự ưu tiên và quyền ưu tiên:
Một bất lợi của chương trình ví dụ trên là job1 không được bắt đầu ngay khi nhận được tín hiệu từ job0 Trong một số trường hợp điều này không được chấp nhận vì lí do thời gian RTX51 cho phép ta xác định mức ưu tiên cho từng tác vụ Một tác vụ với mức ưu tiên cao hơn sẽ được ngắt hoặc được quyền ưu tiên hơn đối với một tác vụ có mức ưu tiên thấp hơn bất cứ khi nào nó cần được thực hiện
Trong ví dụ trên, ta có thể thay đổi cách khai báo cho job1 nhận mức ưu tiên cao hơn job0 Theo mặc định, tất cả các tác vụ được định mức ưu tiên là 0, là mức ưu tiên thấp nhất Các mức ưu tiên cho phép là từ 0 đến 3 Trong ví dụ trên ta, có thể định nghĩa job1 với mức ưu tiên cấp 1 như sau:
Void job1 (void) _ task_ 1 _priority_ 1
{While (1)
{ Os_wait (K_SIG, 0, 0 );
Counter1++;
}
Trang 8}
Với cách khai báo này, bất cứ khi nào job0 gởi tín hiệu đến job1, job1 sẽ bắt đầu thực hiện ngay
3 Một số yêu cầu và định nghĩa đối với chương trình RTX51 Tiny:
Điều khiển ngắt:
RTX51 Tiny có thể hoạt động song song với các hàm ngắt Tương tự như các ứng dụng khác của 8051, nguồn ngắt phải được cho phép bởi các thanh ghi phần cứng của 8051 để tạo ra một ngắt RTX51 Tiny không chứa bất cứ một sự điều khiển nào cho các ngắt; vì lý do đó, một cho phép ngắt cụ thể là đủ để xử lý ngắt.RTX51 Tiny sử dụng timer 0 và ngắt timer0 của 8051 cho hệ thời gian thực Ngoại trừ các cấu trúc khác của 8051, để tránh sự trùng lặp trong xử lý ngắt timer0 không nên được sử dụng trong chương trình
Registerbanks:
RTX51 tiny qui tất cả các tác vụ vào registerbank 0 Vì lý do đó, tất cả các hàm tác vụ phải được chuyển từ ngôn ngữ cấp cao sang ngôn ngữ cấp thấp theo định nghĩa của chương trình C51 Các hàm ngắt có thể sử dụng các registerbank còn lại Tuy nhiên, RTX51 yêu cầu 6 byte cố định trong không gian
registerbank Các registerbank được sử dụng bởi RTX51 Tiny có thể được định nghĩa theo biến cấu hình INT_REGBANK trong thư viện hàm của chương trình C51
Định nghĩa tác vụ:
Trang 9Chương trình thời gian thực hay đa nhiệm (multitasking) được biên soạn với một hoặc vài tác vụ thực hiện riêng biệt RTX51 cho phép thực hiện lên đến 16 tác vụ Các tác vụ là những hàm đơn của chương trình C có giá trị trả về
dạng void và danh sách các đối số dạng void được khai báo thuộc tính hàm như
sau:
void func (void) _task_ num
{…}
với num là số ID của tác vụ được đánh số liên tục từ 0 đến 15.
4 Các hàm thư viện của RTX51-tiny :
Os-create-task Ghi một tác vụ vào danh sách thực hiện
Os-delete_task Xóa một tác vụ khỏi danh sách thực hiện
Os_send_signal Gởi tín hiệu đến một tác vụ khác từ một ngắt Os- clear_signal Xóa tín hiệu đã đuợc gởi
Os_running_task_id Trở về tác vụ thứ ID từ tác vụ hiện hành
Os-wait Tạm dừng tác vụ hiện hành và đợi một hoặc
vài sự kiện như: 1 khoảng thời gian qui định, khoảng thời gian nghỉ hoặc tín hiệu từ một tác vụ khác hay một ngắt
Os-wait1 Tạm dừng tác vụ hiện hành và đợi một sự
kiện là tín hiệu từ một tác vụ khác
Os-wait2 Tạm dừng tác vụ hiện hành và đợi một hoặc
Trang 10vài sự kiện như : 1khoảng thời gian qui định, khoảng thời gian nghỉ hoặc tín hiệu từ một tác vụ khác hay một ngắt
Các thông số hàm:
Hàm os_create_task:
#include<rtx51tny.h>
char os_create_task (unsigned char task_id) /*tác vụ thứ id*/
Hàm Os-delete_task:
#include<rtx51tny.h>
char os_delete_task (insigned char task_id)
Hàm Os_send_signal
#include<rtx51tny.h>
char os_send_signal (insigned char task_id)
Hàm Os- clear_signal:
#include<rtx51tny.h>
char os_clear_signal (insigned char task_id)
Hàm Os_running_task_id:
Trang 11char os_running_task_id (void)
Hàm Os-wait:
#include<rtx51tny>
char os_wait (unsigned char event_sel, /*event: sự kiện chờ*/
unsigned char ticks, /*khoảng thời gian chờ*/ unsigned int dummy); /*unused argument*/ các hằng số sự kiên là:
K_IVL đợi một khoảng thời gian qui định K_SIG đợi một tín hiệu
K_TMO đợi một khoảng thời gian nghỉ
Os-wait1:
#include<rtx51tny>
char os_wait1 (unsigned char event_sel); /*event: sự kiện chờ*/ Hằng số sự kiện chỉ là K_SIG (đợi một tín hiệu)
Os-wait2:
char os_wait (unsigned char event_sel, /*event: sự kiện chờ*/
unsigned char ticks); /*khoảng thời gian chờ*/ các hằng số sự kiên là:
Trang 12K_IVL đợi một khoảng thời gian qui định K_SIG đợi một tín hiệu
K_TMO đợi một khoảng thời gian nghỉ