极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 14428|回复: 5

串口接收问题请指教

[复制链接]
发表于 2015-1-13 18:55:31 | 显示全部楼层 |阅读模式
apMac=00:15:6D:04:BB:2E

wlanOpmode=sta

wlanConnections=1

wlanUptime=996

essid=WJ4G

freq=2482

signal=-58

noise=-93

ccq=940

uptime=334028

loadavg=0

memTotal=29524

memFree=11584

memBuffers=1800

ackTimeout=25

distance=600

lanIpAddress=0.0.0.0

wlanIpAddress=0.0.0.0

wlanTxRate=58.5

wlanRxRate=58.5

wlanTxLatency=1

wlanPolling=1

wlanPollingQuality=85

wlanPollingCapacity=39

lanRxBytes=71908224

lanRxPackets=548976

lanRxErrors=0

lanTxBytes=447911534

lanTxPackets=899527

lanTxErrors=0

lanPlugged=1

lanSpeed=100Mbps-Full

wlanRxBytes=3950840

wlanRxPackets=6281

wlanRxErrors=0

wlanTxBytes=1964354

wlanTxPackets=10427

wlanTxErrors=1

wlanRxErrNwid=0

wlanRxErrCrypt=0

wlanRxErrFrag=0

wlanRxErrRetries=0

wlanRxErrBmiss=0

wlanRxErrOther=0

latitude=0.000000

longitude=0.000000

cfgCrc=d356978d

XM.v5.5.6#
上面就是每隔一定周期从通信模块接收的数据,而且每次都要全部接收,因为是通信模块打包发过来的,但我只用到signal=-xx这一项。
今天我问道您串口缓存一次能存多少字节的问题,因为我发现对于每次发过来的这么多数据使用不同的程序,得到的结果不同。
#include <Servo.h>
Servo myservo1;
Servo myservo2;
int pos1 = 90;
int pos2 = 90;
String comdata = "";
String comdata1 = "";
int rssi=0,lastrssi=0;
int mark = 0;
void setup()
{
  Serial.begin(9600);
  comdata.reserve(188);  // reserve 188 bytes
  myservo1.attach(10);
  myservo2.attach(11);
  myservo1.write(pos1);
  myservo2.write(pos2);
}

void loop()
{
  //int j = 0;
  while (Serial.available() > 0)
  {
    comdata += char(Serial.read());
    delay(8);
    mark = 1;
  }
  if(mark == 0) return; // no data
  if(mark == 1)
  {
    lastrssi=rssi;
    int sIndex = comdata.indexOf("signal=-");
    if(sIndex==-1)
    {
      mark = 0;
      return;
    }
    String charRssi=comdata.substring(sIndex+8,sIndex+10);
    rssi=charRssi.toInt();
    Serial.println(rssi);
    Serial.println(lastrssi);
    comdata = String("");
    Serial.flush();
    mark = 0;
  }
  if(lastrssi!=0)
  {
    if(rssi>lastrssi)Serial.println("you");
    if(rssi<lastrssi)Serial.println("zuo");
  }
}
这是我今天的程序,利用OpenJumper&#8482; Serial Assistant 1.3.6进行接收测试时没有任何显示,是不是通信痛快发来的数据太多,字符串放不下,所以没成功?但是我利用昨天的程序
String comdata = "";
int mark = 0;
void setup()
{
  Serial.begin(9600);
  while (!Serial);
}


void loop()
{
  int j = 0;
  while (Serial.available() > 0)
  {
    comdata += char(Serial.read());
    delay(2);
    mark = 1;
  }
  if(mark == 1)
  {
    int sIndex = comdata.indexOf("signal=-");
    if(sIndex==-1){
      return;
    }
    String rssi=comdata.substring(sIndex+8,sIndex+10);
    Serial.println(rssi.toInt());
  }
  comdata = String("");
  mark = 0;Serial.flush();
}
用这个程序就接收成功了,接收到了58,前辈,您知道这是为什么么?十分感谢!
回复

使用道具 举报

发表于 2015-1-13 22:48:51 | 显示全部楼层
不知道程序哪里出了问题,可以通过分段调试的方式,找出问题的原因。
回复 支持 反对

使用道具 举报

发表于 2015-1-14 00:31:28 | 显示全部楼层
本帖最后由 Super169 于 2015-1-14 00:36 编辑

這麼大的數據包, 時間上要控制得準確, 不容易.
arduino 的串口庫, 預設只有 64 個 byte 的 buffer, 如果不能及時處理, 很快要滿了.
你這裡的數據, 有數百個 byte, 一次過傳送出來, 必須及時處理, 太困難了.
如果你的程序不太大, 考慮把 serial 的 buffer 改成 1KB 吧, 讓它有足夠空間存放, 然後盡快處理好, 準備下一次傳送.

又或是每次接收完一個 byte 不做 delay, 在預知未完結時直接等待下一個 byte.
把 delay(2); 改為 while (!Serial.available()); 去等待下一個 byte, 然後直接處理.
當然, 這樣做要有明確的完成碼, 或其他完結的訊號.  否則可以永遠只會不停地讀取數據.
但就可以省去 buffer 既消耗, 對大的數據包比較可行.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-14 14:10:30 | 显示全部楼层
Super169 发表于 2015-1-14 00:31
這麼大的數據包, 時間上要控制得準確, 不容易.
arduino 的串口庫, 預設只有 64 個 byte 的 buffer, 如果不 ...

嗯嗯,测试发现arduino一次是可以接收到那么多信息的,但必须是delay(2),如果改为delay(4)或delay(8)就都不行了,不知道是为什么
回复 支持 反对

使用道具 举报

发表于 2015-1-14 14:44:57 | 显示全部楼层
毒师老白 发表于 2015-1-14 14:10
嗯嗯,测试发现arduino一次是可以接收到那么多信息的,但必须是delay(2),如果改为delay(4)或delay(8)就都 ...


這就是時間上的問題.
你用的是 9600 bps, 發放一個 Byte, 在沒有 overhead 情況下, 大約是 8/9600 約 1 ms.
在接收了一個 byte 後加入 delay, 就是想把連續送來的資料一次過接收, 等待時間略比所需時間長一點就最好.  避免因為下一個 byte 未送到, 而出現 Serial.available() 為 false.

細看一次你的程式, 原來已用了  "signal=-" 作完成碼判斷, 資料可以分段接收, 而非要一次性接收.  基本上 buffer 的問題可解決, 只是每次接收的長度可以會不同.

但另一個問題是 "signal=-" 並非資料的最尾, 當已接收了 "signal=-" 的一句後, 除非處理速度接近發送時間, 否則資料會被分斷, 未完全接收好就會嘗試放出來.  不過, 你又用了最少 2ms 的 delay, 會變成分段接收的機會不大.

至於 delay(4) 及 delay(8), 有可能是處理速度太慢了, 每讀取一個 byte 就要等一段長時間, 幾乎是發送三個才處理一個.  同一個 while loop 內已可以令 buffer 滿了.

由於你已用了 完成碼的判斷 (只是選擇的不太好), 反正不需要一次過完全讀取, 當中的 delay 意義就不大了, 太長反而令接收太慢而出問題.

而 delay(2) 也存在處理太慢的隱憂, 我也不太肯定, 為何你可以沒事.  試想想, 每 1ms 發一個 byte, 你每接一個就等 2ms.  你將用了 200 ms 等待時間 去接收 100 個 byte, 但 200ms 的時間, 對方已可以發送出 200 個 byte 了, 當中 100 個 byte 要放進 buffer, 我也不明白為何你可以沒問題, 難道是發送的時間也有 1ms 的 overhead?

建議改為 delay(1) (本來可以甚至取消 delay, 但又怕會出現使用 string function 太頻密的問題, comdata.substring 有一定的 overhead, 所以 delay(1) 可能更理想), 而 完成碼改為 "XM.5.5.6#" (這看似是最後結束的資料吧).  可能會更有效率.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-1-15 08:35:08 | 显示全部楼层
Super169 发表于 2015-1-14 14:44
這就是時間上的問題.
你用的是 9600 bps, 發放一個 Byte, 在沒有 overhead 情況下, 大約是 8/9600 約  ...

真的是很详细,太感谢你了!
现在遇到了一个问题,我想通过RSSI的比较来控制舵机,比如说开始令舵机右转10度,接收一次signal=-xx,对当前时刻的与上一时刻的进行比较,如果大于则使舵机继续向右转10度,如果小于,则令舵机1转回到初始位置后再向左转10度,没运动一次,比较一次信号值,然后向信号大的方向转10度,因为通信通信模块的位置是在变化的,会引起signal的变化,我设计的舵机云台就是想去跟踪signal的极大值。
我看了下关于arduino的servo库,没有类似的控制程序,希望您能给点思路
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-10 09:44 , Processed in 0.036874 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表