readString()本来的逻辑就是读到超时为止
前情提要:
在航模中,PWM信号是绕不过去的一部分。在这里为了篇幅考虑,不具体进行介绍,各位读者可自行在网上寻找介绍。在使用arduino进行电子制作的时候,.readString函数会经常被用于读取串口信号,然而为了通用性的考虑,该函数通常会需要至少1秒钟的时间进行读取。在本文中,作者将介绍一种针对PWM信号专门设计的算法。
正文:
为了输出PWM型号,我们可以借用arduino官方的Servo库,输出50Hz的PWM信号,并且其每个周期内高电平时间的范围在1ms~2ms。
下面展示一个标准的实现方式:
#include <Servo.h> Servo myServo; String comStr = ""; int comInt=0; void setup() { Serial.begin(9600); while(Serial.read()>=0){} // 清除串口缓存 myServo.attach(9); // 定义PWM脚为pin9 myServo.writeMicroseconds(1000); // 设置PWM信号到最小值 } void loop() { if (Serial.available() > 0){ // 监听电脑串口 delay(10); comStr = Serial.readString(); // 读取电脑输入的数字 comInt = comStr.toInt(); // 字符串格式转换为int格式 comInt = constrain(comInt, 1000, 2000); // 限制最大最小值 Serial.println(comInt); // 通过串口向电脑发送即将发出的PWM信号大小 myServo.writeMicroseconds(comInt); // 向PWM口输出PWM型号 } }
在作者的实际测试中,由于.readString的存在,在arduino收到信号的约1秒后才能发出修改后的PWM信号。这个延迟对于航模来说是绝对不可接受的,因此我们专门针对PWM信号开发了一直全新的算法。
#include <SoftwareSerial.h> uint16_t temp; void setup() { Serial.begin(115200); RCSerial.begin(115200); } int16_t readInt() { char rec = '0'; int16_t num = 0; while (true) { if (Serial.available()) { rec = Serial.read(); if (rec < '0' || rec > '9') { if (num < 1000 || num > 2000) { num = 1000; return num; } return num; } num = num * 10 + (rec - '0'); } } } void loop() { if (Serial.available()) { Serial.println("Received"); temp = readInt(); Serial.println(temp); } }
注意:上述代码仅仅是实现了读取和再次发送到电脑的功能,至于怎么将读取的信息输出为PWM信号,相信聪明的读者们只要参照第一例代码就能很快完成移植。
因为作者本人并没有写注释的习惯,因此我们挑出其中的精华部分专门讲解一下。
if (rec < '0' || rec > '9') { if (num < 1000 || num > 2000) { num = 1000; return num; } return num; } num = num * 10 + (rec - '0'); } } }
由于这段是从上文直接复制过来的,所以{}的嵌套关系稍微有点怪,不过大家应该都能理解。
我们串口接收到的信息是一个个字符。因此,第一个if语句是判断接收到的数据是否是数字,如果不是,那就结束。
然后,第二个if语句就是判断输入数据的大小,如果不在范围内,那就统统返回1000。
最后是,
num = num * 10 + (rec - '0');
这句,首先是rec - '0'。由于本质上我们得到的是char类型数据,是ASCII码,具体而言,'0'的ascii码是48,'1'的ascii码是49。
所以,rec - '0',可以将它转换为具体的数字,就比如说当rec是'1'的时候,ASCII码相减49 - 48 = 1。现在你1 * 10 + 2 = 12 12 * 10 + 3 =123 123 * 10 + 4 =1234,就可以还原出原来的数字了。
在作者的实际测试下,用此方法时,从arduino接收信号到再次发出的延迟可以忽略不计,与.readString方法产生巨大差距。
总结:
上述介绍的方法很巧妙,使用前一定要完全理解,不然容易出现很多意料之外的错误。第一次没看懂没关系,遇到不会的名词可以先上网查一下,要是多读几次还是读不懂,可以在下方进行提问,只要有时间,我很乐意解答。
[修改于 2年4个月前 - 2022/07/15 15:40:47]
引用WernerPleischner发表于1楼的内容readString()本来的逻辑就是读到超时为止
唔,不太懂,能稍微展开说下嘛
引用WernerPleischner发表于1楼的内容readString()本来的逻辑就是读到超时为止
我去查了一下,确实是你说的这样的。但也正是如此,我们需要一个新的算法来读取PWM信号。
很有钻研精神,但是方向错了,这种情况可以使用XXXXXXXXXadStringUntil(结束符)解决,即读到结束符快速结束本次读取,readString会默认等待防止不能完全读取缓冲区内容
引用NullPeople发表于4楼的内容很有钻研精神,但是方向错了,这种情况可以使用XXXXXXXXXadStringUntil(结束符)解...
感谢指导,之前确实不知道这个,大家或许可以当做一个扩宽思路的方法看看吧哈哈
不需要这么做。串口可以发送停止符。arduino读串口时读到停止符可以立刻退出。可以读一读官方例程
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。