Arduino - 真正 Wire.write() 和 Wire.read() 解释的 5 个问题
Posted
技术标签:
【中文标题】Arduino - 真正 Wire.write() 和 Wire.read() 解释的 5 个问题【英文标题】:Arduino - 5 questions for real Wire.write() and Wire.read() explanation 【发布时间】:2016-10-15 22:17:15 【问题描述】:我在 Google 上搜索了很多,看来我并不是唯一一个在真正理解 Wire.write() 和 Wire.read() 方面遇到问题的人。作为新手,我几乎从不使用已经由某人编写的库,我尝试为模块创建我的类,以便真正了解该模块的工作原理并学习如何使用它。我读过几本书和太多教程,但我可以将它们总结为两点: a)所有教程都只是展示了如何使用这些方法的基础知识,b)它们实际上并没有解释这些步骤,就像一切都是完全不言自明的。说我笨,但我感觉就像有人告诉我 1 + 1 = 2,然后给了我一些多项式方程来解决 :( 所有书籍示例和几乎所有教程看起来都像这个虚构的例子:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.endTransmission(); // end this
//要阅读
Wire.requestFrom(Module_Address, 3); //Read three registers
Wire.read(); //Read first register
Wire.read(); //Read second register
Wire.read(); //Read third register
这就是阅读。 说到写作,就更糟了:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.write(something); //Write to first register
Wire.write(something); //write to second register
Wire.endTransmission(); // end this
到目前为止,使用我得到的任何模块都没有那么容易。通常,每个寄存器内部都有多个“选项”。例如,假设虚构模块具有这样的 First read register:
地址 |位 7 |位 6 |位 5 |位 4 |位 3 |位 2 |位 1 |位 0 数据字节 1 |静音。|选项2.......|........选项3....... ......
要只读选项 3,我会使用以下代码:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(module_address, 1);
byte readings = Wire.read() & 0x1F; //0x1F is hexadecimal of binary 0001111 for option 3 in register 1
问题 1 Wire.read() 之后的这个 '&' 真的意味着什么? (我知道它指向寄存器中的选项,但我不太明白,为什么会在那里)
问题 2 为什么前面的问题没有写在任何地方?这么多教程,这么多书,但当我试图弄清楚一个图书馆是如何运作的时,我偶然“发现”了它。
问题 3 假设假设模块有第三个处于写入模式的寄存器,如下所示:
地址 |位 7 |位 6 |位 5 |位 4 |位 3 |位 2 |位 1 |位 0 数据字节 3 |写标志.......|选项2…………|………………选项3…………
如何在不影响选项2和选项3的情况下写flag?或者换句话说,如何写入寄存器 3 的写标志?如果我采取 11000000 可能会影响,因为我可能不知道选项 2 和 3 到底是做什么的,或者我不希望干扰默认设置。
问题 4 某些模块必须用二进制编码的十进制编写。假设您有一个计时器,并且您希望将 17 秒倒计时设置为 0。为此,您需要写入数字 17 来注册一个,但数字应该是二进制编码的十进制。 17 的二进制编码是:0001 0111。但是当你这样做时:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.write(00010111);
Wire.endTransmission();
你得到不同的数字,13 或 10(不记得是什么数字,我知道是错的)。 但是,在进行此转换时:17/10*16 + 17%10 它会写入正确的数字 17。 是的,我也无意中发现了这一点。但是,这个方程是从哪里来的?我尽可能多地搜索(显然是错误的),但什么也没有。那么,有人是如何得出这个等式的呢?
问题 5 可能是一个愚蠢的题外话问题,但是: Arduino库是否应该以其他人难以理解其背后的想法的方式编写?换句话说,要弄清楚开发人员到底在做什么?我记得有一个人使用了很多乱七八糟的代码从传感器读取某些内容,然后使用公式将其从二进制编码的十进制转换以将其打印到串行监视器,而同样的事情可以简单地完成 Serial.print(read_byte, HEX); 并不是说我比他们更聪明(或更好),我只是不明白为什么有人会在没有(真正)需要的情况下编写复杂的代码。
非常感谢您的帮助:)
【问题讨论】:
【参考方案1】:问题 1. - 4.:在AVRFreaks 论坛Tutorials 上都被Bit Manipulation tutorial 覆盖。简而言之:
1) 在这种情况下,&
用于位掩码。
2) 如果您寻找“位操作”,那么这里有很多教程。
3) 可以通过位操作。如何?对于内存变量,只需使用位掩码。清除两位:var &= 0b00111111
设置两位:var |= 0b11000000
。如果您没有寄存器值,则必须读取 & 修改 & 写回它。如果您无法读取该值(例如,它是 eeproms 的内部地址),则无论如何您都必须在内存中保存该值。
4) 在 C++ 中,从零开始的数字是八进制的。如果你想要二进制,你必须使用 0b00010111。对于 HEX 基数,您必须使用 0xFF。这在该教程中没有明确提及,但两者都在此处使用。
5) 应尽可能清晰。但是对于没有良好 C++ 知识的初学者来说,无论如何都很难。对我来说,没有缩进的代码是最难阅读的,甚至是缩进不好、变量名不好的代码。这些库通常由高级用户编写,因此了解一些背景知识(例如了解二手 MCU 的数据表等)并不难理解。
顺便说一句:错误的 cmets 也不利于理解:
//0x1F is hexadecimal of binary 0001111 for option 3 in register 1
0x1F
的值绝对不是二进制的0001111
,而是00011111
(或更好:0b00011111
)
【讨论】:
感谢您的回答。错误的评论是因为我不小心写了 7 个数字,而不是 8 :) 改变想法 - 你能解决问题 3 的方式吗?以上是关于Arduino - 真正 Wire.write() 和 Wire.read() 解释的 5 个问题的主要内容,如果未能解决你的问题,请参考以下文章