好吧,长期开发人员,但使用C#
和Swift
等高阶语言。我正在为一个硬件项目使用原生C++
,并使用Arduino进行原型设计。然而,这让我为难。
我有一个缓冲区,我通过SPI发送,我目前已经定义为一个局部变量,但当我把它移动到全局范围,我得到不同的结果!
这是预期的工作…
void writeRow(uint8_t row){
uint8_t buffer[] = {
B01111111 ^ 0xFF,
B00111111 ^ 0xFF,
B00111111 ^ 0xFF,
B00011111 ^ 0xFF,
B00001111 ^ 0xFF,
B00000111 ^ 0xFF,
B00000011 ^ 0xFF,
B00000001 ^ 0xFF
};
uint16_t rowMask = 1 << row;
digitalWrite(PIN_LATCH, LOW);
SPI.transfer16(rowMask); SPI.transfer(buffer, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 2, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 4, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 6, 2);
digitalWrite(PIN_LATCH, HIGH);
}
字符串
但是这里没有,这里将缓冲区移动到全局级别,现在将所有零发送到SPI总线。
uint8_t buffer[] = {
B01111111 ^ 0xFF,
B00111111 ^ 0xFF,
B00111111 ^ 0xFF,
B00011111 ^ 0xFF,
B00001111 ^ 0xFF,
B00000111 ^ 0xFF,
B00000011 ^ 0xFF,
B00000001 ^ 0xFF
};
void writeRow(uint8_t row){
uint16_t rowMask = 1 << row;
digitalWrite(PIN_LATCH, LOW);
SPI.transfer16(rowMask); SPI.transfer(buffer, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 2, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 4, 2);
SPI.transfer16(rowMask); SPI.transfer(buffer + 6, 2);
digitalWrite(PIN_LATCH, HIGH);
}
型
那么我遗漏了什么呢?这个缓冲区必须是可以被多个函数访问/更新的,因此想要全局移动它。
如果这是错误的,那么正确的方法是什么?
更新(和专栏!)
我误解了Arduino的API。罪魁祸首是我做了错误的假设,这个版本的“transfer”和所有其他版本一样工作,只是这个版本使用了一个缓冲区,而不是单独发送uint8_t
s。
然而--这是在文档中,所以这在技术上是我的--**不像同一个函数的所有其他重载 * 每次发送一个或两个字节,然后返回传入数据,接受缓冲区的版本 * 用传入数据覆盖缓冲区 *,因此它第一次出去时就破坏了我的全局缓冲区。
我个人认为,对于那些为Arduino设计SPI库的人来说,这是一个非常糟糕的决定,因为相同函数的其他重载不会修改你的输出数据,而且这个名字也没有表明这个版本会有任何不同。相反,如果你已经有了缓冲区中的数据,这是一种更简单的发送方式。
因为它有这种意想不到的副作用行为,在我看来,它应该被命名为不同的东西,以更清楚地表明它正在修改您的输入数据,这与其他重载有根本的不同。或者至少添加一个额外的参数,表明您也想要传入数据。在我的情况下,我不想要或需要它。它是只出站的。
无论如何,很抱歉让你分心了。希望这对SO社区仍然有帮助,并且是一个很好的教训,总是阅读文档,即使你认为有些事情是显而易见的。
3条答案
按热度按时间k3bvogb11#
正如在各种评论和问题更新中所讨论的那样,这不是C++的问题,而是对
SPI
API的误解。问题在于,
SPI.transfer
的重载以缓冲区指针和大小作为参数,仍然像其他重载一样进行双向传输,但它不是像其他重载那样返回传输的数据,而是用传入的数据覆盖传出的缓冲区。因此,如果
buffer
是全局的,那么第二次和以后对writeRow
的调用将发送之前接收到的数据,而不是初始化的数据。对于本地buffer
,这不会发生,因为每次对writeRow
的调用都包含一个新的buffer
和硬编码的初始化器的内容。See the Arduino documentation for
SPI.transfer
.eqoofvh92#
不同之处在于全局缓冲区只初始化一次。
如果你使用另一个函数将值设置为零,那么它们将保持为零。
另一方面,每次输入函数
writeRow()
时,函数中的缓冲区将重新初始化为指定值,因此您将始终获得写入SPI总线的预期值。在我看来,你在某个时候覆盖了缓冲区中的值。在发送之前打印出缓冲区中的值,以确保你得到的是缓冲区中的值。
gab6jxml3#
我假设你是用Arduino GUI/IDE/wher-you-want-to-call-it来构建这个。要记住的是,GUI会对你输入的内容进行一些预处理。