跳转到内容

Mizar32/PWM

来自维基教科书,开放的书籍,开放的世界
Mizar32 PWM LED 衰减器示例电路

PWM 代表脉冲宽度调制,它是一种生成不同频率的方波输出信号的方法,并且每个波形周期的不同比例是低输出或高输出。

当您设置 PWM 输出时,您指定输出的频率(每秒高低变化的次数)及其占空比(每个周期中花费在高输出上的百分比)。

PWM 输出最常见的用法是使用固定频率并改变占空比,从而创建一个粗略的数字到模拟转换器来控制光的亮度或电机提供的功率。如果输出信号被放大以控制大功率设备,这将导致更有效的系统,因为如果放大器全功率开启一半时间,全功率关闭另一半时间,这比始终以半功率开启浪费的能量少。

另一种用途是通过使用固定占空比并改变频率来生成简单的音效或风琴音符,以生成具有方波波形的音效。在这种情况下,改变占空比会改变产生的声音的音调。

最后,PWM 系统可以通过使能 PWM 中断来生成固定时间间隔的中断。这样,每完成一次 PWM 输出周期,处理器就会停止当前的操作,运行一段称为中断例程的特殊代码,完成后,它会回到中断发生之前继续执行它正在做的事情。虽然硬件能够做到这一点,但 eLua 中尚未实现 PWM 中断。

硬件视图

[编辑 | 编辑源代码]

Mizar32 有七个独立的 PWM 输出,虽然在电路图中只标注了 PWM0 到 PWM5。如果启用 PWM6,它将出现在标注为“GPIO50”的引脚上。

总线引脚
PWM AVR32 引脚 总线引脚 eLua 名称 PicoLisp 备注
PWM0 PB19 BUS4 引脚 7 pio.PB_19 'PB_19
PWM1 PB20 BUS4 引脚 8 pio.PB_20 'PB_20 也连接到 JTAG 引脚 7“EVT0”
PWM2 PB21 BUS1 引脚 8 pio.PB_21 'PB_21
PWM3 PB22 BUS6 引脚 1 pio.PB_22 'PB_22
PWM4 PB27 BUS6 引脚 2 pio.PB_27 'PB_27
PWM5 PB28 BUS6 引脚 3 pio.PB_28 'PB_28
PWM6 PB18 BUS5 引脚 9 pio.PB_18 'PB_18 在 Mizar32 总线上,该引脚称为“GPIO50”

软件视图

[编辑 | 编辑源代码]

Alcor6L 的 PWM 模块 用于编程 PWM 引脚。

PWM6 不可用作用户,因为它在内部用于提供系统定时器(eLua 中的 tmr.SYS_TIMER,PicoLisp 中的 *tmr-sys-timer*)。

输出频率和占空比

[编辑 | 编辑源代码]

两个函数用于在引脚上获得一些 PWM 输出。

语言 示例
eLua pwm.setup(channel, frequency, duty_cycle)
PicoLisp (pwm-setup channel frequency duty_cycle)

设置输出频率和占空比,其中 channel(从 0 到 6)是您要使用的 PWM 通道,frequency(从 1 到 1000000)确定输出波形的频率(以每秒周期计),duty_cycle(从 0 到 100 的值)确定波形输出值的每个周期中花费在高电平上的百分比。

语言 示例
eLua pwm.start(channel)
PicoLisp (pwm-start channel)

设置振荡器运行以产生循环输出波形。

如果在调用 start() 函数之前调用了 setup() 函数,正如我们刚才描述的那样,总线上的相应引脚将变为输出引脚,在 setup 完成时输出 0 伏,然后,当调用 start() 时,输出波形变为高电平,保持高电平一段时间,该时间占周期的指定百分比,然后在周期的剩余时间变为低电平,重复此过程,直到对同一通道调用 stop() 为止。

或者,如果先调用 start(),则该引脚将保持为输入状态,直到调用 setup(),此时它将变为输出状态并开始产生波形。

当调用 stop() 时,PWM 输出总是完成当前周期;“停止”状态意味着当当前周期完成时,它不会开始一个新的周期,因此您可以像这样获得恰好一个完整的输出周期

在 eLua 中

pwm.setup(0, 10, 50)
pwm.start(0)
pwm.stop(0)

在 PicoLisp 中

(pwm-setup 0 10 50)
(pwm-start 0)
(pwm-stop 0)

此程序代码将在整个周期输出完成之前完成,请注意,当它“停止”时,该引脚将继续输出 0 伏。

时钟频率

[编辑 | 编辑源代码]

另一个函数

语言 示例
eLua pwm.setclock(id, freq)
PicoLisp (pwm-setclock id freq)

允许您设置 PWM 时钟频率,该频率高于输出频率,并确定输出波形的时间粒度。实际上,PWM 硬件只在每 1/freq 秒内决定是否更改每个 PWM 引脚的输出值一次,因此更高的时钟频率在时间和频率方面提供更好的精度。

PWM 时钟频率也决定了 PWM 输出波形的最低和最高可能频率:较低的时钟频率允许输出频率更低。

Mizar32 上的时钟频率可能的取值为 63Hz 到 16500000Hz。如果您要求超出此范围的值,它将相应地设置这两个值中的最低值或最高值。在此范围内,并非所有频率都可用;在可用的频率中,它将设置最接近您要求的频率,并且 setclock()getclock() 都返回一个整数,该整数是实际设置为 PWM 时钟的频率。

虽然 Alcor6L 的 setclock()getclock() 函数接受第一个参数来指定要设置时钟的通道,但实际上硬件只有一个用于所有通道的时钟,因此设置任何一个通道的时钟频率将改变所有通道的时钟频率,以及改变任何正在运行的通道的当前输出频率。因此,setclock() 通常只在设置各个通道之前调用一次。

PWM 输出频率的范围和精度

[编辑 | 编辑源代码]

在 Alcor6L 中,setup() 函数的参数只关注数字的整数部分,忽略任何小数部分,因此您可以要求的最低频率为每秒一个周期,最大精度为一赫兹。

此外,硬件只能生成某些频率(时钟频率的精确除数),并且 setup() 返回一个整数,该整数是设置的实际输出频率的整数部分的最近似值,这可能与您要求的频率不同。

例如,在默认时钟频率为 1 兆赫兹的情况下,您可以设置从 1 到 1037 的任何整数频率,但 1038 会得到 1039,然后越来越多的值变得越来越不准确,直到我们来到最高可用的频率 250000Hz、333333Hz、500000Hz 和 1000000Hz,它们是时钟频率分别除以 4、3、2 和 1 的结果。

相反,在最高时钟速率为 16500000Hz 的情况下,可以获得从 16Hz 到 4105Hz 的每个整数频率,并且在这个频率之上,可以获得更广泛的值范围,这更适合诸如电子管风琴之类的应用,在这种应用中,高音符频率的准确性比产生极低音符更重要。

使用 PWM 引脚作为 PIO 引脚

[编辑 | 编辑源代码]

如果特定 PWM 输出没有用于 PWM 输出,您可以通过在该引脚上调用 pio 模块中的函数来将其用作通用 PIO 引脚。

如果您希望之前用于 PWM 输出的引脚完全停止输出电压,您也可以使用此方法:您将调用

语言 示例
eLua pio.pin.setdir(pio.INPUT, pio.PB_xx)
PicoLisp (pio-pin-setdir *pio-input* 'PB_xx)

其中 xx 是上述表格中该 PWM 通道的引脚编号。

示例代码 (eLua)

[编辑 | 编辑源代码]
-- Make a LED slowly fade up and down forever

-- Connect a LED in series with a
-- 330 ohm resistor between the PWM0 pin
-- (BUS4 pin 7) and GND (BUS4 pin 1)

local pwmid = 0     -- Which channel to use?
local speed = 3000  -- PWM frequency in Hz
local fadetime = 1  -- How many secs to fade up?
local tmrid = 0     -- Which timer for the delay?
local nsteps = 100  -- How many steps in the fade? 

-- Calculate the delay for each steps, in microseconds
local delay = pwm.getclock( tmrid ) * fadetime / nsteps

pwm.start( pwmid )

while true do
  -- Fade the LED up
  for duty = 0, nsteps do
    pwm.setup( pwmid, speed, duty )
    tmr.delay( tmrid, delay )
  end

  -- Fade the LED back down again
  for duty = nsteps, 0, -1 do
    pwm.setup( pwmid, speed, duty )
    tmr.delay( tmrid, delay )
  end
end

示例代码 (PicoLisp)

[编辑 | 编辑源代码]
# Make the LED slowly fade up and down forever

# Connect a LED in series with a
# 330 ohm resistor between PWM0 pin
# (BUS4 pin 7) and GND (BUS4 pin 1)

(setq
   pwmid 0 # Which channel to use?
   speed 3000 # PWM frequency in Hz
   fadetime 1 # How many secs to fade up?
   nsteps 100 ) # How many steps in the fade?

(setq delay (/ (* (pwm-getclock tmrid) fadetime)
               nsteps ) )

(pwm-start pwmid)

(loop
   # Fade the LED up
   (for duty nsteps
      (pwm-setup pwmid speed duty)
      (tmr-delay *tmr-sys-timer* delay) )
   
   # Fade the LED down
   (for (i nsteps (ge0 i) (dec i))
      (pwm-setup pwmid speed i)
      (tmr-delay *tmr-sys-timer* delay) ) )

进一步阅读

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