差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
mp_serial_bus [2021/10/05 00:14] gongyusu [I2C] |
mp_serial_bus [2021/10/05 17:35] (当前版本) gongyusu [2. 串行外设接口SPI] |
||
---|---|---|---|
行 79: | 行 79: | ||
如您所见,I2C是一种将额外硬件连接到Pico的简单方法。您需要确保为您想要连接的任何设备提供适当的文档,让您知道哪些命令可以做什么,但只要您知道这一点,您就可以轻松地将各种零碎添加到您的 Pico并创建令人印象深刻的建筑。 | 如您所见,I2C是一种将额外硬件连接到Pico的简单方法。您需要确保为您想要连接的任何设备提供适当的文档,让您知道哪些命令可以做什么,但只要您知道这一点,您就可以轻松地将各种零碎添加到您的 Pico并创建令人印象深刻的建筑。 | ||
- | ### 串行外设接口 | + | ### 2. 串行外设接口SPI |
- | 我们已经了解了 I2C 的工作原理,现在让我们来看看 SPI。我们将使用完全相同的 LCD,因此命令和其他所有内容都相同,只是我们发送数据的协议不同。 | + | 我们已经了解了I2C的工作原理,现在让我们来看看SPI。我们将使用完全相同的LCD,因此命令和其他所有内容都相同,只是我们发送数据的协议不同。 |
- | SPI 有四个连接:SCLK、MOSI、MISO 和 CS(有时标记为 SS)。 SCLK 是时钟,MOSI 是将数据从 Pico 传输到外围设备的线路(请参阅“SPI 术语”框),而 MISO 则是将数据从外围设备传输到 Pico。 CS 代表芯片选择,用于将许多设备连接到单个 SPI 总线。您只需为 CS 线供电即可启用 SPI 外设并将其拉低以禁用它。稍微混淆一下,这个特定的设备没有 CS,但 /CS 代表 NOT CS - 换句话说,它与 CS 相反,所以你把它调低以启用 LCD 并调高以禁用它。您可以将 CS 连接到 GPIO 引脚并打开和关闭它以启用和禁用显示,但由于我们只有一个设备,我们可以简单地将其接地以保持启用状态(图 10-3)。 | + | |
- | 因此,将 SerLCD 的电源线连接到 VBUS 和 GND,我们只需要将其 SDO 连接到 Pico 的 MISO (GP4 / SPI0 RX)、SDI 到 MOSI (GP3 / SPI0 TX)、SCK 到 SCLK (GP2 / SPI0 SCK),和 /CS 到 GND。 | + | SPI有四个连接:SCLK、MOSI、MISO和CS(有时标记为SS)。 SCLK是时钟,MOSI是将数据从Pico 传输到外围设备的线路(请参阅“SPI 术语”框),而MISO则是将数据从外围设备传输到Pico。 CS代表芯片选择,用于将许多设备连接到单个SPI总线。您只需为CS线供电即可启用SPI外设并将其拉低以禁用它。稍微混淆一下,这个特定的设备没有CS,但/CS代表NOT CS - 换句话说,它与CS相反,所以你把它调低以启用LCD并调高以禁用它。您可以将CS连接到GPIO引脚并打开和关闭它以启用和禁用显示,但由于我们只有一个设备,我们可以简单地将其接地以保持启用状态(图 10-3)。 |
+ | 因此,将SerLCD的电源线连接到VBUS和GND,我们只需要将其SDO连接到Pico的MISO(GP4/SPI0 RX)、SDI到MOSI(GP3/SPI0 TX)、SCK到SCLK(GP2/SPI0 SCK),和/CS到GND。 | ||
<WRAP center round tip 60%> | <WRAP center round tip 60%> | ||
**SPI术语** | **SPI术语** | ||
- | SPI 需要四个连接:一个从主设备到从设备获取数据,另一个从相反方向获取数据,加上电源和地。 两条数据线意味着数据可以同时双向传输。 这些通常称为主出从入 (MOSI) 和主入从出 (MISO)。 但是,您会遇到它们具有不同的名称。 如果您查看 Raspberry Pi Pico 引脚分配(附录 B),它们被称为 SPI TX(发送)和 SPI RX(接收)。 这是因为 Pico 可以是 | + | SPI需要四个连接:一个从主设备到从设备获取数据,另一个从相反方向获取数据,加上电源和地。 两条数据线意味着数据可以同时双向传输。 这些通常称为主出从入(MOSI)和主入从出(MISO)。 但是,您会遇到它们具有不同的名称。 如果您查看Raspberry Pi Pico引脚分配(附录 B),它们被称为SPI TX(发送)和SPI RX(接收)。 这是因为Pico可以是一个主设备或从设备,所以这些连接是MOSI还是 MISO取决于Pico的当前功能。 在我们使用的LCD上,它们标有SDI(串行数据输入)和SDO(串行数据输出)。 |
- | 一个主设备或从设备,所以这些连接是 MOSI 还是 MISO 取决于 Pico 的当前功能。 在我们使用的 LCD 上,它们标有 SDI(串行数据输入)和 SDO(串行数据输出)。 | + | |
</WRAP> | </WRAP> | ||
- | SPI 中没有地址,因此我们可以深入编写代码: | + | SPI中没有地址,因此我们可以深入编写代码: |
<code python> | <code python> | ||
import machine | import machine | ||
行 102: | 行 103: | ||
spi.write("hello world") | spi.write("hello world") | ||
</code> | </code> | ||
- | 在这种情况下,我们使用 SPI0,一组可用的引脚是 GP2、GP3 和 GP4。 | + | 在这种情况下,我们使用SPI0,一组可用的引脚是GP2、GP3和GP4。 |
- | 大多数类型的串行通信都有速度或波特率,这基本上是多少 | + | 大多数类型的串行通信都有速度或波特率,这基本上是多少它每秒可以通过通道推送的数据位。 很多事情都会对此产生影响,例如连接的两个设备的功能以及它们之间的接线(多长时间?以及是否有其他设备的干扰)。 如果您发现损坏的数据存在问题,那么您可能需要减少它。 对于我们的小屏幕,我们只是为每个字符发送一个字节的数据,所以发送速度有多快并不重要,但对于其他一些SPI设备(例如基于像素的显示器),微调波特率率可能很重要。 |
- | 它每秒可以通过通道推送的数据位。 很多事情都会对此产生影响,例如连接的两个设备的功能以及它们之间的接线(多长时间? | + | |
- | 以及是否有其他设备的干扰)。 如果您发现损坏的数据存在问题,那么您可能需要减少它。 对于我们的小屏幕,我们只是为每个字符发送一个字节的数据,所以发送速度有多快并不重要,但对于其他一些 SPI 设备(例如基于像素的显示器),微调波特率 率可能很重要。 | + | |
让我们来看看这如何留下我们的温度计代码: | 让我们来看看这如何留下我们的温度计代码: | ||
<code python> | <code python> | ||
- | import machine import utime | + | import machine |
- | spi_sck=machine.Pin(2) spi_tx=machine.Pin(3) spi_rx=machine.Pin(4) | + | import utime |
- | spi=machine.SPI(0,baudrate=100000,sck=spi_sck, mosi=spi_tx, miso=spi_rx) adc = machine.ADC(4) | + | spi_sck=machine.Pin(2) |
+ | spi_tx=machine.Pin(3) | ||
+ | spi_rx=machine.Pin(4) | ||
+ | spi=machine.SPI(0,baudrate=100000,sck=spi_sck, mosi=spi_tx, miso=spi_rx) | ||
+ | adc = machine.ADC(4) | ||
conversion_factor = 3.3 / (65535) | conversion_factor = 3.3 / (65535) | ||
while True: | while True: | ||
- | reading = adc.read_u16() * conversion_factor temperature = 25 - (reading - 0.706)/0.001721 spi.write('\x7C') | + | reading = adc.read_u16() * conversion_factor |
+ | temperature = 25 - (reading - 0.706)/0.001721 spi.write('\x7C') | ||
spi.write('\x2D') | spi.write('\x2D') | ||
out_string = "Temp: " + str(temperature) | out_string = "Temp: " + str(temperature) | ||
- | spi.write(out_string) utime.sleep(2) | + | spi.write(out_string) |
+ | utime.sleep(2) | ||
</code> | </code> | ||
- | 如您所见,I2C 和 SPI 之间的代码差异非常小。设置好所有内容后,唯一真正的变化是,使用 I2C 时,您必须在发送数据时指定地址,而使用 SPI 时则不需要(但请记住,如果您连接了多个设备,您需要指定地址)需要切换 CS GPIO 以选择适当的设备)。 | ||
- | 那么,如果它们如此相似,您在构建项目时应该选择哪种协议?有几个因素需要考虑。首先是您要附加的东西的可用性。有时传感器只能用作 I2C 或 SPI,因此您必须使用它。然而,如果你有选择 | ||
- | 在硬件方面,当您使用多个额外设备时,影响最大。使用 I2C,您最多可以将 128 个设备连接到单个 I2C 总线;但是,它们都需要有一个单独的地址。这些地址是硬接线的。有时可以通过可焊接(或可切割)连接来更改地址,但有时则不然。如果您想拥有多个相同类型的传感器(例如,如果您在项目的多个点监测温度),您可能会受到传感器 I2C 地址数量的限制。在这种情况下,SPI 可能是更好的选择。 | ||
- | 或者,SPI可以连接无限数量的设备;但是,每个人都必须有自己的 CS 线。在 Pico 上,有 26 个 GPIO 引脚。您需要其中三个用于 SPI 总线,这意味着有 23 个可用于 CS 线。这是假设您不需要任何其他东西。如果可用的 GPIO 非常珍贵,那么您可能需要查看 I2C。 | + | 如您所见,I2C和SPI之间的代码差异非常小。设置好所有内容后,唯一真正的变化是,使用I2C时,您必须在发送数据时指定地址,而使用SPI时则不需要(但请记住,如果您连接了多个设备,您需要指定地址)需要切换CS GPIO以选择适当的设备)。 |
+ | |||
+ | 那么,如果它们如此相似,您在构建项目时应该选择哪种协议?有几个因素需要考虑。首先是您要附加的东西的可用性。有时传感器只能用作I2C或SPI,因此您必须使用它。然而,如果你有选择在硬件方面,当您使用多个额外设备时,影响最大。使用I2C,您最多可以将128个设备连接到单个I2C总线;但是,它们都需要有一个单独的地址。这些地址是硬接线的。有时可以通过可焊接(或可切割)连接来更改地址,但有时则不然。如果您想拥有多个相同类型的传感器(例如,如果您在项目的多个点监测温度),您可能会受到传感器I2C地址数量的限制。在这种情况下,SPI可能是更好的选择。 | ||
+ | |||
+ | 或者,SPI可以连接无限数量的设备;但是,每个人都必须有自己的CS线。在Pico上,有26个GPIO引脚。您需要其中三个用于SPI总线,这意味着有23个可用于CS线。这是假设您不需要任何其他东西。如果可用的GPIO非常珍贵,那么您可能需要查看I2C。 | ||
实际上,对于许多项目,您可以很高兴地使用任一协议,并且您可能会发现选择使用哪个协议更多地与您在零件盒中找到的零件有关,而不是两者之间的技术差异。 | 实际上,对于许多项目,您可以很高兴地使用任一协议,并且您可能会发现选择使用哪个协议更多地与您在零件盒中找到的零件有关,而不是两者之间的技术差异。 | ||
行 128: | 行 136: | ||
**比特敲打** | **比特敲打** | ||
- | 您的 Pico 有两条硬件 I2C 总线和两条硬件 SPI 总线。 但是,如果您愿意,您可以使用更多。 I2C 和 SPI 都可以用软件而不是硬件来实现。 这意味着主处理核心处理通信协议,而不是微控制器的专用位。 这是众所周知的 | + | 您的Pico有两条硬件I2C总线和两条硬件SPI总线。 但是,如果您愿意,您可以使用更多。 I2C和SPI 都可以用软件而不是硬件来实现。 这意味着主处理核心处理通信协议,而不是微控制器的专用位。 这是众所周知的 |
作为'位砰砰'。 虽然它很有用,但与使用专用硬件相比,它会给您的处理器内核带来更多压力,并且您可能会发现无法达到高波特率。 | 作为'位砰砰'。 虽然它很有用,但与使用专用硬件相比,它会给您的处理器内核带来更多压力,并且您可能会发现无法达到高波特率。 | ||
- | Pico 有一个技巧——PIO。 我们将在本书后面(附录 C)更仔细地研究这一点,但它是微控制器中的额外硬件,可以专用于 I2C 和 SPI 等输入/输出协议。 使用 PIO,您可以创建额外的 I2C 或 SPI 总线,而不会增加主处理器内核的负担。 | + | Pico有一个技巧——PIO。 我们将在本书后面(附录 C)更仔细地研究这一点,但它是微控制器中的额外硬件,可以专用于I2C和SPI等输入/输出协议。 使用PIO,您可以创建额外的I2C或SPI总线,而不会增加主处理器内核的负担。 |
</WRAP> | </WRAP> | ||
+ | |||
+ | ### 3. MMA7660姿态传感器信息获取 | ||
+ | #### 扫描I2C总线获取设备的信息 | ||
+ | |||
+ | <code python> | ||
+ | # Scanner i2c en MicroPython | MicroPython i2c scanner | ||
+ | # Renvoi l'adresse en decimal et hexa de chaque device connecte sur le bus i2c | ||
+ | # Return decimal and hexa adress of each i2c device | ||
+ | # https://projetsdiy.fr - https://diyprojects.io (dec. 2017) | ||
+ | |||
+ | import machine | ||
+ | i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4)) | ||
+ | |||
+ | print('Scan i2c bus...') | ||
+ | devices = i2c.scan() | ||
+ | |||
+ | if len(devices) == 0: | ||
+ | print("No i2c device !") | ||
+ | else: | ||
+ | print('i2c devices found:',len(devices)) | ||
+ | |||
+ | for device in devices: | ||
+ | print("Decimal address: ",device," | Hexa address: ",hex(device)) | ||
+ | </code> | ||
+ | |||
+ | |||
+ | #### 读取测量的数据 | ||
+ | <code python> | ||
+ | import machine, time, bme280 | ||
+ | i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(18)) | ||
+ | bme = bme280.BME280(i2c=i2c,address=0x76) | ||
+ | while True: | ||
+ | print("BME280 values:") | ||
+ | temp,pa,hum = bme.values | ||
+ | print(temp) | ||
+ | print(pa) | ||
+ | print(hum) | ||
+ | time.sleep_ms(2000) | ||
+ | </code> | ||
+ | |||
+ | #### 显示读取的数据 | ||
+ | <code> | ||
+ | import machine, ssd1306 | ||
+ | i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(18)) | ||
+ | oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3c) | ||
+ | oled.fill(0) | ||
+ | oled.text("Hello World", 0, 0) | ||
+ | oled.show() | ||
+ | </code> | ||