c – Serial.println()影响Serial1读数

c – Serial.println()影响Serial1读数,第1张

概述我在将一些C代码转换为Arduino时遇到了麻烦.任何帮助,将不胜感激. 编辑 我已成功完成上述任务.然而,现在唯一的问题是Arduino代码我已准确,正确地读取电压,但没有其他寄存器.我也可以写油门了.如果我调用不同数量的Serial.println()语句,其他寄存器上的读数会发生变化,在某些情况下,电压寄存器也会停止工作.这在我的代码中可以找到 Serial.print("Voltage: 我在将一些C代码转换为Arduino时遇到了麻烦.任何帮助,将不胜感激.

编辑
我已成功完成上述任务.然而,现在唯一的问题是Arduino代码我已准确,正确地读取电压,但没有其他寄存器.我也可以写油门了.如果我调用不同数量的Serial.println()语句,其他寄存器上的读数会发生变化,在某些情况下,电压寄存器也会停止工作.这在我的代码中可以找到

Serial.print("Voltage: );

如果我打印出所有这些寄存器,答案就会改变.我无法弄清楚为什么会这样.

/* DEFinitioNS */#include <math.h>/* floatS */uint8_t command[5];uint8_t response[3];/* INTEGERS */byte deviceid = 0x17;double throttleOut = 0;double voltage = 0;double rippleVoltage = 0;double current = 0;double power = 0;double throttle = 0;double pwm = 0;double rpm = 0;double temp = 0;double becVoltage = 0;double safeState = 0;double linkliveEnabled = 0;double eStopStatus = 0;double rawNTC = 0;/* SETUP */voID setup() {  Serial1.begin(115200);  Serial.begin(115200);}voID loop() {  flushPort();  ReaDWriteRegister(128,1000,true);//_throttleOut is 0[0%] to 65535[100%]  voltage = ReaDWriteRegister(0,false) / 2042.0 / 0.05;  rippleVoltage = ReaDWriteRegister(1,false) / 2042 / 0.25;  current = ReaDWriteRegister(2,false) / 204200 * 50;  power = voltage * current;  throttle = (ReaDWriteRegister(3,false) / 2042.0 / 1.0);  pwm = ReaDWriteRegister(4,false) / 2042.0 / 3.996735;  rpm = ReaDWriteRegister(5,false) / 2042.0 / 4.89796E-5;  int poleCount = 20;//Motor pole count  rpm = rpm / (poleCount / 2);  temp = ReaDWriteRegister(6,false) / 2042.0 * 30.0;  becVoltage = ReaDWriteRegister(7,false) / 2042 / 0.25;  safeState = ReaDWriteRegister(26,false);  linkliveEnabled = ReaDWriteRegister(25,false);  eStopStatus = ReaDWriteRegister(27,false) == 0 ? false : true;  rawNTC = ReaDWriteRegister(9,false) / 2042.0 / 0.01567091;  rawNTC = 1.0 / (log(rawNTC * 10200.0 / (255.0 - rawNTC) / 10000.0 ) / 3455.0 + 1.0 / 298.0) - 273.0;  Serial.print("Voltage: ");  Serial.println(voltage);  Serial.print("Current: ");  Serial.println(current);}voID flushPort() {  command[0] = command[1] = command[2] = command[3] = command[4] = 0;Serial1.write(command,5);  while (Serial1.available() > 0) {    Serial1.read();  }}double ReaDWriteRegister(int reg,int value,bool writeMode) {  // Send read command  command[0] = (byte)(0x80 | deviceid);  command[1] = (byte)reg;  command[2] = (byte)((value >> 8) & 0xFF);  command[3] = (byte)(value & 0xFF);  command[4] = (byte)(0 - command[0] - command[1] - command[2] - command[3]);  Serial1.write(command,5);  // Read response  if(Serial1.available() == 3) {  response[0] = (byte)Serial1.read();  response[1] = (byte)Serial1.read();  response[2] = (byte)Serial1.read();  }  if ((byte)(response[0] + response[1] + response[2]) == 0)  {    return (double)((response[0] << 8) + (response[1]));  }  else  {    Serial.println("Error communicating with device!");  }}

编辑2
一些usb逻辑分析仪拍摄的照片.
[]
[]
[]
[]
[]
[]
[]
并且所有数据包都在这一个:
[]
也许这会有助于超时等.这就是我所拥有的所有信息:.

解决方法 ReaDWriteRegister无法工作.在115200,每个角色大约需要发送或接收87us.在那段时间里,Arduino可以执行大约100行代码!

看看这个片段:

Serial1.write(command,5);  // Read response  if(Serial1.available() == 3) {

write函数仅将命令放入输出缓冲区并开始发送第一个字符.它在所有字符传输之前返回.这需要500us!

然后,您将查看是否收到了3个字符的响应.但是命令还没有完成传输,你当然没有等待258us(3次86us).如果设备需要时间来执行命令,甚至可能需要更长的时间.

您必须做两件事:等待命令发送,并等待接收响应.试试这个:

Serial1.write(command,5);  Serial1.flush(); // wait for command to go out  // Wait for response to come back  while (Serial1.available() < 3)    ; // waitin'....  // Read response  response[0] = (byte)Serial1.read();  response[1] = (byte)Serial1.read();  response[2] = (byte)Serial1.read();

这称为“阻塞”,因为Arduino在您等待响应时不会执行任何其他 *** 作.

但是,如果遗漏了一个角色,你的程序可能会“挂起”,如果没有正确发送/接收第二个角色,则等待第四个角色(它会发生).所以你应该在while循环中放置500us超时:

// Wait for response  uint32_t startTime = micros();  while ((Serial1.available() < 3) && (micros() - startTime < 500ul))    ; // waitin'...

…或更长时间,如果您知道设备响应的速度有多快.然后你可以确定你是否真的得到了回复:

完整程序更新(v2):

/* DEFinitioNS */#include <math.h>/* INTEGERS */byte deviceid = 0x17;uint8_t command[5];uint8_t response[3];/* floatS */double  throttleOut     = 0.0;double  voltage         = 0.0;double  rippleVoltage   = 0.0;double  current         = 0.0;double  power           = 0.0;double  throttle        = 0.0;double  pwm             = 0.0;double  rpm             = 0.0;double  temp            = 0.0;double  becVoltage      = 0.0;uint8_t safeState       = 0;uint8_t linkliveEnabled = 0;bool    eStopStatus     = 0;double  rawNTC          = 0.0;/* SETUP */voID setup() {  Serial1.begin(115200);  Serial.begin(115200);  Serial.println( F("---------------------------") );  // According to the spec,you can synchronize with the device by writing  // five zeroes.  Although I SUSPECT this is mostly for the SPI and I2c  // interfaces (not TTL-level RS-232),it won't hurt to do it here.  Serial1.write( command,5 );  delay( 250 ); // ms  while (Serial1.available())    Serial1.read(); // throw away  // Set the throttle just once  ReaDWriteRegister(128,1000);//_throttleOut is 0[0%] to 65535[100%]}//  For 12-bit A/D conversions,the range is 0..4096.  Values at//  the top and bottom are usually useless,so the value is limited//  to 6..4090 and then shifted down to 0..4084.  The mIDdle of this//  range will be the "1.0" value: 2042.  Depending on what is being //  measured,you still need to scale the result.const double ADC_FACTOR = 2042.0;voID loop() {  uint32_t scanTime = millis(); // mark time Now so we can delay later  voltage             = ReaDWriteRegister(  0,0 ) / ADC_FACTOR * 20.0;  rippleVoltage       = ReaDWriteRegister(  1,0 ) / ADC_FACTOR * 4.0;  current             = ReaDWriteRegister(  2,0 ) / ADC_FACTOR * 50.0;  power               = voltage * current;  throttle            = ReaDWriteRegister(  3,0 ) / ADC_FACTOR * 1.0;  pwm                 = ReaDWriteRegister(  4,0 ) / ADC_FACTOR * 0.2502;  rpm                 = ReaDWriteRegister(  5,0 ) / ADC_FACTOR * 20416.66;  const int poleCount = 20;//Motor pole count  rpm                 = rpm / (poleCount / 2);  temp                = ReaDWriteRegister(  6,0 ) / ADC_FACTOR * 30.0;  becVoltage          = ReaDWriteRegister(  7,0 ) / ADC_FACTOR * 4.0;  safeState           = ReaDWriteRegister( 26,0 );  linkliveEnabled     = ReaDWriteRegister( 25,0 );  eStopStatus         = ReaDWriteRegister( 27,0 );  rawNTC              = ReaDWriteRegister(  9,0 ) / ADC_FACTOR * 63.1825;  const double R0 =  1000.0;  const double R2 = 10200.0;  const double B  =  3455.0;  rawNTC          = 1.0 / (log(rawNTC * R2 / (255.0 - rawNTC) / R0 ) / B + 1.0 / 298.0) - 273.0;  Serial.print( F("Voltage: ") );  Serial.println(voltage);  Serial.print( F("Current: ") );  Serial.println(current);  Serial.print( F("Throttle: ") );  Serial.println(throttle);  Serial.print( F("RPM: ") );  Serial.println(rpm);  // These prints do not actually send the characters,they only queue  // them up to be sent gradually,at 115200.  The characters will be  // pulled from the output queue by a TX interrupt,and given to the  // UART one at a time.  //  // To prevent these interrupts from possibly interfering with any other  // timing,and to pace your program,we will wait *Now* for all the  // characters to be sent to the Serial Monitor.  Serial.flush();  // Let's pace things a little bit more for testing: delay here until  // it's time to scan again.  const uint32_t SCAN_INTERVAL = 1000ul; // ms  while (millis() - scanTime < SCAN_INTERVAL)    ; // waitin'}int16_t ReaDWriteRegister(int reg,int value) {  // Flush @R_419_5983@,as suggested by Gee Bee  while (Serial1.available() > 0)    Serial1.read();  // Send command (register number determines whether it is read or write)  command[0] = (byte)(0x80 | deviceid);  command[1] = (byte)reg;  command[2] = (byte)((value >> 8) & 0xFF);  command[3] = (byte)(value & 0xFF);  command[4] = (byte)(0 - command[0] - command[1] - command[2] - command[3]);  Serial1.write(command,5);  // The command bytes are only queued for transmission,they have not  // actually gone out.  You can either wait for command to go out  // with a `Serial1.flush()`  *OR*  add the transmission time to the  // timeout value below.  However,if anything else has queued bytes  // to be sent and dIDn't wait for them to go out,the calculated   // timeout would be wrong.  It is safer to flush Now and guarantee  // that *all* bytes have been sent: anything sent earlIEr (I don't   // see anything else,but you may change that later) *plus*   // these 5 command bytes.  Serial1.flush();  // Now wait for response to come back,for a certain number of us  //   The TIMEOUT Could be as short as 3 character times @ the Serial1  //   baudrate: 3 * (10 bits/char) / 115200bps = 261us.  This is if  //   the device responds immediately.  Gee Bee says 20ms,which would   //   be 20000ul.  There's nothing in the spec,but 1ms seems generous  //   for reading the raw NTC value,which may require an ADC conversion.  //   Even the Arduino can do that in 100us.  Try longer if you get  //   timeout warnings.  const uint32_t TIMEOUT = 2000ul;  uint32_t startTime = micros();  while ((Serial1.available() < 3) && (micros() - startTime < TIMEOUT))    ; // waitin'...  int16_t result;  if (Serial1.available() >= 3) {    response[0] = (byte)Serial1.read();    response[1] = (byte)Serial1.read();    response[2] = (byte)Serial1.read();    // Verify the checksum    if (response[0] + response[1] + response[2] != 0) {      Serial.print( reg );      Serial.println( F(" Checksum error!") );      Serial.flush(); // optional,use it for Now to stay synchronous    }    //  Cast to 16 bits *first*,then shift and add    result = (((int16_t) response[0]) << 8) + (int16_t) response[1];  } else {    //  Must have timed out,because there aren't enough characters    Serial.print( reg );    Serial.println( F(" Timed out!") );    Serial.flush(); // optional,use it for Now to stay synchronous    result = 0;  }  return result; // You must always return something}

评论:

>您的结果计算中出现错误(可能)已在上面的答案中修复.我认为,在加法之外加注使你失去前八位.如上计算应给出正确的答案.
>经过一番谷歌搜索,我看到这是一个Castle Serial Link controller.这将是有用的知道.它描述了我在上面的ReaDWriteRegister函数中使用的校验和.该函数可以告诉您它是否超时或校验和是否错误.这也意味着可能需要更长的超时.目前尚不清楚您的设备是否等待最多480毫秒来获取最新值,或者是否持续缓存它们并立即响应从ESC接收的最后一个值.但是,由于ESC接收命令然后发送新值所花费的时间,写入将不会反映在最长480ms的读取值中.见ESC Castle Link protocol.
> ReaDWriteRegister函数返回一个16位整数,效率更高.比较浮点数永远不会好. BTW,double只是8位Arduinos上的单浮点数.
> ReaDWriteRegister函数不需要writemode参数,因为寄存器编号决定了您是在写还是正在读取设备.
>仅在设置中执行写入油门值.

更新2

您的逻辑分析仪镜头显示为ESC显示“扫描”.它正在尝试每个设备ID,其中一些回复非零电压.此外,它似乎运行在9600,而不是115200.这是来自不同的设置?

无论如何,它确认了控制器规范所说的内容:写入5个字节,读取3.校验和值如预期.但是,它的运行速度比程序慢10倍,因此它不会提供有关超时的新信息.这可能意味着在设备响应之前有一个小的延迟,可能是~1位时间,或大约100us.

你读过控制器规格吗?您应该将程序与规范进行比较,以确保您了解控制器的工作原理.

我已将上面的程序修改为:

>在设置中与控制器同步(写入5个零字节并等待250ms),
>使用规范中的缩放数字(而不是它们的倒数?),
>使用有意义的常数而不是“魔法”数字(例如2042),
>对几个寄存器使用整数或布尔类型而不是double(请参阅safeState,linkliveStatus和eStopStatus),
>将超时时间增加到2ms(如果继续频繁超时,则继续增加),以及
>发生错误时输出注册号.

如果您想在这方面取得成功,您必须学会阅读规范并将其要求转换为符合要求的代码.你开始的程序在最坏的情况下是非保形的,或者说最好是误导.对于说“INTEGERS”和“floatS”的评论我特别感到好笑,但这些部分却反其道而行之.

也许这是修复别人代码的一课?它确实会遇到许多问题.如果我每次都说镍,我说:

>“这个号码是什么?”
>“那个评论错了!”
>“规范说你应该……”
>“为什么这么难读?我只是添加一些间距.”

……我会成为一个非常富有的人. 总结

以上是内存溢出为你收集整理的c – Serial.println()影响Serial1读数全部内容,希望文章能够帮你解决c – Serial.println()影响Serial1读数所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/1240441.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存