Tôi đang sử dụng con STC8A8K64D4, đã tải phần mềm từ trang web chính thức và cài đặt xong, nhưng vẫn không thể sử dụng ngắt lớn được, lỗi gì vậy? Dưới đây là thông báo lỗi:
*** ERROR L121: IMPROPER FIXUP
MODULE: .\Objects\main.obj (MAIN)
OFFSET: 0001C4H
Program Size: data=18.3 xdata=1048 const=0 code=5874
Target not created.
Build Time Elapsed: 00:00:00
Tôi thấy thông báo lỗi của bạn là ERROR L121: IMPROPER FIXUP. Lỗi này rất điển hình khi sử dụng Keil để xử lý ngắt có số hiệu lớn trên vi điều khiển STC.
Tóm lại: Trình biên dịch C51 của Keil chỉ hỗ trợ nguyên bản các ngắt từ 0 đến 31. Bạn đang dùng model STC8A8K64D4, trong đó một số ngắt (như UART2, UART3, UART4 hay PCA…) thường có số hiệu lớn hơn 31, nếu viết trực tiếp sẽ gây ra lỗi này.
Bạn nói đã dùng phần mềm “mở rộng số hiệu ngắt” từ trang web chính thức của STC nhưng vẫn còn lỗi — nguyên nhân phổ biến nhất là các bước thực hiện chưa đầy đủ hoặc chưa đúng. Tôi sẽ cung cấp hai giải pháp, và khuyên bạn nên thử phương án một trước (nếu đã cài công cụ rồi thì khả năng cao là chưa gọi đúng cách).
Phương án 1: Sử dụng đúng công cụ “Mở rộng vector ngắt” chính hãng của STC
Phần mềm STC-ISP có tích hợp sẵn công cụ này. Nhiều người nghĩ rằng chỉ cần “cài đặt” là xong, nhưng thực tế là bạn phải khởi động Keil thông qua công cụ này trước mỗi lần biên dịch, hoặc cần thay thế file hệ thống.
Tìm công cụ: Mở phần mềm STC-ISP, nhấn vào mục bên cột phải “Thiết lập mô phỏng Keil”, trong đó có nút “Thêm model và file tiêu đề vào Keil”. Lưu ý: Thao tác này không chỉ thêm model mới, mà còn tự động cài đặt plugin hỗ trợ mở rộng số hiệu ngắt.
Thêm lại một lần nữa: Dù bạn đã từng thêm trước đó, hãy nhấn lại nút này, chọn thư mục cài đặt Keil (ví dụ: C:\Keil_v5), xác nhận thêm.
Xác minh plugin: Sau khi thêm thành công, hãy vào thư mục dự án Keil của bạn, tìm đến thư mục \\Keil\\C51\\BIN. Trong đó có file C51.EXE. Nếu việc mở rộng thành công, STC đã dùng một phiên bản C51.EXE hỗ trợ ngắt số lớn để thay thế hoặc vá (patch) cho file gốc.
Biên dịch lại: Đóng Keil, mở lại dự án, nhấn Rebuild (không chỉ nhấn Build), và kiểm tra xem còn lỗi không.
Phương án 2: Chuyển hướng bằng Assembly (phương pháp “hard fix” đáng tin cậy nhất)
Nếu sau khi thực hiện phương án 1 mà vẫn còn lỗi, có thể công cụ mở rộng chưa hoạt động do vấn đề quyền hệ thống hoặc khác. Lúc này, tôi khuyên bạn nên dùng chuyển hướng bằng mã Assembly — đây là cách chắc chắn nhất và không phụ thuộc vào bản vá trình biên dịch.
Ví dụ cách viết:
Giả sử hàm ngắt của bạn ban đầu được viết như sau (giả sử số hiệu ngắt là 46):
void UART4_ISR(void) interrupt 46
{
// Mã xử lý ngắt của bạn
}
Hãy sửa lại như sau:
// 1. Hàm xử lý ngắt thật: Không dùng từ khóa interrupt, viết như hàm bình thường
void UART4_ISR(void)
{
// Viết lại toàn bộ mã xử lý ngắt (giữ nguyên như cũ)
}
// 2. Thiết lập chuyển hướng trong vùng Assembly: ánh xạ địa chỉ vector ngắt tới hàm trên
void UART4_ISR_Entry(void) interrupt 46
{
// Dùng nội tuyến Assembly để nhảy đến hàm thật
__asm
LJMP _UART4_ISR
__asm
}
Điểm quan trọng:
Tên hàm trong Assembly phải có dấu gạch dưới phía trước: _UART4_ISR (vì khi hàm C được biên dịch sang Assembly, tên hàm sẽ tự động thêm dấu gạch dưới ở đầu).
Nếu bạn dùng linker LX51, cú pháp có thể hơi khác, nhưng cách viết trên hoàn toàn tương thích với Keil.
Gợi ý tổng kết
Hãy quay lại STC-ISP và thêm lại “model và file tiêu đề”, đảm bảo chọn đúng đường dẫn (phải chọn đúng thư mục gốc của Keil).
Nếu vẫn còn lỗi, đừng cố gắng sửa công cụ nữa, hãy chuyển ngay sang phương án 2 (chuyển hướng bằng Assembly). Cách này tuy thêm vài dòng mã, nhưng sẽ không bao giờ gặp lỗi L121, đồng thời có tính di động cao. Rất nhiều lập trình viên lâu năm với STC đều dùng cách này.
Anh em đừng vội, dòng STC8 dùng ngắt lớn báo lỗi L121: IMPROPER FIXUP là lỗi rất thường gặp. Dù anh đã cài plugin mở rộng số ngắt chính thức, nhưng khả năng lớn là thiết lập bên trong Keil chưa theo kịp.
Anh có thể lần lượt kiểm tra các nguyên nhân có khả năng nhất sau đây:
1. Chưa chuyển sang linker mở rộng (LX51) — Nguyên nhân phổ biến nhất
Linker mặc định BL51 của Keil C51 hỗ trợ rất kém các ngắt lớn hơn số 31, dễ dẫn đến lỗi L121.
Cách khắc phục: Nhấn vào biểu tượng “magic wand” (Options for Target) trong Keil → tìm đến tab Device → tích chọn Use Extended Linker (LX51) instead of BL51. Sau đó Rebuild All lại thử, 90% trường hợp là lỗi sẽ được giải quyết ngay lập tức.
2. Plugin bị cài nhầm đường dẫn Keil
Nếu máy anh cài nhiều phiên bản Keil (ví dụ vừa cài MDK-ARM và C51 cùng lúc, hoặc cài ở hai ổ đĩa khác nhau), thì bản vá mở rộng chính thức có thể đã được giải nén vào thư mục Keil không phải đang dùng.
Cách khắc phục: Xác nhận rõ đường dẫn giải nén bản vá có đúng là thư mục gốc Keil đang sử dụng hay không (đặc biệt kiểm tra xem các file trình biên dịch trong thư mục C51\\BIN đã được thay thế đúng chưa).
3. Phiên bản Keil C51 quá cũ
Bản vá mở rộng số ngắt chính thức yêu cầu một phiên bản Keil nhất định. Nếu phiên bản Keil của anh quá cũ (ví dụ dưới v9.54), dù đã cài bản vá, bộ hợp dịch底层 vẫn có thể không nhận diện được địa chỉ offset của ngắt lớn.
Cách khắc phục: Nên nâng cấp Keil C51 lên phiên bản v9.60 trở lên.
4. Do các file rác từ lần biên dịch trước
Đôi khi sau khi cài bản vá, các file .obj cũ vẫn còn tồn tại và gây nhiễu trong quá trình liên kết.
Cách khắc phục: Không nên nhấn “Build”, hãy nhấn “Rebuild All” để dọn sạch hoàn toàn các file cũ và biên dịch lại từ đầu.
Anh cứ thử bước thứ nhất là chuyển sang LX51 trước. Nếu vẫn không được, tốt nhất chụp ảnh tab Target và Device trong cửa sổ “magic wand” gửi lên để mọi người cùng kiểm tra giúp.