Đa nhiệm trên vi điều khiển PIC


17

Đa nhiệm là quan trọng những ngày này. Tôi tự hỏi làm thế nào chúng ta có thể đạt được nó trong vi điều khiển và lập trình nhúng. Tôi đang thiết kế một hệ thống dựa trên vi điều khiển PIC. Tôi đã thiết kế phần sụn của nó trong MplabX IDE bằng C và sau đó thiết kế một ứng dụng cho nó trong Visual Studio bằng C #.

Vì tôi đã quen với việc sử dụng các luồng trong lập trình C # trên máy tính để bàn để thực hiện các tác vụ song song, có cách nào để làm điều tương tự trong mã vi điều khiển của tôi không? MplabX IDE cung cấp pthreads.hnhưng nó chỉ còn sơ khai không có triển khai. Tôi biết có hỗ trợ FreeRTOS nhưng việc sử dụng đó làm cho mã của bạn phức tạp hơn. Một số diễn đàn nói rằng các ngắt cũng có thể được sử dụng như đa tác vụ nhưng tôi không nghĩ các ngắt đó tương đương với các luồng.

Tôi đang thiết kế một hệ thống gửi một số dữ liệu tới UART và đồng thời nó cần gửi dữ liệu đến một trang web thông qua ethernet (có dây). Một người dùng có thể kiểm soát đầu ra thông qua trang web nhưng đầu ra bật ON / OFF với độ trễ 2-3 giây. Vì vậy, đó là vấn đề tôi đang phải đối mặt. Có giải pháp nào cho đa tác vụ trong vi điều khiển không?


Chỉ có thể được sử dụng trên các bộ xử lý chạy HĐH, vì các luồng là một phần của quy trình và các quy trình chỉ được sử dụng trong các HĐH.
TicTacToe

@Zola vâng bạn đúng. Nhưng những gì trong trường hợp của bộ điều khiển?
Máy bay

2
Bản sao có thể có của RTOS cho các hệ thống nhúng
Roger Rowland

1
Bạn có thể giải thích lý do tại sao bạn cần đa nhiệm thực sự và không thể triển khai hợp lý phần mềm của mình dựa trên cách tiếp cận nhiệm vụ vòng tròn hoặc vòng lặp select () hoặc tương tự không?
whatsisname

2
Vâng, như tôi đã nói, tôi đang gửi và nhận dữ liệu cho uart, đồng thời gửi và nhận dữ liệu tới ethernet. Ngoài ra, tôi cũng cần lưu dữ liệu trong thẻ SD cùng với thời gian, vì vậy có DS1307 RTC có liên quan và EEPROM cũng tham gia. Cho đến bây giờ tôi chỉ có 1 UART nhưng có thể sau vài ngày tôi sẽ gửi và nhận dữ liệu từ 3 mô-đun UART. Trang web cũng sẽ nhận dữ liệu từ 5 hệ thống khác nhau được cài đặt ở nơi xa. Tất cả điều này phải song song nhưng không phải không song song mà chậm trễ vài giây. !
Máy bay

Câu trả lời:


20

Có hai loại hệ điều hành đa nhiệm chính, ưu tiên và hợp tác. Cả hai đều cho phép nhiều tác vụ được xác định trong hệ thống, điểm khác biệt là cách chuyển đổi tác vụ hoạt động. Tất nhiên với một bộ xử lý lõi đơn, chỉ có một tác vụ thực sự đang chạy tại một thời điểm.

Cả hai loại HĐH đa nhiệm đều yêu cầu một ngăn xếp riêng cho từng tác vụ. Vì vậy, điều này ngụ ý hai điều: thứ nhất, bộ xử lý cho phép các ngăn xếp được đặt ở bất cứ đâu trong RAM và do đó có hướng dẫn để di chuyển con trỏ ngăn xếp (SP) xung quanh - tức là không có ngăn xếp phần cứng có mục đích đặc biệt như ở cấp thấp PIC. Điều này để lại loạt PIC10, 12 và 16.

Bạn có thể viết một hệ điều hành gần như hoàn toàn bằng C, nhưng trình chuyển đổi tác vụ, nơi SP được di chuyển xung quanh phải được lắp ráp. Tại nhiều thời điểm, tôi đã viết trình chuyển đổi tác vụ cho PIC24, PIC32, 8051 và 80x86. Tất cả đều khác nhau tùy thuộc vào kiến ​​trúc của bộ xử lý.

Yêu cầu thứ hai là có đủ RAM để cung cấp cho nhiều ngăn xếp. Thông thường người ta muốn có ít nhất vài trăm byte cho một ngăn xếp; nhưng ngay cả ở mức chỉ 128 byte cho mỗi tác vụ, tám ngăn xếp sẽ yêu cầu 1K byte RAM - bạn không phải phân bổ cùng ngăn xếp kích thước cho mỗi tác vụ. Hãy nhớ rằng bạn cần đủ ngăn xếp để xử lý tác vụ hiện tại và bất kỳ cuộc gọi nào đến các chương trình con lồng nhau của nó, nhưng cũng có không gian ngăn xếp cho một cuộc gọi bị gián đoạn vì bạn không bao giờ biết khi nào sẽ xảy ra.

Có các phương pháp khá đơn giản để xác định số lượng stack bạn đang sử dụng cho mỗi tác vụ; ví dụ: bạn có thể khởi tạo tất cả các ngăn xếp thành một giá trị cụ thể, giả sử 0x55 và chạy hệ thống một lúc rồi dừng và kiểm tra bộ nhớ.

Bạn không nói bạn muốn sử dụng loại PIC nào. Hầu hết các PIC24 và PIC32 sẽ có nhiều chỗ để chạy HĐH đa nhiệm; PIC18 (PIC 8 bit duy nhất có ngăn xếp RAM) có kích thước RAM tối đa 4K. Thật là iffy xinh đẹp.

Với đa nhiệm hợp tác (đơn giản hơn cả hai), chuyển đổi tác vụ chỉ được thực hiện khi tác vụ "từ bỏ" quyền điều khiển của nó trở lại HĐH. Điều này xảy ra bất cứ khi nào tác vụ cần gọi một thói quen của hệ điều hành để thực hiện một số chức năng mà nó sẽ chờ, chẳng hạn như yêu cầu I / O hoặc cuộc gọi hẹn giờ. Điều này giúp HĐH dễ dàng chuyển đổi ngăn xếp hơn, vì không cần thiết phải lưu tất cả các thanh ghi và thông tin trạng thái, SP chỉ có thể được chuyển sang một tác vụ khác (nếu không có tác vụ nào khác sẵn sàng để chạy, một ngăn xếp nhàn rỗi là kiểm soát nhất định). Nếu tác vụ hiện tại không cần thực hiện cuộc gọi HĐH nhưng đã chạy được một thời gian, nó cần từ bỏ quyền kiểm soát một cách tự nguyện để giữ cho hệ thống phản hồi.

Vấn đề với đa nhiệm hợp tác là nếu tác vụ không bao giờ từ bỏ quyền kiểm soát, nó có thể hog hệ thống. Chỉ có nó và bất kỳ thói quen ngắt nào xảy ra để được kiểm soát có thể chạy, do đó, hệ điều hành dường như sẽ bị khóa. Đây là khía cạnh "hợp tác" của các hệ thống này. Nếu bộ định thời watchdog được triển khai chỉ được đặt lại khi thực hiện chuyển đổi tác vụ, thì có thể bắt các tác vụ sai lầm này.

Windows 3.1 trở về trước là các hệ thống hợp tác, đó là một phần lý do tại sao hiệu năng của chúng không được tốt lắm.

Đa nhiệm ưu tiên là khó thực hiện hơn. Ở đây, các tác vụ không bắt buộc phải từ bỏ điều khiển bằng tay, nhưng thay vào đó, mỗi tác vụ có thể được cung cấp một lượng thời gian tối đa để chạy (giả sử 10 ms), và sau đó một chuyển đổi tác vụ được thực hiện cho tác vụ có thể chạy tiếp theo nếu có. Điều này đòi hỏi phải tự ý dừng một tác vụ, lưu tất cả thông tin trạng thái và sau đó chuyển SP sang tác vụ khác và bắt đầu nó. Điều này làm cho trình chuyển đổi tác vụ phức tạp hơn, yêu cầu nhiều ngăn xếp hơn và làm chậm hệ thống xuống một chút.

Đối với cả đa nhiệm hợp tác và ưu tiên, các ngắt có thể xảy ra bất cứ lúc nào sẽ tạm thời làm mất tác vụ đang chạy.

Như supercat chỉ ra trong một nhận xét, một ưu điểm của đa nhiệm hợp tác là việc chia sẻ tài nguyên dễ dàng hơn (ví dụ như phần cứng như ADC đa kênh hoặc phần mềm như sửa đổi danh sách được liên kết). Đôi khi hai tác vụ muốn truy cập vào cùng một tài nguyên cùng một lúc. Với lập lịch ưu tiên, hệ điều hành có thể chuyển đổi các tác vụ ở giữa một tác vụ bằng cách sử dụng tài nguyên. Vì vậy, khóa là cần thiết để ngăn chặn một nhiệm vụ khác đến và truy cập vào cùng một tài nguyên. Với đa nhiệm hợp tác, điều này không cần thiết bởi vì tác vụ sẽ kiểm soát khi nó sẽ tự giải phóng nó trở lại HĐH.


3
Một lợi thế của đa nhiệm hợp tác là trong hầu hết các trường hợp không cần thiết phải sử dụng khóa để phối hợp truy cập vào tài nguyên. Sẽ đủ để đảm bảo rằng các tác vụ luôn để tài nguyên ở trạng thái có thể chia sẻ bất cứ khi nào chúng từ bỏ quyền kiểm soát. Đa nhiệm ưu tiên sẽ phức tạp hơn nhiều nếu một tác vụ có thể bị tắt trong khi nó giữ một khóa trên một tài nguyên cần thiết cho một tác vụ khác. Trong một số trường hợp, nhiệm vụ thứ hai có thể sẽ bị chặn lâu hơn so với hệ thống hợp tác, vì nhiệm vụ giữ khóa sẽ được dành cho hệ thống ...
supercat

1
... toàn bộ tài nguyên để hoàn thành hành động mà (trên hệ thống phủ đầu) sẽ yêu cầu khóa, do đó làm cho đối tượng được bảo vệ có sẵn cho nhiệm vụ thứ hai.
supercat

1
Mặc dù đa nhiệm hợp tác đòi hỏi kỷ luật, việc đảm bảo rằng các yêu cầu về thời gian sẽ được đáp ứng đôi khi có thể dễ dàng hơn theo đa nhiệm hợp tác hơn là theo yêu cầu ưu tiên. Vì rất ít ổ khóa sẽ cần phải được giữ trên một công tắc nhiệm vụ, nên một hệ thống chuyển đổi nhiệm vụ vòng tròn năm nhiệm vụ trong đó các nhiệm vụ được yêu cầu không đi quá 10ms mà không cho năng suất, kết hợp với một logic nhỏ có nội dung "Nếu nhiệm vụ X khẩn cấp cần phải chạy, chạy tiếp theo ", sẽ đảm bảo rằng tác vụ X không bao giờ phải chờ quá 10ms một khi nó báo hiệu trước khi bắt đầu chạy. Ngược lại, nếu một tác vụ yêu cầu khóa thì nhiệm vụ X ...
supercat

1
... sẽ cần nhưng bị tắt bởi một bộ chuyển đổi trước khi phát hành nó, X có thể không làm gì hữu ích cho đến khi bộ lập lịch CPU bắt đầu chạy tác vụ đầu tiên. Trừ khi bộ lập lịch bao gồm logic để nhận biết và xử lý đảo ngược ưu tiên, có thể mất một lúc trước khi nó bắt đầu để cho tác vụ đầu tiên hoàn thành công việc của mình và giải phóng khóa. Những vấn đề như vậy không phải là không thể giải quyết được, nhưng việc giải quyết chúng đòi hỏi rất nhiều sự phức tạp có thể tránh được trong một hệ thống hợp tác. Các hệ thống hợp tác hoạt động tuyệt vời ngoại trừ một gotcha: ...
supercat

3
bạn không cần nhiều ngăn xếp trong hợp tác nếu bạn viết mã liên tục. Về bản chất, mã của bạn được chia thành các hàm void foo(void* context), logic điều khiển (kernel) kéo một con trỏ và cặp con trỏ hàm của hàng đợi và gọi nó một lần. Hàm đó sử dụng bối cảnh để lưu trữ các biến của nó và như vậy và sau đó có thể thêm gửi tiếp tục vào hàng đợi. Các chức năng đó phải quay trở lại nhanh chóng để cho các tác vụ khác vào khoảnh khắc của chúng trong CPU. Đây là một phương pháp dựa trên sự kiện chỉ yêu cầu một ngăn xếp duy nhất.
ratchet freak

16

Threading được cung cấp bởi một hệ điều hành. Trong thế giới nhúng, chúng ta thường không có HĐH ("kim loại trần"). Vì vậy, điều này để lại các tùy chọn sau:

  • Các vòng bỏ phiếu chính cổ điển. Hàm chính của bạn có một thời gian (1) thực hiện nhiệm vụ 1 sau đó thực hiện nhiệm vụ 2 ...
  • Vòng lặp chính + cờ ISR: Bạn có ISR thực hiện chức năng quan trọng về thời gian và sau đó cảnh báo vòng lặp chính thông qua một biến cờ mà tác vụ cần dịch vụ. Có lẽ ISR đặt một ký tự mới vào bộ đệm tròn và sau đó báo cho vòng lặp chính xử lý dữ liệu khi nó sẵn sàng để làm như vậy.
  • Tất cả ISR: Phần lớn logic ở đây được thực thi từ ISR. Trên một bộ điều khiển hiện đại như ARM có nhiều mức ưu tiên. Điều này có thể cung cấp một lược đồ "giống như luồng" mạnh mẽ, nhưng cũng có thể gây nhầm lẫn để gỡ lỗi vì vậy nó chỉ được dành riêng cho các ràng buộc thời gian quan trọng.
  • RTOS: Một hạt nhân RTOS (được hỗ trợ bởi ISR ​​hẹn giờ) có thể cho phép chuyển đổi giữa nhiều luồng thực thi. Bạn đã đề cập đến FreeRTOS.

Tôi sẽ khuyên bạn sử dụng đơn giản nhất trong các chương trình trên sẽ hoạt động cho ứng dụng của bạn. Từ những gì bạn mô tả, tôi sẽ có vòng lặp chính tạo ra các gói và đặt chúng vào bộ đệm tròn. Sau đó, có trình điều khiển dựa trên UART ISR kích hoạt bất cứ khi nào byte trước đó được gửi xong cho đến khi bộ đệm được gửi, sau đó chờ thêm nội dung bộ đệm. Cách tiếp cận tương tự cho ethernet.


3
Đây là một câu trả lời rất hữu ích vì nó giải quyết được gốc rễ của vấn đề (làm thế nào để đa nhiệm trên một hệ thống nhúng nhỏ, thay vì các luồng như một giải pháp). Một đoạn về cách nó có thể áp dụng cho câu hỏi ban đầu sẽ rất tuyệt vời, có lẽ bao gồm cả ưu và nhược điểm của từng câu hỏi cho kịch bản.
David

8

Như trong bất kỳ bộ xử lý lõi đơn nào thực hiện đa nhiệm phần mềm thực sự là không thể. Vì vậy, bạn phải cẩn thận để chuyển đổi giữa nhiều nhiệm vụ một cách. Các RTOS khác nhau đang chăm sóc điều đó. Họ có một bộ lập lịch và dựa trên đánh dấu hệ thống, họ sẽ chuyển đổi giữa các tác vụ khác nhau để cung cấp cho bạn khả năng đa nhiệm.

Các khái niệm liên quan đến việc làm như vậy (lưu và khôi phục ngữ cảnh) khá phức tạp, do đó, việc thực hiện thủ công này có thể sẽ khó khăn và làm cho mã của bạn phức tạp hơn và vì bạn chưa bao giờ làm điều đó trước đây, sẽ có lỗi trong đó. Lời khuyên của tôi ở đây là sử dụng RTOS được thử nghiệm giống như FreeRTOS.

Bạn đã đề cập rằng các ngắt cung cấp một mức độ đa nhiệm. Đây là loại đúng. Ngắt sẽ làm gián đoạn chương trình hiện tại của bạn tại bất kỳ điểm nào và thực thi mã ở đó, nó có thể so sánh với hệ thống hai nhiệm vụ trong đó bạn có 1 nhiệm vụ với mức độ ưu tiên thấp và một nhiệm vụ khác có mức độ ưu tiên cao hoàn thành trong một lát thời gian của bộ lập lịch.

Vì vậy, bạn có thể viết một trình xử lý ngắt cho bộ định thời định kỳ sẽ gửi một vài gói qua UART, sau đó để phần còn lại của chương trình của bạn thực thi trong vài mili giây và gửi vài byte tiếp theo. Bằng cách đó, bạn sắp xếp được một khả năng đa nhiệm hạn chế. Nhưng bạn cũng sẽ có một ngắt khá dài có thể là một điều xấu.

Cách thực sự duy nhất để thực hiện nhiều nhiệm vụ cùng một lúc trên MCU lõi đơn là sử dụng DMA và các thiết bị ngoại vi khi chúng hoạt động độc lập với lõi (DMA và MCU chia sẻ cùng một bus, vì vậy chúng hoạt động chậm hơn một chút khi cả hai đều hoạt động). Vì vậy, trong khi DMA đang xáo trộn các byte đến UART, lõi của bạn có thể tự do gửi nội dung đến ethernet.


2
cảm ơn, DMA nghe có vẻ thú vị Tôi chắc chắn sẽ tìm kiếm nó.!
Máy bay

Không phải tất cả các dòng PIC đều có DMA.
Matt Young

1
Tôi đang sử dụng PIC32;)
Máy bay

6

Các câu trả lời khác đã mô tả các tùy chọn được sử dụng nhiều nhất (vòng lặp chính, ISR, RTOS). Đây là một lựa chọn khác như một sự thỏa hiệp: Protothreads . Về cơ bản, nó là một lib rất nhẹ cho các luồng, sử dụng vòng lặp chính và một số macro C, để "mô phỏng" một RTOS. Tất nhiên nó không có hệ điều hành đầy đủ, nhưng đối với các luồng "đơn giản" thì nó có thể hữu ích.


Tôi có thể tải mã nguồn của nó từ đâu cho windows? Tôi nghĩ rằng nó chỉ có sẵn cho linux.!
Máy bay

@CZAbhinav Nó phải độc lập với hệ điều hành và bạn có thể tải xuống bản mới nhất tại đây .
erebos

Tôi đang ở trong windows ngay bây giờ và sử dụng MplabX, tôi không nghĩ nó hữu ích ở đây. Dù sao cũng cảm ơn.!
Máy bay

Chưa từng nghe về protothreads, nghe có vẻ là một kỹ thuật thú vị.
Arsenal

@CZAbhinav Bạn đang nói về cái gì? Đó là mã C và không liên quan gì đến hệ điều hành của bạn.
Matt Young

3

Thiết kế cơ bản của tôi cho một RTOS cắt lát thời gian tối thiểu đã không thay đổi nhiều so với một số gia đình vi mô. Về cơ bản, nó là một bộ đếm thời gian ngắt điều khiển một máy trạng thái. Thường trình dịch vụ ngắt là nhân hệ điều hành trong khi câu lệnh chuyển đổi trong vòng lặp chính là các tác vụ người dùng. Trình điều khiển thiết bị là các thói quen dịch vụ ngắt cho các ngắt I / O.

Cấu trúc cơ bản như sau:

unsigned char tick;

void interrupt HANDLER(void) {
    device_driver_A();
    device_driver_B();
    if(T0IF)
    {
        TMR0 = TICK_1MS;
        T0IF = 0;   // reset timer interrupt
        tick ++;
    }
}

void main(void)
{
    init();

    while (1) {
        // periodic tasks:
        if (tick % 10 == 0) { // roughly every 10 ms
            task_A();
            task_B();    
        }
        if (tick % 55 == 0) { // roughly every 55 ms
            task_C();
            task_D();    
        }

        // tasks that need to run every loop:
        task_E();
        task_F();
    }
}

Đây về cơ bản là một hệ thống đa nhiệm hợp tác. Các tác vụ được viết để không bao giờ đi vào một vòng lặp vô hạn nhưng chúng tôi không quan tâm vì các tác vụ chạy trong một vòng lặp sự kiện nên vòng lặp vô hạn là ẩn. Đây là một phong cách lập trình tương tự như các ngôn ngữ hướng sự kiện / không chặn như javascript hoặc go.

Bạn có thể thấy một ví dụ về phong cách kiến ​​trúc này trong phần mềm máy phát RC của tôi (vâng, tôi thực sự sử dụng nó để lái máy bay RC vì vậy nó rất an toàn để ngăn tôi đâm máy bay và có khả năng giết người): https://github.com / slebetman / pic-txmod . Về cơ bản, nó có 3 tác vụ - 2 tác vụ thời gian thực được triển khai dưới dạng trình điều khiển thiết bị trạng thái (xem công cụ ppmio) và 1 tác vụ nền thực hiện logic trộn. Về cơ bản, nó tương tự như máy chủ web của bạn ở chỗ nó có 2 luồng I / O.


1
Tôi thực sự sẽ không gọi đó là 'đa nhiệm hợp tác', vì điều đó thực sự không khác biệt nhiều so với bất kỳ chương trình vi điều khiển nào khác phải làm nhiều việc.
tên gì là

2

Mặc dù tôi đánh giá cao câu hỏi đặc biệt hỏi về việc sử dụng RTOS nhúng, nhưng đối với tôi, câu hỏi rộng hơn được đặt ra là "làm thế nào để đạt được đa nhiệm trên nền tảng nhúng".

Tôi thực sự khuyên bạn nên quên sử dụng RTOS nhúng ít nhất là trong thời điểm hiện tại. Tôi khuyên điều này bởi vì tôi nghĩ rằng trước tiên cần tìm hiểu về cách đạt được nhiệm vụ 'đồng thời' bằng các kỹ thuật lập trình cực kỳ đơn giản bao gồm các trình lập lịch tác vụ đơn giản và các máy trạng thái.

Để giải thích ngắn gọn về khái niệm này, mỗi mô-đun công việc cần được thực hiện (tức là mỗi 'nhiệm vụ') có một chức năng cụ thể phải được gọi ('đánh dấu') định kỳ để mô-đun đó thực hiện một số công việc. Các mô-đun giữ lại trạng thái hiện tại của riêng mình. Sau đó, bạn có một vòng lặp vô hạn chính (bộ lập lịch) gọi các hàm mô-đun.

Minh họa thô:

for(;;)
{
    main_lcd_ui_tick();
    networking_tick();
}


...

// In your LCD UI module:
void main_lcd_ui_tick(void)
{
    check_for_key_presses();
    update_lcd();
}

...

// In your networking module:
void networking_tick(void)
{
    //'Tick' the TCP/IP library. In this example, I'm periodically
    //calling the main function for Keil's TCP/IP library.
    main_TcpNet();
}

Cấu trúc lập trình đơn luồng như thế này, theo đó bạn định kỳ gọi các chức năng của máy trạng thái chính từ một vòng lập lịch chính có mặt khắp nơi trong lập trình nhúng và đây là lý do tại sao tôi khuyến khích OP làm quen và thoải mái với nó trước khi sử dụng nó trước khi sử dụng Nhiệm vụ / chủ đề RTOS.

Tôi làm việc trên một loại thiết bị nhúng có giao diện LCD phần cứng, máy chủ web nội bộ, ứng dụng email, ứng dụng khách DDNS, VOIP và nhiều tính năng khác. Mặc dù chúng tôi sử dụng RTOS (Keil RTX), số lượng luồng (tác vụ) riêng lẻ được sử dụng là rất nhỏ và hầu hết 'đa nhiệm' đều đạt được như mô tả ở trên.

Để đưa ra một vài ví dụ về các thư viện thể hiện khái niệm này:

  1. Thư viện mạng Keil. Toàn bộ ngăn xếp TCP / IP có thể được chạy một luồng; bạn định kỳ gọi main_TcpNet (), lặp lại ngăn xếp TCP / IP và bất kỳ tùy chọn kết nối mạng nào khác mà bạn đã biên dịch từ thư viện (ví dụ: máy chủ web). Xem http://www.keil.com/support/man/docs/rlarm/rlarm_main_tcpnet.htmlm . Phải thừa nhận rằng, trong một số tình huống (có thể nằm ngoài phạm vi của câu trả lời này), bạn đạt đến điểm bắt đầu trở nên có lợi hoặc cần thiết để sử dụng các luồng (đặc biệt nếu sử dụng chặn các ổ cắm BSD). (Lưu ý thêm: V5 MDK-ARM mới thực sự sinh ra một luồng Ethernet chuyên dụng - nhưng tôi chỉ đang cố gắng cung cấp một minh họa.)

  2. Thư viện Linphone VOIP. Thư viện linphone chính nó là đơn luồng. Bạn gọi iterate()hàm ở một khoảng đủ. Xem http://www.linphone.org/docs/liblinphone-javadoc/org/linphone/core/LinphoneCore.html#iterate () . (Một ví dụ tồi tệ vì tôi đã sử dụng điều này trên nền tảng nhúng Linux và các thư viện phụ thuộc của linphone chắc chắn sinh ra các luồng, nhưng một lần nữa nó lại để minh họa một điểm.)

Quay trở lại vấn đề cụ thể được OP nêu ra, vấn đề dường như là việc giao tiếp UART phải diễn ra cùng lúc với một số mạng (truyền gói tin qua TCP / IP). Tôi không biết thư viện mạng nào bạn thực sự sử dụng, nhưng tôi cho rằng nó có chức năng chính cần được gọi thường xuyên. Bạn sẽ cần phải viết mã liên quan đến việc truyền / nhận dữ liệu UART để được cấu trúc theo cách tương tự, như một máy trạng thái có thể được lặp lại bằng các cuộc gọi định kỳ đến một chức năng chính.


2
Cảm ơn lời giải thích tốt đẹp này, tôi đang sử dụng thư viện TCP / IP được cung cấp bởi microchip và nó là một mã phức tạp rất lớn. Tôi bằng cách nào đó đã xoay sở để chia nó thành nhiều phần và làm cho nó có thể sử dụng được theo yêu cầu của tôi. Tôi chắc chắn sẽ thử một trong những cách tiếp cận của bạn.!
Máy bay

Hãy vui vẻ :) Sử dụng RTOS chắc chắn giúp cuộc sống dễ dàng hơn trong nhiều tình huống. Theo quan điểm của tôi, sử dụng một luồng (tác vụ) làm cho nỗ lực lập trình dễ dàng hơn rất nhiều theo một nghĩa, vì bạn có thể tránh phải chia nhỏ nhiệm vụ của mình thành một máy trạng thái. Thay vào đó, bạn chỉ cần viết mã tác vụ giống như trong các chương trình C # của mình, với mã tác vụ được tạo như thể đó là thứ duy nhất tồn tại. Điều cần thiết là khám phá cả hai cách tiếp cận và khi bạn thực hiện nhiều chương trình nhúng hơn, bạn bắt đầu cảm thấy cách tiếp cận nào là tốt nhất trong mỗi tình huống.
Trevor Trang

Tôi cũng thích sử dụng tùy chọn luồng. :)
Máy bay
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.