跳转到内容

Hempl/PWM

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

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

在设置PWM输出时,您指定输出的频率(每秒高低变化的次数)及其占空比(每个周期中多少百分比的时间处于高电平输出)。

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

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

最后,PWM系统可以通过启用PWM中断来用于以固定的时间间隔生成中断。这样,每当PWM输出的一个周期完成时,处理器就会停止它正在做的事情,运行一个称为中断例程的特殊代码片段,然后完成后,它将返回继续中断发生之前正在做的事情。尽管硬件能够做到这一点,但PWM中断在Hempl中尚未实现。请参阅issue #5

硬件视图

[编辑 | 编辑源代码]

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

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

软件视图

[编辑 | 编辑源代码]

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

PWM6不可供用户使用,因为它被内部用于提供系统计时器(PicoLisp中的*tmr-sys-timer*)。

输出频率和占空比

[编辑 | 编辑源代码]

使用两个函数来获得引脚上的某些PWM输出。

(pwm-setup channel frequency duty_cycle)

设置输出频率和占空比,其中channel(从0到6)是要使用的PWM通道,frequency(从1到1000000)确定输出波形的频率,单位为每秒周期数,duty_cycle(值从0到100)确定每个周期中波形输出值处于高电平状态的百分比。

(pwm-start channel)

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

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

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

当调用stop时,PWM输出始终完成当前周期;“停止”状态意味着当当前周期完成后,它将不会开始一个新的周期,因此您可以通过这种方式获得一个完整的输出周期

在PicoLisp中

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

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

时钟频率

[编辑 | 编辑源代码]

另一个函数

(pwm-setclock id freq)

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

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

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

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

PWM输出频率的范围和精度

[编辑 | 编辑源代码]

在Hempl中,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 输出的引脚完全停止输出电压,也可以使用此方法:您将调用

(pio-pin-setdir *pio-input* 'PB_xx)

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

示例代码

[编辑 | 编辑源代码]
# 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) ) )

进一步阅读

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