Cách tốt nhất là sử dụng bộ định thời trên chip. Systick, RTC hoặc bộ định thời ngoại vi. Chúng có ưu điểm là thời gian chính xác, xác định và có thể dễ dàng điều chỉnh nếu thay đổi tốc độ xung nhịp của CPU. Tùy chọn, bạn thậm chí có thể để CPU ngủ và sử dụng ngắt đánh thức.
Mặt khác, các vòng lặp "làm chậm trễ", hiếm khi chính xác và đi kèm với các vấn đề khác nhau như "khớp nối chặt chẽ" với một bộ lệnh và xung nhịp CPU cụ thể.
Một số điều cần lưu ý:
- Việc lặp đi lặp lại một chân GPIO là một ý tưởng tồi vì điều này sẽ rút ra hiện tại một cách không cần thiết và có khả năng cũng gây ra các vấn đề EMC nếu pin được kết nối với dấu vết.
- Sử dụng hướng dẫn NOP có thể không hoạt động. Nhiều kiến trúc (như Cortex M, iirc) có thể bỏ qua NOP ở cấp độ CPU và thực sự không thực hiện chúng.
Nếu bạn muốn nhấn mạnh vào việc tạo ra một vòng lặp bận rộn bẩn thỉu, thì chỉ cần volatile
đủ điều kiện để lặp vòng lặp. Ví dụ:
void dirty_delay (void)
{
for(volatile uint32_t i=0; i<50000u; i++)
;
}
Điều này được đảm bảo để tạo mã crap khác nhau. Ví dụ gcc ARM -O3 -ffreestanding
đưa ra:
dirty_delay:
mov r3, #0
sub sp, sp, #8
str r3, [sp, #4]
ldr r3, [sp, #4]
ldr r2, .L7
cmp r3, r2
bhi .L1
.L3:
ldr r3, [sp, #4]
add r3, r3, #1
str r3, [sp, #4]
ldr r3, [sp, #4]
cmp r3, r2
bls .L3
.L1:
add sp, sp, #8
bx lr
.L7:
.word 49999
Từ đó, về lý thuyết, bạn có thể tính toán số lượng tích tắc của mỗi hướng dẫn và thay đổi số ma thuật 50000 tương ứng. Đường ống, dự đoán nhánh, vv sẽ có nghĩa là mã có thể thực thi nhanh hơn chỉ là tổng số chu kỳ đồng hồ. Vì trình biên dịch quyết định liên quan đến ngăn xếp, bộ nhớ đệm dữ liệu cũng có thể đóng một phần.
Toàn bộ quan điểm của tôi ở đây là việc tính toán chính xác thời gian mà mã này sẽ thực sự mất rất nhiều thời gian. Thử nghiệm & điểm chuẩn lỗi với một phạm vi có lẽ là một ý tưởng hợp lý hơn so với việc thử tính toán lý thuyết.