跳转到内容

Hempl/PIO

来自维基教科书,开放世界中的开放书籍

PIO 代表可编程输入/输出,这是控制和测量连接到总线连接器的 AVR32 处理器引脚上的数字电压电平的最简单方法。

要将 GPIO 引脚用作 PIO,您必须首先将引脚设置为输入或输出。如果将其设置为输入,则可以检查输入电压以查看它是否具有传入的低电平或高电平,例如检查开关的位置。如果将其设置为输出,则可以对其编程以输出低电压或高电压以控制灯光、电机或其他电路。

对于作为输入的 PIO 引脚,您还可以要求当该引脚上的电压从 0 变为 1 或从 1 变为 0 时,这将产生一个中断。发生这种情况时,处理器将停止其正在执行的操作,运行一个称为中断例程的特殊代码段,并在完成该操作后,它将返回并继续其在中断发生时正在执行的操作。

最后,每个引脚都有一个可选的上拉电阻,可以启用它,以便如果没有任何东西连接到作为输入的引脚,它将浮动到逻辑“1”而不是随机波动。这是连接开关或按钮的常用方法:您在引脚上编程一个上拉电阻,然后将开关连接到引脚和零伏之间,以便当触点闭合时,您将读取 0 的值,而当触点打开时,您将读取 1 的值。

硬件视图

[编辑 | 编辑源代码]

AT32UC3A 芯片的任何外设引脚都可以读取为数字输入或设置为输出,并编程为 0 或 1 逻辑电平。

当引脚设置为输出时,0 逻辑输出将引脚连接到 0 伏,而逻辑 1(“高”)值将 3.3 伏放在它上面,两种状态的最大电流供应或消耗为 4 毫安。

当它们被设置为输入时,从 0.0 到 0.8 伏的电压电平读取为“0”(低)输入,而从 2.0 伏到 5.0 伏的电压电平读取为“1”(高)输入。从 0.8 到 2.0 伏的值可能读取为高或低,不确定。

Mizar32 的一些引脚只能用作可编程 I/O 引脚,因为它们没有用于其他任何用途。其他引脚将信号传送到各种外围设备,但是,如果这些设备没有被使用,则可以使用这些引脚作为 PIO 引脚。

其他引脚对于处理器的正常运行至关重要,例如用于访问 SDRAM、振荡器和其他板载电路的那些引脚;如果您将它们用作 PIO 引脚,则板很可能会崩溃,需要按下其复位按钮。

专用 PIO 引脚

[编辑 | 编辑源代码]
引脚 名称 总线引脚 PicoLisp
PA2 GPIO2 BUS5 引脚 11 'PA_2
PA7 GPIO7 BUS5 引脚 12 'PA_7
PB17 GPIO49 BUS5 引脚 8 'PB_17
PB18 GPIO50 BUS5 引脚 9 'PB_18
PB29 GPIO61 板载 LED 'PB_29
PB30 GPIO62 BUS6 引脚 9 'PB_30
PB31 GPIO63 BUS6 引脚 10 'PB_31
PX16 GPIO88 用户按钮 'PX_16
PX19 GPIO85 BUS6 引脚 12 'PX_19
PX22 GPIO82 BUS6 引脚 11 'PX_22
PX33 GPIO71 BUS5 引脚 10 'PX_33

可选 PIO 引脚

[编辑 | 编辑源代码]

未使用的 ADCPWMSPIUART 引脚也可以用作 PIO 引脚。有关相关引脚名称,请参见这些部分。这将可用的 PIO 总数增加到 66 个。

软件视图

[编辑 | 编辑源代码]

PIO Hempl 模块允许您将任何引脚设置为逻辑输入或将其设置为输出,并在其上放置 0v 或 3.3V,并且您可以在任何引脚上启用上拉电阻。

将引脚驱动为输出

[编辑 | 编辑源代码]

此示例点亮板载 LED。

来自 PicoLisp

(setq led 'PB_29)
(pio-pin-setdir *pio-output* led)
(pio-pin-setlow led)

请注意,在复位后,LED 在第 2 行亮起,因为复位状态是所有引脚都为低电平,并且当信号为低电平时,板载 LED 亮起。要设置一个初始值为高的输出引脚,您需要在调用 pio.pin.setdir() 之前调用 pio.pin.sethigh()

读取引脚上的电压作为输入

[编辑 | 编辑源代码]

这是一个读取一个 PIO 引脚并驱动另一个引脚以响应它的示例。我们将读取连接到板载用户按钮的引脚,并且只要按下该按钮,我们就将使板载 LED 闪烁。在 PicoLisp 中,以下是如何操作。

# A simple program which demonstrates
# the usage of user-buttons.
 
# declare pins
(setq led 'PB_29 button 'PX_16)

# a simple delay function
(de delay (t)
   (tmr-delay 0 t) )

# make sure the LED starts in
# the "off" position and enable
# input/output pins
(de init-pins ()
   (pio-pin-sethigh led)
   (pio-pin-setdir *pio-output* led)
   (pio-pin-setdir *pio-input* button) )

# And now, the main loop
(de prog-loop ()
   (init-pins)
   (loop
      (if (= 0 (pio-pin-getval button))
          (prog (pio-pin-setlow led)
                (delay 100000)
                (pio-pin-sethigh led)
                (delay 100000) ) ) ) )

(prog-loop)

可编程上拉电阻

[编辑 | 编辑源代码]

用户按钮的电路非常简单:按下按钮时,它将 PIO 引脚连接到零伏,提供低输入值,并且在 PIO 引脚和 3.3 伏之间有一个电阻,以便如果按钮没有被按下,PIO 引脚将轻轻地拉到 3.3V 并读取为高值。

其他未连接到任何东西的 PIO 引脚,如果您将它们编程为输入,将拾取周围环境的随机噪声,并给出有时为高有时为低的值。可编程上拉电阻是一种确保如果没有任何信号连接到输入引脚,它将被轻轻地拉到高值而不是随机漂浮的方法。

此示例将一个未使用的 GPIO 引脚转换为 PIO 输入,但确保如果没有任何东西物理连接到它,它将始终返回高值 1

如果您从以下代码中删除 (pio-pin-setpull) 行(至少在我的测试板上),它会打印大部分为零,但如果您触摸 Mizar32 板的底部,则值会在 0 和 1 之间闪烁。包含 (pio-pin-setpull) 行,除非您用一段电线将其连接到 GND 引脚(例如 BUS5 引脚 14),否则输入值始终为 1。

在 PicoLisp 中

(setq pin 'PA_2) # Stabilize GPIO2 (connector BUS5 pin 11)
(pio-pin-setdir *pio-input* pin)
(pio-pin-setpull *pio-pullup* pin)
(loop
   (prinl (pio-pin-getval pin)) )

虽然 Hempl 也有类似的原始函数 PULLDOWN,但 Mizar32 中使用的 AVR32 芯片在其硬件中没有可编程下拉电阻,因此使用它会引发错误消息。

要再次禁用上拉电阻,您可以使用

(pio-pin-setpull pin *pio-nopull*)

开集输出

[编辑 | 编辑源代码]

可编程上拉电阻的另一个用途是实现“开集输出”。在这种方案中,引脚可以处于两种状态之一:要么它被驱动为 0 输出,要么它被读取为输入。上拉电阻确保如果没有人将其驱动为输出,每个人都会将其读取为高值。当多台计算机需要通过一根信号线进行通信,并且任何一台计算机都可以与任何其他计算机通信,而无需主从关系或协商谁控制总线的方式时,就会使用它。使用这种系统,任何计算机都可以读取电线以查看其值是高还是低,任何计算机都可以将电线驱动到低值,以便所有其他计算机读取它。这与将电线驱动为高或低输出不同,因为如果一台计算机将其驱动为高,而另一台计算机将其驱动为低,则可能会损坏相关计算机,并且肯定会导致通信混乱。

一个简单的例子是,一个系统可以通过多个开关单元中的任何一个来打开或关闭房屋的灯光。而 I2C 总线是一个更高级的例子,它在信号线上使用开集输出,这样 I2C 总线上的任何一台计算机都可以与任何其他计算机通信,而不会在总线线上产生冲突的信号。

以下代码在 PIO 引脚上实现了一个开集输出,提供了一个函数将其配置为 OC 引脚,一个函数将其驱动为低输出,还有一个函数将其设置为输入并告诉你此时导线上是什么值。

在 PicoLisp 中

# Turn a PIO pin into an open-collector output.
# Call this function once before using the other
# two to drive and read the pin.

(de oc-setup (pin)
  # OC output starts as an input, not driving
  # the bus wire
  (pio-pin-setdir *pio-input* pin)

  # Arrange that, when it is an input and no
  # one is driving it, it will float high
  (pio-pin-setpull *pio-pullup* pin)

  # and that when we set it as an output, it will drive a low value
  (pio-pin-setlow pin) )

# Drive a low output value onto the pin.
# The low output value is already programmed during setup()
# so we only need to enable it as an output.
(de oc-drive-low (pin)
  (pio-pin-setdir *pio-output* pin) )

# Make the pin an input and return the value on the bus wire
(de oc-read (pin)
  (pio-pin-setdir *pio-input* pin)
  (pio-pin-getval pin) )

请注意:目前 PicoLisp 不支持中断处理。请参阅 问题 #2

解码引脚编号

[编辑 | 编辑源代码]

'PB_29 这样的符号会返回 Hempl 内部用来识别 GPIO 引脚的数字。除了在一种情况下,你不需要知道这些数字的值:当你同时从 Hempl 在不同的 GPIO 引脚上启用了多个边沿触发中断。

如果你想将像 'PB_29 这样的符号解码为端口号和引脚号,你可以使用

(pio-decode 'PB_29)

结果是一个列表。它的 car 给出端口号,它的 cadr 给出引脚号。

对于端口 A 上的引脚,port 将为 0pin 将为 0 到 31 之间的数字。
对于端口 B 上的引脚,port 将为 1pin 将为 0 到 31 之间的数字。
对于端口 C 上的引脚,port 将为 2pin 将为 0 到 5 之间的数字。
对于端口 X 上的引脚,port 将为 23pin 将为 0 到 39 之间的数字。

进一步阅读

[编辑 | 编辑源代码]
华夏公益教科书