c++ 使用SPI时,为什么全局缓冲区变量与局部缓冲区变量产生不同的结果?

ycl3bljg  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(121)

好吧,长期开发人员,但使用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社区仍然有帮助,并且是一个很好的教训,总是阅读文档,即使你认为有些事情是显而易见的。

k3bvogb1

k3bvogb11#

正如在各种评论和问题更新中所讨论的那样,这不是C++的问题,而是对SPI API的误解。
问题在于,SPI.transfer的重载以缓冲区指针和大小作为参数,仍然像其他重载一样进行双向传输,但它不是像其他重载那样返回传输的数据,而是用传入的数据覆盖传出的缓冲区。
因此,如果buffer是全局的,那么第二次和以后对writeRow的调用将发送之前接收到的数据,而不是初始化的数据。对于本地buffer,这不会发生,因为每次对writeRow的调用都包含一个新的buffer和硬编码的初始化器的内容。
See the Arduino documentation for SPI.transfer .

eqoofvh9

eqoofvh92#

不同之处在于全局缓冲区只初始化一次。
如果你使用另一个函数将值设置为零,那么它们将保持为零。
另一方面,每次输入函数writeRow()时,函数中的缓冲区将重新初始化为指定值,因此您将始终获得写入SPI总线的预期值。
在我看来,你在某个时候覆盖了缓冲区中的值。在发送之前打印出缓冲区中的值,以确保你得到的是缓冲区中的值。

gab6jxml

gab6jxml3#

我假设你是用Arduino GUI/IDE/wher-you-want-to-call-it来构建这个。要记住的是,GUI会对你输入的内容进行一些预处理。

相关问题