简体   繁体   English

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

[英]Serial monitor showing unexpected input from Arduino Mega

I'm using an Arduino Mega to control a CS1237 ADC.我正在使用 Arduino Mega 来控制 CS1237 ADC。 I'm sending a signal to the clock pin and after each clock pulse, waiting 1ms and then reading the response, according to the datasheet I found (via https://github.com/SiBangkotan/CS1237-ADC-cpp-library ).根据我找到的数据表(通过https://github.com/SiBangkotan/CS1237-ADC-cpp-library ),我向时钟引脚发送信号,并在每个时钟脉冲后等待 1ms,然后读取响应. This seems to be working in some capacity, because when I do Serial.println() for each bit received, and for the resulting dataword, I get a 24 bit dataword that matches the 24 separate bits I got.这似乎在某种程度上起作用了,因为当我对接收到的每个位执行Serial.println()时,对于生成的数据字,我得到一个 24 位数据字,与我得到的 24 个独立位相匹配。 However, when I take out the extra debugging uses of Serial.println() that print each bit as they are received, I get a different dataword as well.但是,当我取出Serial.println()的额外调试用途时,即在接收到每一位时打印每一位,我也会得到一个不同的数据字。 It's 20 bits of all 1's every single time, instead of 24 bits of various 1's and 0s.每次都是 20 位全 1,而不是 24 位各种 1 和 0。 I cant figure out why this extra debugging output in the serial communication channel should change the dataword that comes into the serial monitor?我不明白为什么串行通信通道中的这个额外调试 output 应该改变进入串行监视器的数据字?

Here's my setup and pre-setup code:这是我的设置和预设置代码:

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

Here's the relevant code:这是相关代码:

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

The output of this in serial monitor is 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

...and so forth. ...等等。 However, when I add an extra Serial.println(new_bit);但是,当我添加一个额外的Serial.println(new_bit); just before the closing bracket of the for(int i = 0; i < 24; i++) loop, I get output like this in the Arduino IDE's serial monitor (shown with timestamps turned on):就在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

This doesn't happen if I'm Serial.println() -ing anything other than the new_bit on that line, eg if I do Serial.println(dataword);如果我是Serial.println() - 在该行上除了new_bit之外的任何东西,这不会发生,例如,如果我做Serial.println(dataword); or if I introduce a small delay instead of doing the serial print.或者如果我引入一个小的延迟而不是进行串行打印。 In those cases, it still does the twenty 1's output. I can't figure out what is wrong with the serial communication, since it seems like reading from the ADC is going OK.在那些情况下,它仍然执行 20 1 的 output。我无法弄清楚串行通信有什么问题,因为从 ADC 读取似乎正常。 If I introduce a delay of 5000us or more, then there is a change in the contents of dataword , which seems to then become a function of the length of the delay.如果我引入 5000us 或更多的延迟,那么dataword的内容就会发生变化,这似乎变成了延迟长度的 function。 Ie the content of dataword is constant for each delay length (5000us, 6000us, 10000us, and 20000us are what I tried).即对于每个延迟长度(5000us、6000us、10000us和20000us是我试过的), dataword的内容是恒定的。 If the delay is long enough, it goes back to being all 1's.如果延迟足够长,它会回到全 1。

From looking at the datasheet...从查看数据表...

First when the chip boots... Al pins are input by default.首先当芯片启动时... Al 引脚默认输入。 You do not set your clock pin mode, so you have no clock.你没有设置你的时钟引脚模式,所以你没有时钟。 Also, the ADC could take up to 300 milliseconds to wake up.此外,ADC 可能需要长达 300 毫秒才能唤醒。 That is part of your boot sequence, the chip should be ready when you exit setup().这是启动顺序的一部分,当您退出 setup() 时芯片应该准备就绪。 You may also include setting of any ADC registers in setup() as well.您还可以在 setup() 中包含任何 ADC 寄存器的设置。 See datasheet startup sequence @ figures 5 and 6.请参见数据表启动顺序 @ 图 5 和图 6。

Also, if you want to try lower clock speeds, do not leave clck high longer than 100us此外,如果您想尝试较低的时钟速度,请不要让clck高电平超过 100us

From datasheet, 2.5: "When SCLK goes from low to high and stays high for more than 100μs, the CS1237 entersPowerDown mode, which consumes less than 0.1μA. When SCLK goes back low, the chip will resume normal operation."来自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)) {}
}

The chart "figure 7" of the datasheet says:数据表的图表“图 7”表示:

Wait until /DRDY is low, wait for duration t4 (which is 0), so no wait is OK, then loop for each bit:等到 /DRDY 为低电平,等待持续时间 t4(为 0),所以不等待也是可以的,然后循环每个位:

  • set clock high设置时钟高
  • wait at least for duration t6 (455 ns)至少等待持续时间 t6 (455 ns)
  • read input bit.读取输入位。
  • set clock low.将时钟设置为低电平。
  • clock must be held low for least duration t5 (455 ns) before next clock.在下一个时钟之前,时钟必须保持低电平至少持续时间 t5 (455 ns)。

You could read the data bit while the clock is low, but note how on database fig.您可以在时钟较低时读取数据位,但请注意数据库图。 8, the 27th bit becomes invalid as soon as the clock bit goes low. 8、时钟位一变低,第27位就失效了。 From experience, this hints that you are expected to read while clock is high.根据经验,这暗示您应该在时钟高时阅读。 Some datasheets are very tricky to read, and some are even wrong.有些数据表很难阅读,有些甚至是错误的。 That's how I interpret this one, but I may be wrong, you may want to also try reading while clock is high.这就是我对这个的解释,但我可能是错的,你可能还想在时钟高时尝试阅读。

Your input procedure then becomes:然后你的输入过程变成:

// 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(")");
    }

    // ...
}

Once you have this running smoothly, you can try and make reading a bit faster by making your own 455ns delay function, using no ops一旦你顺利运行,你可以尝试通过让你自己的 455ns 延迟 function 不使用任何操作来加快读取速度

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

The actual delay will depend on your clock speed.实际延迟将取决于您的时钟速度。 Usually, these are implemented using macros.通常,这些是使用宏来实现的。

Example, in a multi-line macro.例如,在多行宏中。 Note the backslash at the end of line.请注意行尾的反斜杠。 These should be the very last character of the line, and there should not be any blank lines in the macro这些应该是该行的最后一个字符,宏中不应有任何空行

  // 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