humhumhum 发表于 2014-6-7 12:20:16

有关于串口通信自定通信协议之资料分隔....一点点心得

本帖最后由 humhumhum 于 2014-6-7 12:25 编辑

小弟前些日子在研究串口通信的通信协定,由于敝人是个新手对于指令还不是很熟,在一些时日的研究下有了点心得与大家分享。

我在做个项目里面有多重的功能可供蓝牙切换或是选择,于是小弟需要一串通信命令来告诉Arduino功能的开与关或是数值的變化。我找寻资料中无意发现Arduino Cookbook这本书,他对Arduino里面指令的部份说的很详细。之前我只知道Serial.read(),Serial.print,Serial.begin的基础指令,但看过了这本书之后发现还有其他额外的功能是存在但是不常用到的但是存在关键性的功能的指令,还有String的部份也写的很好尤其是资料互转的部份写的和其他网上的有点不太一样。我是初学者对我来说可是很新鲜的。

首先就贴上我的编程跟大家分享 第一次贴 请见谅:

=========vvvvvvvv开始了vvvvvvvvv==========

String content = ""; //定义Serial接收字串
char character;   //定义Serial接收字元
int commaPosition;//定义逗点位置
int commaNumber=0;//先占定逗点数量为0初始化
int endcontent=0;   //定义逗点之后的内容

String contentArray="";//预设字串阵列为10个
String contentArrayU;//字串占存
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {

do
{
while(Serial.available()) //发现有串口输入
{character = Serial.read();

   if(character=='Z')//之前我加了一个控制符Z为结束选项现在可用可不用
   {Serial.println("aa"+content);
   int cc=content.toInt();//测试Steing转换Int
   int ca=cc-100;
   Serial.println(ca);}

   else
    {
      if(character ==',')//若是发现逗点就将逗点数量自加1
      {commaNumber++;}
      content.concat(character);//将Char类型加入String字串内
      Serial.println(content);}//检查内容
}
}
while(character=='Z');//这个我也不知道在打什么应该等于Z就干麻去...在这里除非有Z不然没用

Serial.println(content); //等Serial全部截取完毕后列印出内容
delay(2000);             //延迟一下好区分出程序前后
Serial.print("CommaNumber is = ");Serial.println(commaNumber); //确认一下标点数量是否正确


if (commaNumber>0)//如果发现有标点 表示有资料进来就执行下列语句
{
         for(int commaMarkq = 0;commaMarkq < 10 ; commaMarkq++) //之前预设最多10组资料当然你可以设定更多
            {          if(commaMarkq<commaNumber+1)//我测试的时后是小于10组,当然您可以可判定如果大于10要怎么样
                         {
                         commaPosition = content.indexOf(',');//这就厉害了 目前字串第一个豆点的位置
                         if(commaPosition != -1) // 如果commaPosition没有逗点会等于 -1
                         {
                         contentArrayU = content.substring(0,commaPosition);//从字串的0位置到逗点的位置之间的字符先指拆下来给contentArrayU缓存,如果您有信心当然也可以直接指定给字串组
                         Serial.print("I am contentLegth= "); Serial.println(content.length());//列印出接收字串长度
                         content=content.substring(commaPosition+1,content.length());//将接收字串从第一个逗点之后到字串尾全部拆下来准备第二次拆分
                         delay(5);//我也不知道为什么,就等一下让它吸收一下消化会比较好,也可以拿掉试试看。
                         contentArray=contentArrayU;//将拆分下来的占存指定给字串组
                         Serial.print("I am contentArray ");Serial.print(commaMarkq);Serial.print(" = ");Serial.println( contentArray);//印出结果
                         Serial.print("I am commaNumber= ");Serial.println(commaPosition);//确认逗点拆分位置
                         }
                         else
                         {
                        contentArray=content;endcontent=1;//如果没有逗点了就将最后一串内容指定给目前的字串组,并将endcontent指定为1告诉机器可以进行后面的语句
                                                                        //您也可以将最后的阵列位置标定例如 EndArray=commaMarkq; 当然EndArray要注意域的使用
                         }
                         }
                         else
                        {contentArray="";} //如果后面没资料全部将字串阵列清空


   }
    commaNumber=0;//将逗点数量归零等待下次接收
    content="";   //清空接收字串等待下次接收
   }

if (endcontent=1) //如果字串编结结束后
{
for(int test=0;test<10;test++)
{
Serial.print("String Array ");Serial.print(test);Serial.print(" is = ");Serial.println( contentArray);// 将阵列内容全数印出
}

Serial.print("ContentArray 1 = ");Serial.println(contentArray.toInt()-100);//这边我做了个小测试故意将第二组讯息改成数字利用toInt()的方式做运算并列印出结果
endcontent=0;//跟Arduino我编辑完了若完事可以将阵列全部清空不清也行
}
}

=====^^^^^^到此为止^^^^^========

代码里面有注解,其中最令我讶异的是Srting的转换,一般网上都是利用乘法的方式将字串转成INT。而书里写的是利用toInt的方式直接转过去,挺好挺快的。
此外还有其他用法例如.contact( )将INT转换成字串或是连接字串。atoi (ASCII to int) 或是atol (ASCII to long)

最后String还有chatAt(n),compareTo(String2),indexOf(S)...族繁不及备载,小弟觉得挺好的所以分享给大家。
这是我第一次发帖子请多多包涵,谢谢。如前辈有更好的建议也请多多指教谢谢!!感激~~

humhumhum 发表于 2014-6-7 12:33:23

以下是我定义的通信协定,提供给各位批评谢谢

HC命令传递起始标记/发送机器所要变更的命令。
HS 状态传递起始标记/要求机器发送相对应参数状态的数值
HI 为初始化命令/要求相机传递所有讯息来初始化同步状态。
HB 操作命令/键盘上下左右、移动选项。

再依照字母小写来定义EPPROM位置。

abcdEFGhiJklmnopqrstuvwxyz
1234567891011121314151617181920212223242526
上列字母代表EEPROM的位置


释例一
更改LED1则EEPROM地址为 11,所以Serial传输为 HC,k,11,Z
HC为起使标记
j 为LED操作代码
11为操作控制数字。
Z为结束标记
判别数据数量方法为 三个”, ”的数量 “ , ”数量-1/2=1组
若HC,n,14,l,45,h,34,Z ”, ”的数量为7个,所以7-1/2=3组
以Comma数量来判定。

释例二
更改LED2则EEPROM地址为 13,所以Serial传输为 HC,m,26,Z
HC为起使标记
m 为LED2操作代码
13为操作控制数字。
Z为结束标记


pumpitup 发表于 2014-6-7 12:48:11

留个爪吧,感觉就是字符处理啊

Super169 发表于 2014-6-7 22:00:52

回應一下你對 String 的見解:

代码里面有注解,其中最令我讶异的是Srting的转换,一般网上都是利用乘法的方式将字串转成INT。而书里写的是利用toInt的方式直接转过去,挺好挺快的。
此外还有其他用法例如.contact( )将INT转换成字串或是连接字串。atoi (ASCII to int) 或是atol (ASCII to long)

一般單片機要做的東西不會太複雜, 資源也很珍貴, 而 String 之類的 class 比較耗資源.
所以你會看到網上的教學, 一般都不會使用 String 類, 並非作者不知道有 String 類, 而是大家考慮到資源及速度的因素, 直接用簡單的方式去做.

在 serial communization 中, 資料是一個個 byte 傳過來, 轉換成數值只需減去 '0' 再不斷 * 10 相加就可以.
如果用到 toInt, 先要把資料合成 String, 再把 String 轉回 integer, 當中對資源及速度上均沒好處, 所以大多會採用 一個個加乘的方法.

當然, 如果只需要把程式做出來, String class 可以提供很大幫助.
但如果習慣了之後, 將來就很難改過來, 簡單的轉換也可能會依賴 String class 去完成.
不是說 String 不好, 但可以的話, 還是先想想是否有其他更好(速度及資源方面作考慮)的方法可以取代, 最後才選用 String.
比方說接收 串口資料時, 如果長度是已知有限的話, 就算送來的是一個 string, 用 array 加 index 把資料填上去, 就比用 String class 把 一個個 byte 用 .concat 連上去好得多了.

humhumhum 发表于 2014-6-8 20:29:45

感谢~~真是一语惊醒梦中人,因未小弟需要混合的编码又初学所以想到这方法,不过用 array 加 index 的方式该怎么使用?? array我会之前有试过,不过不知道该怎么将全部的array拼在一起变成一个String!!!

谢谢!!

maxims 发表于 2014-6-8 21:27:47

:o好东西啊。谢谢分享

小小东熙 发表于 2014-7-17 16:03:08

请问楼主。你用过arduino和变频器通信吗。给变频器发命令数据。我该怎样写我的代码语句????

humhumhum 发表于 2014-11-2 14:15:46

对不起~~木有~~
页: [1]
查看完整版本: 有关于串口通信自定通信协议之资料分隔....一点点心得