Xem bài viết riêng lẻ
Cũ 26-02-2013, 08:48 AM   #7
bpa
Member
 
Tham gia ngày: May 2012
Bài gửi: 52
Online Status: bpa đang online
Mặc định

Lập trình cho module bằng OpenAT

Về cấu trúc, OpenAT dựa hoàn toàn vào C/C++ nên việc làm quen với lập trình OpenAT không khó khăn nhiều với những người đã biết lập trình C/C++. Chỉ cần biết các hàm ADL và một số điểm khác biệt so với ngôn ngữ C/C++ là các bạn có thể hoàn toàn làm chủ ngôn ngữ lập trình OpenAT.

Chúng ta sẽ cùng phân tích một ví dụ đơn giản nhất là “Hello World” để hình dung ra cấu trúc của một chương trình OpenAT. Ví dụ này có trong bộ DeveloperStudio, các bạn làm theo các bước mình đã hướng dẫn ở bài trước để tạo project Hello chứa ví dụ Hello của DeveloperStudio. Khi chạy chương trình, mỗi giây sẽ in ra cổng UART dòng chữ “Hello World from Open-AT”.

Một chương trình OpenAT được chia thành các task, được định nghĩa qua “adl_InitTasks” table.
“adl_InitTasks” table chứa các structure định nghĩa các task trong chương trình.
Mỗi structure bao gồm: tên entry point (tên hàm định nghĩa task), Stack size, tên task, mức độ ưu tiên.
Kết thúc một “adl_InitTasks” table luôn là task có mức ưu tiên bằng 0, các giá trị khác là NULL (hay 0)
const adl_InitTasks_t adl_InitTasks [] =
{
{ main_task, DECLARE_CALL_STACK ( 1024 ), "main", 1 },
{ 0, 0, 0, 0 }
};
Ở đây, main_task là tên hàm main được định nghĩa ở trên :
extern void main_task ( void );
Chú ý là một chương trình OpenAT không có hàm main chung, mà chỉ có hàm main cho từng task.

DECLARE_CALL_STACK là macro định nghĩa stacksize theo từng phiên bản trình dịch, để đơn giản ta có thể thay bằng một con số cụ thể, giá trị tùy thuộc vào mức độ sử dụng của chương trình, nhưng không vượt quá dung lượng RAM có thể sử dụng.

#ifndef __GNU_GCC__
#define DECLARE_CALL_STACK(X) (X)
#else
#define DECLARE_CALL_STACK(X) (X*3)
#endif
Đoạn này để định nghĩa stack size khi dùng các trình dịch khác nhau. Nếu khai báo cố định một giá trị stack size, ta sẽ không cần đoạn chương trình này.
"main" là tên gọi của task, có thể dùng bất cứ tên nào cũng không ảnh hưởng đến chương trình.
Chương trình gồm 1 task nên task có mức ưu tiên là 1, nếu có nhiều task, mức độ ưu tiên sẽ tăng dần, luôn bắt đầu từ 1 (không kể task NULL kết thúc)

Bây giờ đi sâu vào phân tích các lệnh của chương trình:
void main_task ( void )
{
adl_InitType_e adl_InitType = adl_InitGetType ();
TRACE (( 1, "Embedded : Appli Init" ));


adl_tmrSubscribe ( TRUE, 10, ADL_TMR_TYPE_100MS, HelloWorld_TimerHandler );
}

Lệnh “TRACE” thường dùng để debug, nó in các thông tin debug ra cổng UART 1 hoặc UART 2 của module, trong các ứng dụng của OpenAT, thường dùng cách này hoặc dùng lệnh “adl_atSendResponse “ để print trực tiếp thông tin debug ra cổng UART.
adl_InitGetType() là hàm dùng để lây nguyên nhân module bị reset (power on hay reset do lỗi, do mới download xong firmware mới…)

adl_tmrSubscribe() để tạo một timer (ở ví dụ này là 1s lặp lại) để in dòng chữ "\r\nHello World from Open-AT\r\n" ra cổng UART đang hoạt động
Chi tiết các hàm này các bạn tham khảo trong tài liệu “ADL user guide” , trong đó viết rất chi tiết và đầy đủ, tất cả các hàm đều có giải thích và ví dụ nên rất dễ đọc.

Một điều chú ý, OpenAT là một RTOS nên trong các chương trình ứng dụng viết bằng OpenAT, watchdog timer tự động được kích hoạt, nếu các bạn dùng các vòng lặp chờ (như chờ dữ liệu từ UART…) phải chú ý có thể watchdog timer sẽ làm module bị reset liên tục.
  Trả lời với trích dẫn