差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
mp_ws2812b [2021/10/07 22:14] gongyusu |
mp_ws2812b [2021/10/07 23:36] (当前版本) gongyusu [2. 一个真实的例子] |
||
---|---|---|---|
行 14: | 行 14: | ||
### 1. 数据输入和数据输出 | ### 1. 数据输入和数据输出 | ||
- | 在本书中,我们讨论了使用MicroPython控制Pico上的引脚的方法。我们可以使用专用的SPI和I2C控制器打开和关闭它们,获取输入,甚至发送数据。然而,如果我们想要连接一个不使用SPI或I2C通信的设备,该怎么办?如果它有自己的特殊协议呢? | + | 在本书中,我们讨论了使用MicroPython控制Pico上的引脚的方法。我们可以使用专用的SPI和I2C控制器打开和关闭它们,获取输入,甚至发送数据。然而,如果我们想要连接一个不使用SPI或I2C通信的设备,该怎么办? 如果它有自己的特殊协议呢? |
有几种方法可以做到这一点。在大多数MicroPython设备上,你需要做一个叫做“位敲打”的过程,在这个过程中你在MicroPython中实现协议。使用此功能,您可以按正确的顺序打开或关闭引脚以发送数据。 | 有几种方法可以做到这一点。在大多数MicroPython设备上,你需要做一个叫做“位敲打”的过程,在这个过程中你在MicroPython中实现协议。使用此功能,您可以按正确的顺序打开或关闭引脚以发送数据。 | ||
- | 这样做有三个缺点。首先是它的速度很慢。MicroPython在某些方面做得非常好,但它的运行速度不如本地编译的代码快。 | + | 这样做有三个缺点。 |
+ | * 首先是它的速度很慢。MicroPython在某些方面做得非常好,但它的运行速度不如本地编译的代码快。 | ||
+ | * 第二,我们必须把这个和在微控制器上运行的其他代码混在一起。 | ||
+ | * 第三,一些时间关键的代码可能很难可靠地实现。快速协议可能需要事情在非常精确的时间发生,而使用MicroPython,我们可以非常精确,但如果你试图每秒传输兆比特,你需要事情每毫秒或可能每几百纳秒发生、这在MicroPython中很难可靠地实现。 | ||
- | 第二,我们必须把这个和在微控制器上运行的其他代码混在一起。 | + | Pico对此有一个解决方案:可编程I/O。有一些额外的、真正剥离的处理核心,可以运行简单的程序来控制IO引脚。你不能用MicroPython对这些核心进行编程,你必须为它们使用一种特殊的语言,但你可以从MicroPython中对它们进行编程。让我们来看一个例子: |
- | + | ||
- | 第三,一些时间关键的代码可能很难可靠地实现。快速协议可能需要事情在非常精确的时间发生,而使用MicroPython,我们可以非常精确,但如果你试图每秒传输兆比特,你需要事情每毫秒或可能每几百纳秒发生。这在MicroPython中很难可靠地实现。 | + | |
- | + | ||
- | Pico对此有一个解决方案:可编程I/O。有一些额外的,真正剥离的处理核心,可以运行简单的程序来控制IO引脚。你不能用MicroPython对这些核心进行编程——你必须为它们使用一种特殊的语言——但你可以从MicroPython对它们进行编程。让我们来看一个例子 | + | |
<code python> | <code python> | ||
from rp2 import PIO, StateMachine, asm_pio | from rp2 import PIO, StateMachine, asm_pio | ||
行 63: | 行 62: | ||
</code> | </code> | ||
- | 这里有三种方法,看起来都有点奇怪,但将板载LED设置为四分之一、一半和全亮度。它们看起来有点奇怪的原因是它们是用一种特殊的语言为Pico的PIO系统编写的。你大概可以猜到它们是做什么的- 以一种类似于我们如何使用PWM的方式快速打开和关闭LED。指令: | + | 这里有三种方法,看起来都有点奇怪,但将板载LED设置为四分之一、一半和全亮度。它们看起来有点奇怪的原因是它们是用一种特殊的语言为Pico的PIO系统编写的。你大概可以猜到它们是做什么的,以一种类似于我们如何使用PWM的方式快速打开和关闭LED。指令: |
* set(pins,0) 关闭GPIO引脚 | * set(pins,0) 关闭GPIO引脚 | ||
* set(pins,1) 打开GPIO引脚。 | * set(pins,1) 打开GPIO引脚。 | ||
行 87: | 行 86: | ||
### 2. 一个真实的例子 | ### 2. 一个真实的例子 | ||
- | 前面的示例有点做作,所以让我们通过一个实际示例来看看使用PIO的方法。WS2812B led(有时也被称为NeoPixels)是一种包含三个led(一个红、一个绿、一个蓝)和一个小微控制器的光。它们是由一根数据线控制的,该数据线有一个时间依赖协议,很难对数据进行实时控制。 | + | 前面的示例有点做作,所以让我们通过一个实际示例来看看使用PIO的方法。WS2812B led(有时也被称为NeoPixels)是一种包含三个led(一个红、一个绿、一个蓝)和一个小微控制器的发光管。它们是由一根数据线控制的,该数据线有一个时间依赖协议,很难对数据进行实时控制。 |
- | LED条的布线很简单,如图C-1所示。取决于你的LED带的制造商,你可能已经有电线连接,你可能有一个插座,你可以推动头部电线,或你可能需要焊接他们自己。 | + | |
- | + | ||
- | 你需要知道的一件事是潜在的电流吸引。虽然你可以在你的Pico上添加几乎无穷无尽的新像素系列,但你可以从Pico上的5v引脚获得的功率是有限的。在这里,我们将使用8个led,这是非常安全的,但如果你想使用更多的led,你需要了解其局限性,可能需要添加一个单独的电源。你可以把长条切成长度,led之间应该有切线,告诉你在哪里切。在hsmag.cc/neopixelpower上有关于各种问题的很好的讨论。 | + | |
- | 现在我们已经把led连接起来了,让我们看看如何用PIO来控制它: | + | 让我们看看如何用PIO来控制它: |
<code python> | <code python> | ||
import array, utime | import array, utime | ||
行 100: | 行 96: | ||
# Configure the number of WS2812 LEDs. | # Configure the number of WS2812 LEDs. | ||
- | NUM_LEDS = 10 | + | NUM_LEDS = 12 |
@asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) | @asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT, autopull=True, pull_thresh=24) | ||
行 106: | 行 102: | ||
T1 = 2 | T1 = 2 | ||
T2 = 5 | T2 = 5 | ||
- | T3 = 3 label("bitloop") | + | T3 = 3 |
+ | label("bitloop") | ||
out(x, 1) .side(0) [T3 - 1] | out(x, 1) .side(0) [T3 - 1] | ||
jmp(not_x, "do_zero") .side(1) [T1 - 1] | jmp(not_x, "do_zero") .side(1) [T1 - 1] | ||
行 121: | 行 118: | ||
</code> | </code> | ||
- | 数据进入状态机有两个阶段。第一个是称为先进先出(FIFO)的存储器。这是我们的主Python程序发送数据的地方。第二个是输出移位寄存器(OSR)。这是out()指令获取数据的地方。这两个是由pull指令连接的,从FIFO取数据,并把它放在OSR。然而,由于我们的程序设置autopull启用阈值为24,每次我们从OSR读取24位,它将从FIFO重新加载。 | + | 数据进入状态机有两个阶段。第一个是称为先进先出(FIFO)的存储器。这是我们的主Python程序发送数据的地方。第二个是输出移位寄存器(OSR),这是out()指令获取数据的地方。这两个是由pull指令连接的,从FIFO取数据,并把它放在OSR。然而,由于我们的程序设置autopull启用阈值为24,每次我们从OSR读取24位,它将从FIFO重新加载。 |
指令out(x,1)从OSR获取一位数据,并将其放入名为x的变量中(在PIO中只有两个可用变量:x和y)。 | 指令out(x,1)从OSR获取一位数据,并将其放入名为x的变量中(在PIO中只有两个可用变量:x和y)。 | ||
行 195: | 行 192: | ||
用于PIO状态机的语言非常稀疏,因此只有少量的指令。除了我们已经看过的,你还可以使用: | 用于PIO状态机的语言非常稀疏,因此只有少量的指令。除了我们已经看过的,你还可以使用: | ||
- | * In() -在状态机中移动1到32位(类似于out(),但相反)。Push() -将数据发送到连接状态机和主机的内存中MicroPython程序。 | + | * In( ) -在状态机中移动1到32位(类似于out(),但相反)。Push() -将数据发送到连接状态机和主机的内存中MicroPython程序。 |
- | * pull() -从连接状态机和主MicroPython程序的内存块中获取数据。这里我们没有使用它,因为在我们的程序中包含了autopull=True,当我们使用out()时,它会自动发生。 | + | * pull( ) -从连接状态机和主MicroPython程序的内存块中获取数据。这里我们没有使用它,因为在我们的程序中包含了autopull=True,当我们使用out()时,它会自动发生。 |
- | * Mov() -在两个位置之间移动数据(例如x和y变量)。 | + | * Mov( ) -在两个位置之间移动数据(例如x和y变量)。 |
- | * Irq()——控制中断。如果您需要在程序的MicroPython端触发一个特定的东西来运行,则使用这些。 | + | * Irq( )——控制中断。如果您需要在程序的MicroPython端触发一个特定的东西来运行,则使用这些。 |
- | * wait() -暂停,直到某件事发生(例如IO引脚改变为设定值或中断发生)。 | + | * wait( ) -暂停,直到某件事发生(例如IO引脚改变为设定值或中断发生)。 |
<WRAP center round tip 60%> | <WRAP center round tip 60%> |