Làm thế nào để tính toán tốc độ nối tiếp và yêu cầu bộ đệm cho PC để truyền thông vi điều khiển?


8

Một kịch bản phổ biến là có một PC gửi lệnh đến vi điều khiển thông qua RS232. Chương trình PC của tôi đang gửi các lệnh (mỗi lệnh được tạo thành từ nhiều byte) nhanh nhất có thể đến một robot nhỏ. Bộ vi điều khiển trên robot là Parallax Propellor.

Tôi đã nhận thấy rằng nếu tôi không xử lý byte đủ nhanh ở phía vi điều khiển, thì nó có thể nhanh chóng tràn bộ đệm mặc định trong trình điều khiển cổng nối tiếp phổ biến có sẵn cho Propellor. (Bộ đệm thường ở bất kỳ đâu từ 16 đến 256 byte). Tôi có thể tùy ý tăng các bộ đệm này hoặc tạo bộ đệm tròn lớn hơn của riêng mình, nhưng tôi muốn có một cách tiếp cận có phương pháp hơn để xác định các yêu cầu kích thước phù hợp và / hoặc lượng thời gian tối thiểu tôi có thể đợi trước khi rút byte ra khỏi bộ đệm trình điều khiển cổng nối tiếp .

Trong nháy mắt thứ nhất:

  • 115200 == 115,2 bit mỗi mili giây == ~ 12,8 byte mỗi mili giây (giả sử 1 bit stop)

1) Đó có phải là cách hợp lệ để tính thời gian cho truyền nối tiếp không?

Ngoài ra, đưa ra thiết lập cụ thể của tôi:

  • Chương trình PC <-> Trình điều khiển cấu hình nối tiếp Bluetooth <-> Bộ thu phát Bluetooth <- * -> Modem không dây BlueSMIRF <-> Chương trình truyền phát Parallax

2) Lượng dữ liệu tối đa tôi có thể gửi trong một khoảng thời gian nhất định mà không gặp sự cố?

Có thể tôi quá phức tạp mọi thứ, nhưng có vẻ như có nhiều bộ đệm liên quan đến chuỗi truyền tải ở trên. Làm thế nào để những người khác thường đối phó với điều này? Họ có điều tiết PC gửi đến một tỷ lệ an toàn đã biết không? Thực hiện kiểm soát dòng chảy? Nếu thực hiện kiểm soát luồng, điều đó ảnh hưởng đến băng thông và thời gian đáp ứng như thế nào?

(Nếu có vấn đề, thử nghiệm của tôi là sử dụng cần điều khiển trên PC để điều khiển nhiều động cơ phản ứng tức thì với chuyển động của cần điều khiển. Vì vậy, mỗi chuyển động nhỏ của cần điều khiển đều dẫn đến nhiều lệnh được gửi đến vi điều khiển. Các lệnh không đơn giản Mặc dù các lệnh vị trí, chúng cũng liên quan đến việc tăng / giảm tốc độ của các servo theo thời gian và đây là lý do mà vi điều khiển dành một lượng đáng kể chu kỳ xung nhịp trước khi xử lý các byte mới.)

Câu trả lời:


2

Tôi nghĩ rằng hình thức của câu hỏi của bạn là sai. Vấn đề không phải là bạn đã tính toán không chính xác bao nhiêu dữ liệu mỗi giây có thể được ném vào vi điều khiển; đó là bạn không có cách nào để vi điều khiển chỉ ra sự sẵn sàng của nó để nhận lệnh tiếp theo.

Nói cách khác, nếu bạn cố gắng giải quyết vấn đề này bằng cách tính toán chính xác tốc độ gửi dữ liệu, chắc chắn bạn sẽ thực hiện một trong những điều sau đây:

  1. gửi ít dữ liệu hơn vi điều khiển có thể xử lý
  2. gửi nhiều dữ liệu hơn so với vi điều khiển có thể xử lý (và trong trường hợp xấu nhất, nó sẽ chỉ rất nhẹ hơn để bộ đệm mất một giờ để tràn ngập và dẫn bạn gỡ lỗi một cái gì đó hoàn toàn không liên quan)

Giải pháp là để vi điều khiển của bạn cung cấp phản hồi - điều khiển luồng. Trong ví dụ cơ bản nhất, chỉ cần gửi lại một ký tự đại diện cho việc hoàn thành lệnh (đề xuất SpaceWire của @ Rocketmagnet sẽ mạnh mẽ nhất, nhưng cũng nặng tay).

Nhiều khả năng, bạn có thể đủ khả năng để có một vài lệnh trong bộ đệm. Vì vậy, phép tính bạn nên làm là chia kích thước bộ đệm của bạn cho kích thước của lệnh lớn nhất bạn sẽ gửi, sau đó trừ đi 1 (hoặc nhiều hơn) để đảm bảo an toàn. Điều đó sẽ cho bạn biết sự khác biệt lớn nhất cho phép giữa các lệnh được gửi và xác nhận đã nhận và sẽ cho phép bạn làm việc ở tốc độ tối đa bằng cách giữ cho bộ đệm được lấp đầy.

Thí dụ

Giả sử rằng lệnh dài nhất có thể của bạn là 7 byte ("fw 4.32") hoặc một số như vậy và bạn có bộ đệm 64 byte. Điều đó có nghĩa là bạn có thể điều chỉnh 9 lệnh trong bộ đệm ( ), nhưng để an toàn, bạn sẽ trừ đi một và chỉ cho phép 8 lệnh. Đây là một số psudeocode python:7×9= =63<64

MAX_UNACKED = 8  # constant, how many un-acked commands to send
unacked = 0      # number of un-acked commands that have been sent
while (true):
    # can send up to MAX_UNACKED commands as we like
    if MAX_UNACKED > unacked:
        send_command()
        unacked = unacked + 1

    # assume that the ack is a single character, we don't care which
    acks = receive_response()      # receive a string of characters
    unacked = unacked - len(acks)  # number of characters = number of acks

Lưu ý rằng mã psuedocode này là một ví dụ về chặn quay vòng và có nhiều cách tốt hơn để chờ nhập liệu ... nhưng cách nào cụ thể sẽ phụ thuộc vào cách mã PC của bạn hoạt động.


Cảm ơn, đây là một câu trả lời tuyệt vời. Tuy nhiên, sự chậm trễ của việc chờ đợi một tin nhắn kiểu "ack" là khá đáng kể. Tôi đã hy vọng tránh nó, nhưng có lẽ đơn giản là không thể tránh khỏi độ tin cậy 100%. Tôi đồng ý giao thức Spacewire được đề xuất bởi Rocketmagnet trông rất mạnh mẽ, nhưng có lẽ quá nhiều cho những gì tôi cần.
kaliatech

Chà, hãy nhớ rằng bạn không cần đợi mỗi lệnh được ack'd. Bạn có thể gửi nhiều lệnh như bạn có không gian bộ đệm, và sau đó bắt đầu gửi một tin nhắn cho mỗi ack nhận được. Điều đó sẽ loại bỏ bất kỳ sự chậm trễ nào (bằng cách giữ cho hàng đợi lệnh của vi điều khiển đầy đủ) nhưng ngăn bạn vượt qua bộ đệm - vấn đề ban đầu.
Ian

4

Tôi muốn đề xuất hai cách tiếp cận có thể.

  1. Sử dụng 'nhịp tim' để chuyển gói trạng thái nổi tiếng với tần suất cố định phù hợp với 'ngân sách tốc độ' của bạn. Trong trường hợp này, bạn không bao giờ gửi tin nhắn ad hoc trực tiếp từ PC hoặc MCU, tất cả những gì bạn có thể làm là cập nhật gói trạng thái sẽ được gửi vào thời gian đã lên lịch.

  2. Đặt một giới hạn cứng cho 'ngân sách truyền tải' của bạn và thực thi nó. Ví dụ: bạn chỉ có thể gửi một gói cứ sau 100 ms và nếu gói thứ 2 được gửi trước khi hết 100 ms, việc truyền của nó bị trì hoãn cho đến khi hết thời gian 100 ms (ví dụ: lượng tử). Điều này đòi hỏi bạn phải thêm tin nhắn vào hàng đợi và sau đó gửi từ hàng đợi theo tỷ lệ cố định. Tương tự như cách tiếp cận nhịp tim ở # 1 nhưng hiệu quả hơn một chút vì dữ liệu không được gửi khi nó không thay đổi. Nhược điểm của thiết kế này là nếu bạn quá mức, bạn xây dựng độ trễ cao hơn và cao hơn vào thông tin liên lạc của bạn và nếu bạn có truyền thông bùng nổ thay đổi, độ trễ truyền thông có thể thay đổi lớn.

Tôi có xu hướng làm việc với # 1 để gửi dữ liệu từ MCU vì thuật toán rất đơn giản và nhỏ.


3

Không có câu trả lời đúng cho vấn đề này và tôi chắc chắn bạn đã biết (hoặc có thể đoán) tất cả những gì bạn cần để giải quyết vấn đề này. Tuy nhiên

Điều rõ ràng đầu tiên phải nói là các thiết bị hạ nguồn phải có khả năng xử lý luồng dữ liệu, cả về lâu dài và ngắn hạn. Trong ngắn hạn, các thiết bị sử dụng bộ đệm để đối phó với dòng chảy. Về lâu dài, khả năng xử lý cần thiết để hành động trên dữ liệu.

Một vấn đề bạn gặp phải là bạn không kiểm soát tất cả các bước trong chuỗi của mình, vì vậy nếu một trong số chúng gây ra sự chậm trễ, có thể bạn sẽ không thể làm gì nhiều về việc thay thế nó. Dù sao, tôi đã nghĩ rằng trình điều khiển nối tiếp Bluetooth sẽ có một bộ đệm lớn đẹp và sẽ chơi tốt với bộ thu phát và BlueSMIRF, vì vậy có lẽ an toàn khi bỏ qua chúng. Tôi đoán vấn đề thực sự là giữa Cánh quạt và PC.

Điều dường như đang xảy ra trong trường hợp của bạn là sự tương tác giữa nhà sản xuất dữ liệu và người tiêu dùng đang tạo ra độ dài hàng đợi không thể đoán trước và bạn muốn áp dụng một số lý thuyết phù hợp cho điều đó.

Thật thú vị, các nghiên cứu đã được thực hiện về chính xác vấn đề này liên quan đến việc xếp hàng tại các nhà hàng, Nghiên cứu điển hình của EG về Mô hình xếp hàng nhà hàngCân bằng trong hàng đợi theo Thời gian dịch vụ không xác định và Giá trị dịch vụ . Nhưng có nhiều tài nguyên trực tuyến dễ hiểu hơn, như Lý thuyết xếp hàng lý thuyết xếp hàng cho người giả . Nhưng cái bạn thực sự muốn có lẽ là Làm thế nào để kích thước hàng đợi tin nhắn .

Bạn có một vài lựa chọn:

  • Chỉ cần đảm bảo rằng PC gửi dữ liệu với tốc độ có trật tự. Quyết định chính xác mức giá bạn thực sự cần, và đừng vượt lên trên mức đó.
  • Sử dụng Hệ điều hành thời gian thực trên MCU để đảm bảo rằng các byte đang được xử lý kịp thời.
  • Thực hiện kiểm soát dòng chảy.

Nhưng đây là giải pháp ưa thích của tôi. Tàu vũ trụ ! Hoặc ít nhất là sử dụng hệ thống kiểm soát dòng chảy từ nó.

Về cơ bản, thiết bị xuôi dòng gửi byte đến thiết bị ngược dòng cho biết số lượng vị trí trống trong FIFO của nó. Bằng cách này, nhà sản xuất dữ liệu chỉ gửi những gì người tiêu dùng có thể đối phó.

Nếu bạn quan tâm, bạn có thể đọc tiêu chuẩn Spacewire đầy đủ: IEEE 1355 .


2

Trong nháy mắt thứ nhất:

115200 == 115,2 bit mỗi mili giây == ~ 12,8 byte mỗi mili giây (giả sử 1 bit stop)

Đó có phải là một cách hợp lệ để tính thời gian cho việc truyền nối tiếp?

Rất đơn giản, điều này cũng ổn - nhưng đừng quên bất kỳ bit bắt đầu và chẵn lẻ nào, và đừng quên bất kỳ giao thức nào trên các liên kết bluetooth

Ngoài ra, đưa ra thiết lập cụ thể của tôi:

Chương trình PC <-> Trình điều khiển cấu hình nối tiếp Bluetooth <-> Bộ thu phát Bluetooth <- * -> Modem không dây BlueSMIRF <-> Chương trình truyền phát Parallax

Tôi nghĩ thật hợp lý khi giả định rằng PC thông qua Modem có khả năng xử lý lưu lượng ở mức 115200 bps, vì vậy bạn có thể loại bỏ chúng khỏi phương trình.

Tuy nhiên, việc có nhiều bước nhảy như thế này sẽ ngăn việc sử dụng tín hiệu điều khiển luồng, mà không đưa ra thông điệp phản hồi ... điều này sẽ làm chậm thời gian phản hồi.

Bây giờ, hãy xem trường hợp xấu nhất, không có phí giao thức, 115200 bps có nghĩa là Parallax của bạn sẽ nhận được một byte mỗi 69us - thêm vào lúc bắt đầu, dừng hoặc bit chẵn lẻ sẽ làm chậm tốc độ này xuống một chút, nhưng giả sử trường hợp xấu nhất sẽ khiến bạn chậm trễ .

Điều này có nghĩa là bộ điều khiển của bạn phải xử lý việc nhận một byte mỗi 69us, cũng như thực hiện các công việc bình thường của nó (tính toán, v.v.).

Nhưng trong thực tế, bạn sẽ gửi một chuỗi tin nhắn gồm (n) byte, cần được đệm và xử lý dưới dạng chuỗi - trong khi vẫn thực hiện các công việc bình thường. Bản thân việc tính toán bộ đệm là một nghệ thuật, nhưng tôi thường sẽ làm việc (tối thiểu) gấp đôi kích thước của chuỗi dài nhất (nếu bạn có không gian RAM). Bất cứ điều gì ít có khả năng mất tin nhắn, nếu một trong những không được xử lý trước khi nhận được bắt đầu tiếp theo.

Nếu bạn bị giới hạn chỉ độ dài của tin nhắn dài nhất, bạn cần chắc chắn 100% rằng bạn có thể xử lý tin nhắn đó giữa việc nhận byte cuối cùng và nhận byte đầu tiên của tin nhắn tiếp theo. (Rõ ràng là ít vấn đề hơn với các tin nhắn nhỏ hơn).


0

Thay vì tính toán yêu cầu tốc độ (có thể thay đổi theo thời gian / comp sang comp và bất cứ khi nào bạn thay đổi mã), có một số điều khác bạn có thể làm:

  • Có đầu vào C yêu cầu của bạn bằng cách gửi các ngắt đến thiết bị chính (trong trường hợp này là PC - bạn có thể không cần sử dụng các ngắt, chỉ cần giữ một cổng dành riêng). Bạn có thể có bộ đệm thiết bị chính các đầu ra (dễ dàng hơn để làm điều đó với máy tính - bộ đệm không giới hạn hiệu quả) hoặc bạn chỉ có thể loại bỏ chúng trừ khi cần thiết.

  • Với kịch bản của bạn, tốt hơn hết là loại bỏ hoàn toàn bộ đệm. Chấp nhận các đầu vào tới viaC thông qua chân ngắt. Có một số biến cờ về cơ bản nói "cần đầu vào" trên μC. Nếu cờ này được đặt, μC sẽ chấp nhận đầu vào. Nếu không, nó sẽ chỉ loại bỏ nó. Bằng cách này, tất cả các đầu vào được tiêu thụ nhanh chóng (giữ cho bộ đệm miễn phí), nhưng không phải tất cả được sử dụng. Để có hiệu quả, hãy điều chỉnh thời gian theo tốc độ gần đúng của toàn bộ thiết lập. Thay vì loại bỏ nó, bạn có thể muốn mã hóa loại điều bộ đệm của riêng bạn - có một mảng nhỏ trong đó một vài đầu vào được lưu trữ. Bây giờ, bạn đã thoát khỏi tất cả các bộ đệm ngược dòng và có một bộ đệm "nhân tạo" duy nhất trên μC - qua đó bạn có toàn quyền kiểm soát.

  • Có thể tốt hơn để giữ tất cả các tính toán trên máy tính và sử dụng μC như một bộ điều khiển nô lệ đơn giản - cung cấp cho nó các lệnh chuyển động / vị trí đơn giản có thể được dẫn trực tiếp đến các động cơ. Nếu bạn có đủ các chân ngắt / ngắt MUXing, bạn có thể muốn gửi các lệnh này thông qua các ngắt để đáp ứng nhanh hơn.

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.