极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 32753|回复: 14

关于arduino串口接收数据的处理问题。求大神帮助。

[复制链接]
发表于 2014-11-27 12:13:16 | 显示全部楼层 |阅读模式
我写了一个程序,想要在串口输入1或者2,然后arduino就可以做出相应的回应。
  1. int analogPin = 0;//定义模拟量读取口
  2. int LED = 13;//定义13为led灯接口
  3. void setup()
  4. {
  5.   Serial.begin(9600);//定义波特率
  6.   pinMode(LED,OUTPUT);
  7.   digitalWrite(LED,LOW);
  8. }
  9. void loop()
  10. {
  11.   char val;//定义变量val,用于暂存上位机发送来的字符
  12.   if (Serial.available() > 0) //如果上位机发送来了字符
  13.   {
  14.     val = Serial.read(); //读取上位机发来的字符,并保存到val
  15.     while (val == '1') //当上位机发送过来'1',执行第一个循环
  16.     {
  17.       int n = analogRead(analogPin);
  18.       int i = n / 1000;
  19.       int a = n % 1000;
  20.       int j = a / 100;
  21.       int b = a % 100;
  22.       int k = b / 10;
  23.       int c = b % 10;
  24.       Serial.print(i);
  25.       Serial.print(j);
  26.       Serial.print(k);
  27.       Serial.print(c);//把模拟量分段从串口输出,输出固定的四字节数据。
  28.       digitalWrite(LED, LOW); //关闭LED灯
  29.       delay(500);
  30.       digitalWrite(LED, HIGH);//点亮LED
  31.       delay(500);
  32.     }
  33.     while (val == '0') //如果上位机发送字符'0',执行第二个循环
  34.     {
  35.       digitalWrite(LED, LOW); //熄灭LED灯
  36.     }
  37.   }
  38. }
复制代码

但是存在一个问题,就是当串口输入“1”时,能够输出模拟量,灯也能够闪烁,单是它一直在执行第一个循环,无法跳出循环,即使串口输入了“0”,也不会执行第二个循环。
求大家帮忙修改一下,如何才能根据串口的数来执行不同的循环啊。
回复

使用道具 举报

发表于 2014-11-27 12:59:55 | 显示全部楼层
我今天不说话 发表于 2014-11-27 12:54
不过呢,还是不行,刚刚试了一下,串口一打开,灯立马就闪了,发送了“1”反而不闪了。

第10行:  is_blink = true; 初始化为闪烁,所以打开就闪。
改为 is_blink = false; 默认不闪。

第20行,给1加上单引号,‘1’,串口收的是字符,不是数值。
回复 支持 1 反对 0

使用道具 举报

发表于 2014-11-27 12:26:58 | 显示全部楼层
把while改为if
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-11-27 12:32:54 | 显示全部楼层
peanut 发表于 2014-11-27 12:26
把while改为if

改为if以后LED就不能闪烁,串口只输出一次数据。
回复 支持 反对

使用道具 举报

发表于 2014-11-27 12:35:01 | 显示全部楼层
改成这样试试:
  1. if (Serial.available() > 0) //如果上位机发送来了字符
  2.   {
  3.     val = Serial.read();


  4. if (val == 1){
  5. ...
  6. ...
  7. }

  8. if (val == 0){
  9. ...
  10. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2014-11-27 12:45:54 | 显示全部楼层
本帖最后由 peanut 于 2014-11-27 14:08 编辑
我今天不说话 发表于 2014-11-27 12:32
改为if以后LED就不能闪烁,串口只输出一次数据。



  1. int analogPin = 0;//定义模拟量读取口
  2. int LED = 13;//定义13为led灯接口
  3. bool is_blink;

  4. void setup()
  5. {
  6.   Serial.begin(9600);//定义波特率
  7.   pinMode(LED,OUTPUT);
  8.   digitalWrite(LED,LOW);
  9.   is_blink = false;
  10. }


  11. void loop()
  12. {
  13.   char val;//定义变量val,用于暂存上位机发送来的字符
  14.   if (Serial.available() > 0) //如果上位机发送来了字符
  15.   {
  16.     val = Serial.read(); //读取上位机发来的字符,并保存到val
  17.     if (val == '1')
  18.     {
  19.       is_blink = true;
  20.     }
  21.     else if (val == '0')
  22.     {
  23.       is_blink = false;
  24.     }
  25.   }

  26.   if (is_blink)
  27.   {
  28.     blink(); //闪烁
  29.   }
  30.   else
  31.   {
  32.     shutdown();//熄灭LED灯
  33.   }
  34. }


  35. void blink()
  36. {
  37.   int n = analogRead(analogPin);
  38.   int i = n / 1000;
  39.   int a = n % 1000;
  40.   int j = a / 100;
  41.   int b = a % 100;
  42.   int k = b / 10;
  43.   int c = b % 10;
  44.   Serial.print(i);
  45.   Serial.print(j);
  46.   Serial.print(k);
  47.   Serial.print(c);//把模拟量分段从串口输出,输出固定的四字节数据。
  48.   digitalWrite(LED, LOW); //关闭LED灯
  49.   delay(500);
  50.   digitalWrite(LED, HIGH);//点亮LED
  51.   delay(500);
  52. }


  53. void shutdown()
  54. {
  55.   digitalWrite(LED, LOW);
  56. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-11-27 12:49:00 | 显示全部楼层
peanut 发表于 2014-11-27 12:45

谢谢这位大神,对我帮助太大了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-11-27 12:54:47 | 显示全部楼层
我今天不说话 发表于 2014-11-27 12:49
谢谢这位大神,对我帮助太大了。

不过呢,还是不行,刚刚试了一下,串口一打开,灯立马就闪了,发送了“1”反而不闪了。
回复 支持 反对

使用道具 举报

发表于 2014-11-27 13:58:15 | 显示全部楼层
本帖最后由 Super169 于 2014-11-27 14:01 编辑

如果用電腦作 serial input, 每次讀取所需資料後, 除非你會同時處理多行指令, 否則, 最好加上一些 clean-up 的動作.  

  1. if (Serial.available()) {
  2.   val = Serial.read();
  3.   :
  4.   :
  5.   // clean-up serial buffer
  6.   delay(1);
  7.   while(Serial.available()) {
  8.     Serial.read();
  9.     delay(1);
  10.   }

  11. }
复制代码


即使改成 if, 預設不閃, 輸入 '1' 後也只會閃一下就停下來.
原因是電腦會多送 LRLF 給你, 而你的程式就會因為 else 部份而停止閃爍了.


回复 支持 反对

使用道具 举报

发表于 2014-11-27 14:03:41 | 显示全部楼层
注意, clean-up 中的 delay(1) 也很重要的.  
除非你可以肯定傳送速度足夠快, 否則, 不要為了節省千分一秒而省去.  
對於比較慢的波特率, 甚至要加上 delay(2) 或更多.
回复 支持 反对

使用道具 举报

发表于 2014-11-27 14:13:27 | 显示全部楼层
Super169 发表于 2014-11-27 14:03
注意, clean-up 中的 delay(1) 也很重要的.  
除非你可以肯定傳送速度足夠快, 否則, 不要為了節省千分一秒 ...

学习了。我并没有操作过串口。
回复 支持 反对

使用道具 举报

发表于 2014-11-27 23:39:58 | 显示全部楼层
发送的指令过于简单了,以至于经常被误以为是是到了什么指令。建议加一个简单的指令格式,这样很容易鉴别是否收到了正确的指令。
比如NMEA0183,它这么说话:
$GPRMC,.....,.....,................,*
我建议你也可以这样:
$1*
$0*
$XX,1,YY,*
...
回复 支持 反对

使用道具 举报

发表于 2019-3-20 20:28:47 | 显示全部楼层
Super169 发表于 2014-11-27 13:58
如果用電腦作 serial input, 每次讀取所需資料後, 除非你會同時處理多行指令, 否則, 最好加上一些 clean-up ...

怎么有两个delay(1); 那这个clean-up怎么接上上面的代码
回复 支持 反对

使用道具 举报

发表于 2019-3-25 09:26:01 | 显示全部楼层
JIMJIM 发表于 2019-3-20 20:28
怎么有两个delay(1); 那这个clean-up怎么接上上面的代码

delay(1) 是確保有足夠時間接收完整的一個 byte.
試想想, 如果是 9600bps, 一個 bit 就要 1/9600 秒, 8 個 bit 最少都要 8/9600 ... 接近 1ms 了.
第一個 delay 是開始前的確認, 如果刪了, 可能因為時間不足而進不了 while.
之後不斷讀取, 裡面的 delay 是確認完成, 如果刪了, 可能因為時間不足而太早離開 while.
回复 支持 反对

使用道具 举报

发表于 2023-5-6 19:53:39 | 显示全部楼层
亲测可行:
int analogPin = 0;//定义模拟量读取口
int LED = 13;//定义13为led灯接口
char val = 0;//定义为全局变量!!!
void setup()
{
    ...
}
void loop()
{
  //char val;//定义变量val,用于暂存上位机发送来的字符
  if (Serial.available() > 0) //如果上位机发送来了字符
  {
    val = Serial.read(); //读取上位机发来的字符,并保存到val
  }
  if(val == '1') //当上位机发送过来'1',执行第一个循环
  {
    ...
  }
  if(val == '0') //如果上位机发送字符'0',执行第二个循环
  {
    ...
  }
}
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-20 06:01 , Processed in 0.051106 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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