我的第一篇博客--論arduino通信問題的解決

本人, 男, 四川省成都市四川大學在讀本科生一枚,專業是微電子科學與工程。平時不好打遊戲,不愛做社團活動,唯獨對機械的工作和程序的運轉有一種原始般的發自肉體和精神上的激情。迷戀《鋼鐵俠》,也愛好各類科幻小說。由於編程經驗尚淺,知識貯備較爲匱乏,所以不敢以程序員這種神聖的稱號自居,只能算一個業餘的編程愛好者,加入CSDN,目的是爲了向各路大神學習,請教,以後還請大家多多包涵。

我爲什麼要加入CSDN?

去年九月,在學校接手了一個項目,目標是造一臺魔方機器人拿去參賽,當時懷着滿滿的激情,覺得定能給學校和教授交一份完美的答卷。可到了實際操作中卻舉步維艱,編程知識的匱乏和對樹莓派等單片機操作的不熟悉都成爲我前進過程中的巨大障礙,好在寒假時,我回到家中,有了一個超級幫手 —— 有20多年編程經驗的工程師 —— 我父親。在我調試程序的時候,我父親總在我身旁,教我怎樣使用函數,並及時糾正我的錯誤。他給了我巨大的幫助,很多程序段甚至完全由他上手,我在一旁看着,領悟理解其中的精髓。回學校的最後一天晚上,他給我看了他的有道雲筆記,整整幾十個大文件夾的技術資料擺在我眼前,他把其中很多他覺得能對我有幫助的資料都發給了我。我十分感激他,沒有他我就無法完成這個項目。寒假還未結束,我就回到學校,必須趕在3月10號之前做好這個機器人,但苦於知識貧乏,我只好重看我父親給我的技術資料。這些技術資料裏,有很多是直接從CSDN博客上取得的網頁簡報。我懷着好奇心,在一個晚上,進入了CSDN這個神奇的世界。五湖四海,各路大神的文章一下子就吸引住了我,各類資料,琳琅滿目的程序世界令我目不暇接,每每看到一個好的經驗與解決方案,我便如獲至寶,欣喜萬分,每每看到振聾發聵之點,好似醍醐灌頂,大夢方覺,前輩們的這些經驗和方案,好似一盞盞長明燈,指引我們這些後來者,探尋編程的崑崙神宮。在不斷的學習過程中,愈加對通往程序員大神之路心馳神往,此地似有絕世武林祕籍,可令我大展拳腳,得道成俠。懷着極大的興奮之情,我決定從此加入CSDN這個大家庭,今後在編程過程中遇到什麼問題,我將貢獻出我自己的經驗,爲後來的編程學習者門再多點亮一盞長明燈,也算是對這個大家庭做出了貢獻。


arduino通信問題的學習與解決

既然是第一篇博客,我決定還是上點乾貨,我來寫寫我前幾天遇到的一個‘小問題’,着實困擾了我很久。

我想實現的是,我用電腦在串口監視器上輸入一個字符串,arduino能識別這個字符串中的每一個字符並在相應的串口上給出相應的高低電平以驅動舵機,比如輸入L1,RS,功能是左手腕舵機逆時針旋轉90°,然後右手指舵機鬆開魔方,鑑於arduino的Serial.read()函數一次只能從串口上讀取一個字節,所以要想輸入字符串,得先寫讀入字符串程序。

網上這種程序有,複製粘貼一段:

String comdata = "";

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

void loop()
{
    while (Serial.available() > 0)  
    {
        comdata += char(Serial.read());
        delay(2);
    }
    if (comdata.length() > 0)
    {
        Serial.println(comdata);
        comdata = "";
    }
}

此代碼作用就是用Serial.read()以此讀入數據,然後存在comdata字符串內,之後要調用只需要comdata[x](x爲你指定的整型數字)即可,但是我加進我的程序之後,發現問題並不這麼簡單,怎麼調都出問題,在無能爲力的情況下,只能重新寫程序,一點一點研究走。

我自己重寫了一個程序,用於研究。


首先,我認爲問題出在串口上面,arduino的串口一次通過一個值,如果不通過電腦給arduino輸出的話,它應該會通過一個默認值。寫入程序,發現這個默認值爲-1


那麼我們就需要一個判斷語句,把這些沒用的值過濾掉。

if(myinput > 0)即可。

這裏注意,Serial.read()語句調用一次讀一個字符,調用第二次就讀下一個字符,所以我們需要一個臨時的變量存儲Serial.read()讀到的值,問題是,該用什麼類型定義這個變量呢?

int myinput;

然後 myinput = Serial.read(); 

爲啥?

這裏重要的事情說三遍:

Serial.read()從電腦端讀入的值強制轉換成整型輸出!

Serial.read()從電腦端讀入的值強制轉換成整型輸出!

Serial.read()從電腦端讀入的值強制轉換成整型輸出!

但是,你從電腦端輸入的是字符型;

你從電腦端輸入的是字符型;

你從電腦端輸入的是字符型;

也就是說,你要輸入1,myinput就是1字符的ASC2碼,就是49,輸入2,myinput就是整型50,輸入S,返回的就是83!

所以,要把myinput減一個‘0’,讓他變成整形數字,這樣的話,1爲1,2爲2,S就是35。明白了這個,之後的操作纔可行。



輸入123JS,成功!不過串口默認值變成-4。

當然你也可以用char來處理,不過默認值就變成了不知道什麼的字符,看着很難受。




解決的這個問題後,來解決下一個問題,如果我在電腦上輸入兩個字符LS,存進兩個myinput裏,但是機器怎麼識別是不是有默認值混進來呢,因爲電腦不傳命令,就傳默認值,所以到頭來,我的myinput可能是-1L,或是S-1,這就不好了。

沒有關係,加入這段代碼即可

//判斷輸入指令
  if(myinput1 > 0)
  {
    order1 = myinput1 - '0';
    order2 = myinput2 - '0';
  }
  else
  {
    order1 = myinput2 - '0';
    order2 = myinput3 - '0';
   }

意思是,從串口裏讀入三個信號,然後從中依次判別各個信號是否有效(是否大於0),最後輸出有效字符,存入order內,從而剔除了默認值-1。

串口的問題已解決,之後的問題都迎刃而解,程序一下次就實驗成功了。

下面給出arduino源碼

//arduino環境

#include <string.h>


int servopinL1=9;//定義數字接口9 連接左手旋轉伺服舵機信號線
int servopinL2=10;//定義數字接口10 連接左手夾持伺服舵機信號線
int servopinR1=8;//定義數字接口9 連接右手旋轉伺服舵機信號線
int servopinR2=7;//定義數字接口10 連接右手夾持伺服舵機信號線


int myinput1;
int myinput2;
int myinput3;


int order1;
int order2;


int myangle;//定義角度變量


int pulsewidth;//定義脈寬變量
int val;


String comdata = "";


void servopulse(int servopin,int myangle)//定義一個脈衝函數


{


pulsewidth=(myangle*11)+500;//將角度轉化爲500-2480 的脈寬值


digitalWrite(servopin,HIGH);//將舵機接口電平至高


delayMicroseconds(pulsewidth);//延時脈寬值的微秒數


digitalWrite(servopin,LOW);//將舵機接口電平至低


delay(20-pulsewidth/1000);


}




void setup()


{
  Serial.begin(9600);//連接到串行端口,波特率爲9600
  Serial.println("servo1 ready" ) ;
  Serial.println("servo2 ready" ) ;
  
  pinMode(servopinL1,OUTPUT);//設定舵機接口爲輸出接口
  pinMode(servopinL2,OUTPUT);//設定舵機接口爲輸出接口
  pinMode(servopinR1,OUTPUT);//設定舵機接口爲輸出接口
  pinMode(servopinR2,OUTPUT);//設定舵機接口爲輸出接口




}


void loop()
{
  myinput1 = Serial.read();
  myinput2 = Serial.read();
  myinput3 = Serial.read();


  Serial.println(myinput1);
  Serial.println(myinput2);
  Serial.println(myinput3);
  delay(1000);
  
  //判斷輸入指令
  if(myinput1 > 0)
    if(myinput2 > '0')
    {
       order1 = myinput1 - '0';
       order2 = myinput2 - '0';
       
    }
  else
  {
    order1 = myinput2 - '0';
    order2 = myinput3 - '0';
  }


  
  if(order1 > 0 && order2 > 0)
  {
  Serial.println(order1);
  Serial.println(order2);




 if(order1 == 28)
 {
  switch (order2)
  {
    case 1:
    
      val = 0;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("anticlockwise ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinL1,val);//引用脈衝函數
      }
     break;
     
    
    case 2:
    
      val = 1;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("no move ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinL1,val);//引用脈衝函數
      }
    break;
    
    
    case 3:
    
      val = 2;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("clockwise ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinL1,val);//引用脈衝函數
      }
     break;
     


    case 26:       //字符串'J'的ASC二碼轉化爲整形後 - '0'
    
      val = 4;
      val=val*(180/9);//將數字轉化爲角度
      Serial.print("close ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinL2,val);//引用脈衝函數
      }
     break;
     


    case 35:       //字符串'S'的ASC二碼轉化爲整形後 - '0'
    
      val = 2;
      val=val*(180/9);//將數字轉化爲角度
      Serial.print("open ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinL2,val);//引用脈衝函數
      }
     break;      
  }


  Serial.println("Good job!");
  myinput1 = 0;
  myinput2 = 0;
  myinput3 = 0;
  order1 = 0;
  order2 = 0;
  }


  else if(order1 == 34)
  {
      switch (order2)
  {
    case 1:
    
      val = 0;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("anticlockwise ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinR1,val);//引用脈衝函數
      }
     break;
     
    
    case 2:
    
      val = 1;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("no move ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinR1,val);//引用脈衝函數
      }
    break;
    
    
    case 3:
    
      val = 2;
      val=val*(180/2);//將數字轉化爲角度
      Serial.print("clockwise ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinR1,val);//引用脈衝函數
      }
     break;
     


    case 26:       //字符串'J'的ASC二碼轉化爲整形後 - '0'
    
      val = 5;
      val=val*(180/9);//將數字轉化爲角度
      Serial.print("close ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinR2,val);//引用脈衝函數
      }
     break;
     


    case 35:       //字符串'S'的ASC二碼轉化爲整形後 - '0'
    
      val = 0;
      val=val*(180/9);//將數字轉化爲角度
      Serial.print("open ");
      Serial.print(val,DEC);
      Serial.println();
      for(int i=0;i<=50;i++) //給予舵機足夠的時間讓它轉到指定角度
      {
        servopulse(servopinR2,val);//引用脈衝函數
      }
     break;      
  }


  Serial.println("Good job!");
  myinput1 = 0;
  myinput2 = 0;
  myinput3 = 0;
  order1 = 0;
  order2 = 0;
  }
  }
  

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章