Các lựa chọn thay thế chủ đề cho các hệ thống nhúng
Tôi hiện đang học kỹ thuật điện. Do đại dịch, các lớp học của tôi đã bị tạm ngừng và thời gian này tôi đang sử dụng để học thêm về điện tử và lập trình.
Tôi hiện đang cố gắng sử dụng một Pic16f628a
và một màn hình kỹ thuật số chung để tạo ra một đồng hồ kỹ thuật số với một số tính năng. Vấn đề là tôi đã phải truy cập menu nhấn một nút trong thời gian thực thi, trong khi đồng hồ đang được hiển thị. Thông thường, tôi sẽ gọi một luồng để hiển thị đồng hồ và luồng chính sẽ xem các đầu vào, nhưng do sự đơn giản của bộ điều khiển pic, tôi không thể sử dụng tài nguyên.
Vì vậy, mã C của tôi (chưa được triển khai cụ thể cho pic) là một cái gì đó như thế này:
void display_timer(){
static struct current_time timer;
static int is_time_set = 0;
set_current_time(&timer, &is_time_set);
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
sleep(1);
update_timer(&timer, &is_time_set);
}
}
int main ()
{
while (1){
display_menu();
}
}
Trong thời gian ngủ (), bộ điều khiển sẽ có thể theo dõi các đầu vào mới và hoạt động tương ứng.
Một cách thay thế mà tôi đã sử dụng là sử dụng máy trạng thái để lưu trữ một lần nhấn nút, chia chức năng ngủ thành 4 hoặc 8 khoảng thời gian, giống như sau:
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
for (int i = 0; i<8; i++){
if (state_machine_input == 1){state_machine_input = 0; break;}
sleep(1/8);
}
update_timer(&timer, &is_time_set);
Nó có thể được thực hiện, nhưng tôi đánh giá cao nếu tôi không phải thêm phức tạp hơn vào dự án, thêm một máy trạng thái khác chẳng hạn. Tôi có thể làm gì trong bộ phần mềm để triển khai chức năng này?
Trả lời
Phân luồng là một khái niệm cấp cao hơn so với lập trình vi điều khiển. Nói một cách đơn giản, các luồng được thực hiện như một bộ lập lịch sử dụng các ngắt bộ định thời, lần lượt lưu bộ đếm chương trình + con trỏ ngăn xếp, v.v. và đặt chúng ở các vị trí khác nhau. Vì vậy, hoàn toàn có thể và dễ dàng thực hiện một khái niệm tương tự bằng cách sử dụng ngắt - với lợi ích là bạn nhận được các ngắt chuyên biệt thay vì đa luồng chung chung.
Đó là cách hợp lý duy nhất để làm điều đó với một di sản 8 bị hạn chế như PIC, vốn cực kỳ hạn chế khi sử dụng ngăn xếp. Quên việc sử dụng các lib luồng, ngay cả những thứ được viết cho vi điều khiển. Điều đó sẽ chỉ làm tăng thêm sự cồng kềnh và phức tạp mà không thu được gì. Nói chung là một ý tưởng tồi nếu kéo các khái niệm lập trình PC vào thế giới nhúng.
Những gì bạn nên làm là đặt nút quét của bạn bên trong một ngắt hẹn giờ theo chu kỳ được thực hiện một lần mỗi 10ms hoặc lâu hơn. Từ bên trong ngắt, bạn thăm dò các nút và so sánh nút đã đọc với lần trước đó, cho mục đích gỡ lỗi. Kết quả của việc này được lưu trữ trong một biến được chia sẻ với chương trình chính, được khai báo là volatile
và được bảo vệ khỏi các điều kiện chủng tộc. Vì bạn chỉ ghi vào biến từ bên trong các ngắt, nó có thể đủ bảo vệ để đảm bảo rằng các lần đọc là 8 bit, nhưng bạn phải tháo rời để chắc chắn. Thông tin thêm về điều đó tại đây: Sử dụng dễ bay hơi trong phát triển C nhúng .
Sử dụng ngắt
Bạn muốn chạy một số mã khi nhấn một nút? Sử dụng ngắt pin-thay đổi
Bạn muốn làm điều gì đó vào một khoảng thời gian cố định? Sử dụng bộ hẹn giờ ngắt
Theo một cách nào đó, phần cứng của bộ vi điều khiển chạy một 'luồng' giám sát các nguồn ngắt và chạy một 'lệnh gọi lại' hoặc quy trình ngắt cho mỗi sự kiện.
Chương trình chính sẽ tự động bị tạm dừng trong khi thực hiện ngắt.
Một cách phổ biến để chia sẻ dữ liệu giữa các ngắt và mã chính là thông qua volatile
các biến toàn cục và tạm thời vô hiệu hóa các ngắt khi đọc dữ liệu từ các toàn cầu này khi chúng lớn hơn kích thước từ của bộ điều khiển (hầu như luôn có trên bộ điều khiển 8 bit)
Tôi có thể sẽ đề xuất một thư viện đa nhiệm hợp tác. Một mà tôi đã sử dụng trong quá khứ là Protothreads:http://www.dunkels.com/adam/pt/
Bất kỳ thư viện đa nhiệm hợp tác tốt nào sẽ giúp loại bỏ máy trạng thái ngầm cần thiết để theo dõi mọi thứ.
Chúc may mắn.
Nói chung, có các cách tiếp cận khác nhau với đa nhiệm khi nói đến hệ thống nhúng:
- Thăm dò ý kiến hoặc Đa nhiệm hợp tác : Mọi thứ được thực hiện trong một vòng lặp vô hạn và các tác vụ được thiết kế để dành thời gian tối thiểu có thể và quay lại quá trình thực thi chính nhanh nhất có thể, để tránh chậm trễ. Lưu ý rằng các tác vụ phù hợp với kiến trúc này có thể không giống như những gì bạn nghĩ về khái niệm cấp cao hơn, ví dụ: trong ứng dụng của bạn, một tác vụ có thể là
update_display
và một tác vụ khác có thể làcheck_button
và bạn sẽ xây dựng một vòng lặp như:
while(1){
check_buttons();
update_display();
sleep(0.1); //seconds
}
Ngắt : Tất cả các đầu vào có thể có khi được kết nối với ngắt phần cứng và việc thực thi chính được để lại cho những thứ không thể ngắt (có thể không có gì, trong trường hợp này, bộ vi điều khiển thường được đặt ở chế độ nghỉ để giảm mức tiêu thụ điện năng. Chi tiết cách thực hiện được thực hiện thường phụ thuộc vào bộ vi điều khiển và trình biên dịch cụ thể được sử dụng.
RTOS : tùy thuộc vào mức năng lượng mà bộ vi điều khiển cung cấp, có thể chạy Hệ điều hành thời gian thực (RTOS), hệ điều hành này có thể cung cấp API để tạo các tác vụ hoặc thậm chí các luồng. Điều này phụ thuộc vào ứng dụng và khả năng phần cứng, và đối với các ví dụ giáo dục thì không cần thiết (hoặc khuyến khích, imo)
Cũng cần lưu ý rằng một phần quan trọng khác trong việc quyết định kiến trúc tổng thể của ứng dụng là sự phân chia nhiệm vụ và cách chúng hợp tác. Một trong những mô hình được sử dụng là State Machines (liên kết đến trang wikipedia chung có thể quá tải, bạn có thể tìm thấy các tài nguyên đơn giản hơn dành riêng cho lập trình nhúng trên sách giáo khoa hoặc trên google).
Hầu hết, trong các thiết bị 8-bit có nguồn hạn chế. Tôi nghĩ rằng giải pháp đơn giản hơn là giải pháp tốt hơn trong PIC 8-bit.
Bạn có thể tạo Bộ hẹn giờ phần cứng cho 2 tác vụ khác nhau. Đặt cờ và kiểm tra cờ trong vòng lặp vô hạn của bạn, thực hiện nhiệm vụ và đặt lại cờ. Đừng sử dụng sự chậm trễ. Phương pháp này đảm bảo thực hiện các nhiệm vụ của bạn trong vòng lặp vô hạn của bạn, nếu bạn gắn cờ.
Tuy nhiên, bạn phải biết rằng các tác vụ không được thực thi thời gian chính xác khi cờ lên. Nếu có hai cờ được đặt cùng một lúc, bạn không thể biết cờ nào được thực thi trước. Vì bạn không biết ở đâu trong vòng lặp vô hạn. Tuy nhiên, hầu như không sao đối với các ứng dụng giao diện không quan trọng về thời gian.