我的第一篇博客--论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通信问题的解决_第1张图片

首先,我认为问题出在串口上面,arduino的串口一次通过一个值,如果不通过电脑给arduino输出的话,它应该会通过一个默认值。写入程序,发现这个默认值为-1

我的第一篇博客--论arduino通信问题的解决_第2张图片

那么我们就需要一个判断语句,把这些没用的值过滤掉。

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。明白了这个,之后的操作才可行。

我的第一篇博客--论arduino通信问题的解决_第3张图片

我的第一篇博客--论arduino通信问题的解决_第4张图片

输入123JS,成功!不过串口默认值变成-4。

当然你也可以用char来处理,不过默认值就变成了不知道什么的字符,看着很难受。

我的第一篇博客--论arduino通信问题的解决_第5张图片


我的第一篇博客--论arduino通信问题的解决_第6张图片

解决的这个问题后,来解决下一个问题,如果我在电脑上输入两个字符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


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;
  }
  }
  

}



你可能感兴趣的:(我的第一篇博客--论arduino通信问题的解决)