[英]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),所以不等待也是可以的,然后循环每个位:
您可以在时钟较低时读取数据位,但请注意数据库图。 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.