繁体   English   中英

串行监视器显示来自 Arduino Mega 的意外输入

[英]Serial monitor showing unexpected input from Arduino Mega

我正在使用 Arduino Mega 来控制 CS1237 ADC。 根据我找到的数据表(通过https://github.com/SiBangkotan/CS1237-ADC-cpp-library ),我向时钟引脚发送信号,并在每个时钟脉冲后等待 1ms,然后读取响应. 这似乎在某种程度上起作用了,因为当我对接收到的每个位执行Serial.println()时,对于生成的数据字,我得到一个 24 位数据字,与我得到的 24 个独立位相匹配。 但是,当我取出Serial.println()的额外调试用途时,即在接收到每一位时打印每一位,我也会得到一个不同的数据字。 每次都是 20 位全 1,而不是 24 位各种 1 和 0。 我不明白为什么串行通信通道中的这个额外调试 output 应该改变进入串行监视器的数据字?

这是我的设置和预设置代码:

// Using pins 2 and 3 on the Arduino, since 0 and 1 are used to talk to the USB port.
int ndrdy = 2;
int clck = 3;

// the setup routine runs once when you press reset:
void setup() {
    // initialize serial communication at 9600 bits per second:
    Serial.begin(9600);
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
    }
    // make the drdy's pin an input and clock an output:
    pinMode(ndrdy, INPUT);
}

这是相关代码:

void loop() {
  // Hacky way of waiting for the signal that !DRDY is ready.
  while(digitalRead(ndrdy) == LOW) {
    // do nothing until pin pulls high.
  }
  while(digitalRead(ndrdy) == HIGH) {
    // keep doing nothing until pin goes low again.
  }
  // now data is ready, we can read

  long dataword = 0;

  for(int i = 0; i < 24; i++) {
    digitalWrite(clck, HIGH);
    delayMicroseconds(1);
    digitalWrite(clck, LOW);
    int new_bit = digitalRead(ndrdy);
    dataword <<= 1;       // shift everything one place to the left
    dataword |= new_bit;  // add the new bit to the newly empty place
  }

  // There's a total of 27 bits but we don't care about the last 3.
  // Write HIGH 3 times to flush it out.
  for (int i = 0; i < 3; i++) {
    digitalWrite(clck, HIGH);
    delayMicroseconds(1);
    digitalWrite(clck, LOW);
  }

  // Send out the data to the USB serial out:
  Serial.println(dataword, BIN);
}

serial monitor中这个output是

13:44:45.685 -> 11111111111111111111
13:44:45.685 -> 11111111111111111111
13:44:45.718 -> 11111111111111111111
13:44:45.751 -> 11111111111111111111
13:44:45.751 -> 11111111111111111111
13:44:45.785 -> 11111111111111111111
13:44:45.818 -> 111111111111111111111
13:44:45.852 -> 11111111111111111111
13:44:45.852 -> 11111111111111111111
13:44:45.885 -> 11111111111111111111
13:44:45.918 -> 111111111111111111111
13:44:45.918 -> 11111111111111111111
13:44:45.951 -> 11111111111111111111

...等等。 但是,当我添加一个额外的Serial.println(new_bit); 就在for(int i = 0; i < 24; i++)循环的右括号之前,我在 Arduino IDE 的串行监视器中得到了这样的 output(显示时间戳已打开):

14:41:19.992 -> 0
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 1
14:41:19.992 -> 0
14:41:19.992 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 0
14:41:20.025 -> 0
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.025 -> 1
14:41:20.058 -> 0
14:41:20.058 -> 1
14:41:20.058 -> 11111111011111001111101
14:41:20.091 -> 0
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 1
14:41:20.091 -> 0
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 0
14:41:20.125 -> 0
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.125 -> 1
14:41:20.158 -> 1
14:41:20.158 -> 0
14:41:20.158 -> 1
14:41:20.158 -> 11111111011111001111101

如果我是Serial.println() - 在该行上除了new_bit之外的任何东西,这不会发生,例如,如果我做Serial.println(dataword); 或者如果我引入一个小的延迟而不是进行串行打印。 在那些情况下,它仍然执行 20 1 的 output。我无法弄清楚串行通信有什么问题,因为从 ADC 读取似乎正常。 如果我引入 5000us 或更多的延迟,那么dataword的内容就会发生变化,这似乎变成了延迟长度的 function。 即对于每个延迟长度(5000us、6000us、10000us和20000us是我试过的), dataword的内容是恒定的。 如果延迟足够长,它会回到全 1。

从查看数据表...

首先当芯片启动时... Al 引脚默认输入。 你没有设置你的时钟引脚模式,所以你没有时钟。 此外,ADC 可能需要长达 300 毫秒才能唤醒。 这是启动顺序的一部分,当您退出 setup() 时芯片应该准备就绪。 您还可以在 setup() 中包含任何 ADC 寄存器的设置。 请参见数据表启动顺序 @ 图 5 和图 6。

此外,如果您想尝试较低的时钟速度,请不要让clck高电平超过 100us

来自datasheet,2.5: “当SCLK从低变高并保持高电平超过100μs时,CS1237进入PowerDown模式,消耗小于0.1μA。当SCLK变回低电平时,芯片将恢复正常运行。”

void setup() 
{
    // initialize serial communication at 9600 bits per second:
    Serial.begin(9600);
    while (!Serial) {}
    
    // make the drdy's pin an input and clock an output:
    // remove pullup on ndrdy
    digitalWrite(ndrdy, LOW);
    pinMode(ndrdy, INPUT);

    digitalWrite(clck, LOW);
    pinMode(clck, OUTPUT);

    // wait for ADC to end its own boot sequence.
    while (digitalRead(ndrdy)) {}
    while (!digitalRead(ndrdy)) {}
}

数据表的图表“图 7”表示:

等到 /DRDY 为低电平,等待持续时间 t4(为 0),所以不等待也是可以的,然后循环每个位:

  • 设置时钟高
  • 至少等待持续时间 t6 (455 ns)
  • 读取输入位。
  • 将时钟设置为低电平。
  • 在下一个时钟之前,时钟必须保持低电平至少持续时间 t5 (455 ns)。

您可以在时钟较低时读取数据位,但请注意数据库图。 8、时钟位一变低,第27位就失效了。 根据经验,这暗示您应该在时钟高时阅读。 有些数据表很难阅读,有些甚至是错误的。 这就是我对这个的解释,但我可能是错的,你可能还想在时钟高时尝试阅读。

然后你的输入过程变成:

// reads a 24 bit value from ADC, returns -1 if no data to read 
// note that this function does not wait, so your other processing 
// can still be responsive. 
long readADC() 
{
    // check if data is ready. 
    if (digitalRead(ndrdy))
        return -1;    

    long result = 0;

    // read 24 bits.
    for (int i = 0; i < 24; i++) 
    {
        // get ADC to output a bit.
        digitalWrite(clck, HIGH);
        delayMicroseconds(1);      

        // read it
        int new_bit = digitalRead(ndrdy);

        digitalWrite(clck, LOW);

        delayMicroseconds(1);      // this delay could be shorter, because of 
                                   // operations immediately taking some
                                   // time...  You may want to time it
                                   // using a scope, at least for the fun
                                   // of it.  On a slow 8-bit ATMega, it may not
                                   // be needed, there are move than 16 cycles
                                   // of processing below. plus 2 cycles for
                                   // jumping back to top of loop.
                                   // IS needed for sure at clock speeds above
                                   // 16 MHz.
        result <<= 1;
        result |= new_bit;
    }

    // emit 3 more clock cycles.
    for (int i = 0; i < 3; i++) 
    {
        digitalWrite(clck, HIGH);
        delayMicroseconds(1);      
        digitalWrite(clck, LOW);
        delayMicroseconds(1);
    }

    // note that the 27th clock cycle has set /DRDY high.
    // There is never any need to wait on /DRDY going high.

    return result;  // mask unwanted bits.
}


void loop()
{
    // ...

    long adcValue = readADC();

    if (adcValue >= 0)
    {
       // process ADC input
       Serial.print("ADC reading: ");
       Serial.print(adcValue);
       Serial.print(" (");
       Serial.print(adcValue, BIN);
       Serial.println(")");
    }

    // ...
}

一旦你顺利运行,你可以尝试通过让你自己的 455ns 延迟 function 不使用任何操作来加快读取速度

#define NOOP() __asm__("nop\n\t")  // 1 operation cycle delay, for 8-bit ATMega, 
                                   // 1 op cycle == 1 clock cycle.
                       

实际延迟将取决于您的时钟速度。 通常,这些是使用宏来实现的。

例如,在多行宏中。 请注意行尾的反斜杠。 这些应该是该行的最后一个字符,宏中不应有任何空行

  // 500 ns delay @ 16MHz clock, on an 8-bit ATMega.
  #define NOOP() __asm__("nop\n\t")
  #define DELAY_500ns()   NOOP(); NOOP(); NOOP(); NOOP(); \ 
                          NOOP(); NOOP(); NOOP(); NOOP(); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM