Đây là một câu hỏi mà cha tôi luôn luôn hỏi tôi. " Tại sao nó không chạy qua tất cả các hướng dẫn và dừng lại ở cuối? "
Hãy xem xét một ví dụ bệnh lý. Đoạn mã sau được biên dịch trong trình biên dịch C18 của Microchip cho PIC18:
void main(void)
{
}
Nó tạo ra đầu ra trình biên dịch mã sau:
addr opco instruction
---- ---- -----------
0000 EF63 GOTO 0xc6
0002 F000 NOP
0004 0012 RETURN 0
.
. some instructions removed for brevity
.
00C6 EE15 LFSR 0x1, 0x500
00C8 F000 NOP
00CA EE25 LFSR 0x2, 0x500
00CC F000 NOP
.
. some instructions removed for brevity
.
00D6 EC72 CALL 0xe4, 0 // Call the initialisation code
00D8 F000 NOP //
00DA EC71 CALL 0xe2, 0 // Here we call main()
00DC F000 NOP //
00DE D7FB BRA 0xd6 // Jump back to address 00D6
.
. some instructions removed for brevity
.
00E2 0012 RETURN 0 // This is main()
00E4 0012 RETURN 0 // This is the initialisation code
Như bạn có thể thấy, hàm main () được gọi và ở cuối có chứa câu lệnh return, mặc dù chúng tôi không đặt nó ở đó một cách rõ ràng. Khi trả về chính, CPU thực hiện lệnh tiếp theo, đơn giản là GOTO để quay lại phần đầu của mã. main () được gọi đơn giản là lặp đi lặp lại.
Bây giờ, đã nói điều này, đây không phải là cách mọi người sẽ làm mọi thứ thường. Tôi chưa bao giờ viết bất kỳ mã nhúng nào cho phép main () thoát như thế. Hầu hết, mã của tôi sẽ trông giống như thế này:
void main(void)
{
while(1)
{
wait_timer();
do_some_task();
}
}
Vì vậy, tôi thường không bao giờ để main () thoát.
"OK ok" bạn nói. Tất cả điều này rất thú vị khi trình biên dịch đảm bảo không bao giờ có câu lệnh trả lại cuối cùng. Nhưng điều gì xảy ra nếu chúng ta buộc vấn đề này? Điều gì sẽ xảy ra nếu tôi tự mã hóa trình biên dịch chương trình của mình và không đặt lại bước khởi đầu?
Chà, rõ ràng CPU sẽ tiếp tục thực hiện các hướng dẫn tiếp theo. Những thứ đó sẽ trông giống như thế này:
addr opco instruction
---- ---- -----------
00E6 FFFF NOP
00E8 FFFF NOP
00EA FFFF NOP
00EB FFFF NOP
.
. some instructions removed for brevity
.
7EE8 FFFF NOP
7FFA FFFF NOP
7FFC FFFF NOP
7FFE FFFF NOP
Địa chỉ bộ nhớ tiếp theo sau lệnh cuối cùng trong hàm main () trống. Trên một vi điều khiển có bộ nhớ FLASH, một lệnh trống chứa giá trị 0xFFFF. Trên PIC ít nhất, mã op đó được hiểu là 'nop' hoặc 'không hoạt động'. Nó chỉ đơn giản là không làm gì cả. CPU sẽ tiếp tục thực thi các bước đó cho đến hết bộ nhớ.
Sau đó là gì?
Ở lệnh cuối cùng, con trỏ lệnh của CPU là 0x7FFe. Khi CPU thêm 2 vào con trỏ lệnh của nó, nó nhận được 0x8000, được coi là tràn trên PIC chỉ với 32k FLASH và do đó, nó quấn quanh trở lại 0x0000 và CPU vui vẻ tiếp tục thực hiện lại các hướng dẫn khi bắt đầu mã , giống như nó đã được thiết lập lại.
Bạn cũng hỏi về sự cần thiết phải tắt điện. Về cơ bản bạn có thể làm bất cứ điều gì bạn muốn, và nó phụ thuộc vào ứng dụng của bạn.
Nếu bạn đã có một ứng dụng chỉ cần thực hiện một việc sau khi bật nguồn, và sau đó không làm gì khác, bạn chỉ có thể đặt một lúc (1); ở cuối main () để CPU ngừng làm bất cứ điều gì đáng chú ý.
Nếu ứng dụng yêu cầu CPU tắt nguồn, thì tùy thuộc vào CPU, có thể sẽ có nhiều chế độ ngủ khác nhau. Tuy nhiên, CPU có thói quen thức dậy một lần nữa, vì vậy bạn phải đảm bảo rằng không có giới hạn thời gian cho giấc ngủ và không có Watch Dog Timer hoạt động, v.v.
Bạn thậm chí có thể tổ chức một số mạch bên ngoài cho phép CPU tự cắt hoàn toàn nguồn điện của mình khi hoàn thành. Xem câu hỏi này: Sử dụng nút ấn tạm thời làm công tắc bật tắt chốt .