簡體   English   中英

如何通過串行發送浮動

[英]How to send float over serial

在 Arduino 上通過串行發送floatdoubleint16的最佳方法是什么?

Serial.print()僅發送ASCII編碼的值。 但我想將值作為字節發送。 Serial.write()接受字節和字節Serial.write() ,但將值轉換為字節的最佳方法是什么?

我試圖將int16轉換為byte* ,但沒有運氣。 我也使用了 memcpy,但它使用了許多 CPU 周期。 Arduino 使用普通的 C/C++。 這是一個ATmega328微控制器。

嗯。 這個怎么樣:

void send_float (float arg)
{
  // get access to the float as a byte-array:
  byte * data = (byte *) &arg; 

  // write the data to the serial
  Serial.write (data, sizeof (arg));
}

是的,要發送這些數字,您必須先將它們轉換為ASCII字符串。 如果您正在使用 C,則sprintf()是 IMO 進行此轉換的最簡便方法:

[后來補充:啊啊啊! 我忘了對於ints / longs ,函數的輸入參數想要無符號。 同樣對於傳遞給sprintf()的格式字符串。 所以我在下面改變了它。 很抱歉我的疏忽,這本來是一個很難找到的錯誤。 此外, ulong使它更通用一些。]

char *
int2str( unsigned long num ) {
    static char retnum[21];       // Enough for 20 digits plus NUL from a 64-bit uint.
    sprintf( retnum, "%ul", num );
    return retnum;
}

浮動和雙打也類似。 進行轉換的代碼是預先知道的。 必須告訴它 - 它正在轉換什么樣的實體,所以你最終可能會得到函數char *float2str( float float_num)char *dbl2str( double dblnum)

您將在轉換中得到一個以 NUL 結尾的左調整(沒有前導空格或零)字符串。

您可以在任何地方/以您喜歡的方式進行轉換; 這些功能只是說明。

使用Firmata協議。 引用:

Firmata 是一種通用協議,用於通過主機上的軟件與微控制器進行通信。 它旨在與任何主機計算機軟件包一起使用。 現在有多種語言的匹配對象。 很容易為其他軟件添加對象以使用此協議。 基本上,這個固件建立了一個協議,用於從主機軟件與 Arduino 對話。 目的是讓人們可以通過主機上的軟件完全控制 Arduino。

您需要查找的行話是“序列化”。

這是一個關於串行連接的有趣問題,它可能對哪些字符可以端到端地進行限制,並且也可能無法每個字符傳遞 8 位。

對某些字符代碼的限制相當普遍。 這是袖口上的一些:

  • 如果使用軟件流控制,則通常控制字符 DC1 和 DC3(Ctrl-Q 和 Ctrl-S,有時也稱為 XON 和 XOFF)不能作為數據傳輸,因為它們被發送以啟動和停止另一端的發送器電纜的末端。

  • 在某些設備上,NUL 和/或 DEL 字符(0x00 和 0x7F)可能會從接收器的 FIFO 中消失。

  • 如果接收器是 Unix tty,並且 termio 模式設置不正確,則字符 Ctrl-D(EOT 或 0x04)會導致 tty 驅動程序向打開 tty 的進程發出文件結束信號。

串行連接通常可配置字節寬度和可能包含的奇偶校驗位。 某些連接需要使用帶奇偶校驗的 7 位字節,而不是 8 位字節。 甚至可以連接到(非常舊的)傳統硬件來為 5 位和 6 位字節配置許多串行端口。 如果每字節少於 8 位可用,則需要更復雜的協議來處理二進制數據。

ASCII85是處理 7 位數據和控制字符限制的流行技術。 這是僅使用 85 個精心挑選的 ASCII 字符代碼重寫二進制數據的慣例。

此外,您當然必須擔心發送方和接收方之間的字節順序。 您可能還需要擔心浮點格式,因為並非每個系統都使用 IEEE-754 浮點。

最重要的是,通常選擇純 ASCII 協議是更好的答案。 它的優點是可以被人類理解,並且更能抵抗串行連接的問題。 除非您正在發送大量浮點數據,否則表示的低效率可能會被實現的簡易性所抵消。

只是對你接受的東西保持自由,對你發出的東西保持保守。

這很簡單。 使用Serial.println()函數

void setup() {
  Serial.begin(9600);

}

void loop() {
  float x = 23.45585888;
  Serial.println(x, 10);
  delay(1000);
}

這是輸出:

在此處輸入圖片說明

也許這是將 Float 轉換為 Byte 並將 Byte 轉換為 Float 的最佳方式,-Hamid Reza。

int breakDown(int index, unsigned char outbox[], float member)
{
  unsigned long d = *(unsigned long *)&member;

  outbox[index] = d & 0x00FF;
  index++;

  outbox[index] = (d & 0xFF00) >> 8;
  index++;

  outbox[index] = (d & 0xFF0000) >> 16;
  index++;

  outbox[index] = (d & 0xFF000000) >> 24;
  index++;
  return index;
}


float buildUp(int index, unsigned char outbox[])
{
  unsigned long d;

  d =  (outbox[index+3] << 24) | (outbox[index+2] << 16)
    | (outbox[index+1] << 8) | (outbox[index]);
  float member = *(float *)&d;
  return member;
}

問候。 `

大小重要嗎? 如果是這樣,您可以使用 ASCII85 將每個 32 位組編碼為 5 個 ASCII 字符,請參閱http://en.wikipedia.org/wiki/Ascii85

結構和工會解決了這個問題。 使用具有與結構匹配的字節大小聯合的打包結構。 將指向結構和聯合的指針重疊(或在結構中添加聯合)。 使用 Serial.write 發送流。 在接收端有一個匹配的結構/聯合。 只要字節順序匹配沒有問題,否則您可以使用“C” hto(s..l) 函數解包。 添加“標題”信息以解碼不同的結構/聯合。

對於 Arduino IDE:

float buildUp(int index, unsigned char outbox[])
{
  unsigned long d;
 d = (long(outbox[index +3]) << 24)  |   \
     (long(outbox[index +2]) << 16) |   \
     (long(outbox[index +1]) << 8)  |   \
     (long(outbox[index]));
 float member = *(float *)&d;
 return member;
}

否則不工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM