Hiện tại tôi đang mã hóa cho Cortex M0 / M4 và cách tiếp cận chúng tôi đang sử dụng trong C ++ (không có thẻ C ++, vì vậy câu trả lời này có thể lạc đề) như sau:
Chúng tôi sử dụng một lớp CInterruptVectorTable
có chứa tất cả các thói quen dịch vụ ngắt được lưu trữ trong vectơ ngắt thực tế của bộ điều khiển:
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
{ .__ptr = __sfe( "CSTACK" ) }, // 0x00
__iar_program_start, // 0x04
CInterruptVectorTable::IsrNMI, // 0x08
CInterruptVectorTable::IsrHardFault, // 0x0C
//[...]
}
Lớp CInterruptVectorTable
thực hiện một sự trừu tượng hóa các vectơ ngắt, vì vậy bạn có thể liên kết các hàm khác nhau với các vectơ ngắt trong thời gian chạy.
Giao diện của lớp đó trông như thế này:
class CInterruptVectorTable {
public :
typedef void (*IsrCallbackfunction_t)(void);
enum InterruptId_t {
INTERRUPT_ID_NMI,
INTERRUPT_ID_HARDFAULT,
//[...]
};
typedef struct InterruptVectorTable_t {
IsrCallbackfunction_t IsrNMI;
IsrCallbackfunction_t IsrHardFault;
//[...]
} InterruptVectorTable_t;
typedef InterruptVectorTable_t* PinterruptVectorTable_t;
public :
CInterruptVectorTable(void);
void SetIsrCallbackfunction(const InterruptId_t& interruptID, const IsrCallbackfunction_t& isrCallbackFunction);
private :
static void IsrStandard(void);
public :
static void IsrNMI(void);
static void IsrHardFault(void);
//[...]
private :
volatile InterruptVectorTable_t virtualVectorTable;
static volatile CInterruptVectorTable* pThis;
};
Bạn cần tạo các hàm được lưu trữ trong bảng vectơ static
vì bộ điều khiển không thể cung cấp một con this
trỏ vì bảng vectơ không phải là một đối tượng. Vì vậy, để giải quyết vấn đề đó, chúng ta có con pThis
trỏ tĩnh bên trong CInterruptVectorTable
. Khi nhập một trong các hàm ngắt tĩnh, nó có thể truy cập vào pThis
-pulum để có quyền truy cập vào các thành viên của một đối tượng CInterruptVectorTable
.
Bây giờ trong chương trình, bạn có thể sử dụng SetIsrCallbackfunction
để cung cấp một con trỏ hàm cho một static
hàm được gọi khi xảy ra gián đoạn. Các con trỏ được lưu trữ trongInterruptVectorTable_t virtualVectorTable
.
Và việc thực hiện một chức năng ngắt trông như thế này:
void CInterruptVectorTable::IsrNMI(void) {
pThis->virtualVectorTable.IsrNMI();
}
Vì vậy, nó sẽ gọi một static
phương thức của một lớp khác (có thể là private
), sau đó có thể chứa một con static
this
trỏ khác để có quyền truy cập vào các biến thành viên của đối tượng đó (chỉ một).
Tôi đoán bạn có thể xây dựng và giao diện thích IInterruptHandler
và lưu trữ các con trỏ tới các đối tượng, vì vậy bạn không cần con trỏ static
this
trong tất cả các lớp đó. (có lẽ chúng tôi thử điều đó trong lần lặp lại tiếp theo của kiến trúc của chúng tôi)
Cách tiếp cận khác hoạt động tốt đối với chúng tôi, vì các đối tượng duy nhất được phép thực hiện trình xử lý ngắt là những đối tượng bên trong lớp trừu tượng phần cứng và chúng tôi thường chỉ có một đối tượng cho mỗi khối phần cứng, do đó, nó hoạt động tốt với các con static
this
trỏ. Và lớp trừu tượng phần cứng cung cấp một sự trừu tượng hóa khác cho các ngắt, được gọi ICallback
là lớp sau đó được triển khai trong lớp thiết bị phía trên phần cứng.
Bạn có truy cập dữ liệu toàn cầu? Chắc chắn bạn làm như vậy, nhưng bạn có thể làm cho hầu hết các dữ liệu toàn cầu cần thiết ở chế độ riêng tư như các con this
trỏ và các hàm ngắt.
Nó không chống đạn, và nó có thêm chi phí. Bạn sẽ đấu tranh để thực hiện ngăn xếp IO-Link bằng cách sử dụng phương pháp này. Nhưng nếu bạn không quá chặt chẽ với thời gian, điều này hoạt động khá tốt để có được sự trừu tượng hóa linh hoạt của các ngắt và giao tiếp trong các mô-đun mà không sử dụng các biến toàn cục có thể truy cập từ mọi nơi.