zoukankan      html  css  js  c++  java
  • 张高兴的 .NET Core IoT 入门指南:(五)PWM 信号输出

    什么是 PWM

    在解释 PWM 之前首先来了解一下电路中信号的概念,其中包括模拟信号和数字信号。模拟信号是一种连续的信号,与连续函数类似,在图形上表现为一条不间断的连续曲线。数字信号为只能取有限个数值的信号,比如计算机中的高电平(1)和低电平(0)。

    PWM(Pulse Width Modulation)即脉冲宽度调制,简称脉宽调制,通过对一系列的脉冲的宽度进行调制,从而等效出所需要的模拟信号。如图 1 所示,蓝色波形为调制的一系列脉冲,红色波形为模拟的正弦样信号。在模拟电路中,模拟信号的值可以连续进行变化,而数字电路是在高电平和低电平中取值,所以电压或电流会以脉冲的形式出现。通过使用 PWM 技术,我们可以在数字电路中模拟出电信号的连续变化。

    图1:PWM 示意图

      提示

    看完上面的如果你还不明白,那么可以看看下面这个生动的解释,这个解释来源于百度知道

    “简单的说,比如你有5V电源,要控制一台灯的亮度,有一个传统办法,就是串联一个可调电阻,改变电阻,灯的亮度就会改变。还有一个办法,就是PWM调节。不用串联电阻,而是串联一个开关。假设在1秒内,有0.5秒的时间开关是打开的,0.5秒关闭,那么灯就亮0.5秒,灭0.5秒。这样持续下去,灯就会闪烁。如果把频率调高一点,比如是1毫秒,0.5毫秒开,0.5毫秒灭,那么灯的闪烁频率就很高。我们知道,闪烁频率超过一定值,人眼就会感觉不到。所以,这时你看不到灯的闪烁,只看到灯的亮度只有原来的一半。同理,如果1毫秒内,0.1毫秒开,0.9毫秒灭,那么,灯的亮度就只有原来的10分之一。”

    使用 PWM 需要了解占空比(Duty Cycle)和频率(Frequency)的概念。占空比即 PWM 信号在一个周期内处于高电平的时间与整个周期的时间的比值。在 5V 电源的情况下,想要产生一个 3V 的信号,可以使用占空比为 60% 的 PWM。图 2 从波形的角度解释了 PWM。频率是 PWM 信号在 1 秒内完成一个周期的次数,单位是 Hz。如果输出的频率够高并保持一定的占空比,就可以模拟出恒定电压。图 3 对比了小灯亮度的变化与占空比的变化,通过观察图右侧的 PWM 波形可以看到占空比越高小灯越亮。

    图2:占空比示意图

    图3:小灯亮度变化与占空比变化对比

    Raspberry Pi 上提供了硬件 PWM 功能,一共包括 2 个通道,引出了 4 个 GPIO 引脚。其中 GPIO 12 和 GPIO 18 属于通道 0,GPIO 13 和 GPIO 19 属于通道 1。但有意思的是只有通道 0 的 GPIO 18 引脚的默认功能为 PWM,其他的不是被音频处理所占用,就是引脚另有它用。启用这些引脚需要进行一些特殊配置甚至内核编程。

      提示

    如何启用 Raspberry Pi 上的 PWM ?

    修改 /boot/config.txt ,添加 dtoverlay=pwm 。

    启用 PWM 通道 1 请参考:https://github.com/raspberrypi/firmware/issues/1178

    修改 GPIO 引脚功能请参考:https://www.dummies.com/computers/raspberry-pi/raspberry-pi-gpio-pin-alternate-functions 和 http://abyz.me.uk/rpi/pigpio/pigs.html

    相关类

    PWM 操作的相关类位于 System.Device.Pwm 命名空间下。

    PwmChannel

    public class PwmChannel : IDisposable
    {
        // 创建 PwmChannel 对象
        // chip 为 PWM 芯片编号,Linux 下位于 /sys/class/pwm 文件夹下
        // channel 为 通道编号
        public static PwmChannel Create(int chip, int channel, int frequency = 400, double dutyCycle = 0.5);
    
        // 占空比,取值为 0.0 - 1.0
        public double DutyCycle { get; set; }
        // 频率,单位为 Hz
        public int Frequency { get; set; }
    
        // 打开和关闭 PWM 通道
        public void Start();
        public void Stop();
    }
    

    PWM 的使用步骤

    1. 实例化一个 PwmChannel 对象
    PwmChannel pwm = PwmChannel.Create(chip: 0, channel: 0, frequency: 400, dutyCycle: 0);
    
    1. 打开 PWM 通道
    pwm.Start();
    
    1. 设置占空比/频率改变输出的 PWM 信号
    pwm.DutyCycle = 0.5;
    
    1. 关闭 PWM 通道
    pwm.Stop();
    

    使用硬件 PWM 控制 LED 的亮度

    硬件需求

    名称 数量
    LED x1
    220 Ω 电阻 x1
    杜邦线 若干

    电路

    • LED 正极 - GPIO 18 (Pin 12)
    • LED 负极 - GND

    使用 Docker 运行示例

    示例地址:https://github.com/ZhangGaoxing/dotnet-core-iot-demo/tree/master/src/PwmLed

    docker build -t pwm-led-sample -f Dockerfile .
    docker run --rm -it -v=/sys/class/pwm:/sys/class/pwm --privileged=true pwm-led-sample
    

    代码

    1. 打开 Visual Studio ,新建一个 .NET Core 控制台应用程序,项目名称为“PwmLed”。
    2. 引入 System.Device.Gpio NuGet 包。
    3. Program.cs 中,将主函数代码替换如下:
    static void Main(string[] args)
    {
        int brightness = 0;
        using PwmChannel pwm = PwmChannel.Create(chip: 0, channel: 0, frequency: 400, dutyCycle: 0);
    
        pwm.Start();
    
        while (brightness != 255)
        {
            pwm.DutyCycle = brightness / 255D;
    
            brightness++;
            Thread.Sleep(10);
        }
    
        while (brightness != 0)
        {
            pwm.DutyCycle = brightness / 255D;
    
            brightness--;
            Thread.Sleep(10);
        }
    
        pwm.Stop();
    }
    
    1. 发布、拷贝、更改权限、运行

    效果图

    使用软件 PWM 控制 RGB LED

    上面提到 Raspberry Pi 中默认只有 GPIO 18 这一个引脚可以使用 PWM,要控制 RGB LED 则至少需要使用 3 个 PWM,这显然是不够用的。在 Iot.Device.Bindings 这个 NuGet 包中为我们提供了使用 GPIO 模拟的软件 PWM 类 SoftwarePwmChannel 。软件 PWM 的使用效果并没有硬件 PWM 的那种“顺滑”,因为其精度完全取决于 GPIO 的速度。

      提示

    RGB LED 有三种颜色,但通常只有 4 个引脚,而三种单色 LED 却有 6 个引脚,为什么会少了 2 个引脚?RGB LED 分为共阳极和共阴极。如果少的两个引脚为阳极,则为共阳极 RGB LED,三个单色 LED 共用一个阳极,剩下的三个引脚为各自的阴极。共阴极 RGB LED 则相反。两种 LED 在使用上类似,但程序相反,比如共阴极时占空比越高 LED 越亮,而共阳极时,占空比越高则 LED 越暗。

    硬件需求

    名称 数量
    RGB LED x1
    220 Ω 电阻 x3
    杜邦线 若干

    电路

    • LED R - GPIO 18 (Pin 12)
    • LED G - GPIO 23 (Pin 16)
    • LED B - GPIO 24 (Pin 18)
    • LED 阴极 - GND

    使用 Docker 运行示例

    示例地址:https://github.com/ZhangGaoxing/dotnet-core-iot-demo/tree/master/src/PwmRgb

    docker build -t pwm-rgb-sample -f Dockerfile .
    docker run --rm -it --device /dev/gpiomem pwm-rgb-sample
    

    代码

    1. 打开 Visual Studio ,新建一个 .NET Core 控制台应用程序,项目名称为“PwmRgb”。
    2. 引入 Iot.Device.Bindings NuGet 包。
    3. Program.cs 中,将主函数代码替换如下:
    static void Main(string[] args)
    {
        using PwmChannel red = new SoftwarePwmChannel(pinNumber: 18, frequency: 400, dutyCycle: 0);
        using PwmChannel green = new SoftwarePwmChannel(pinNumber: 23, frequency: 400, dutyCycle: 0);
        using PwmChannel blue = new SoftwarePwmChannel(pinNumber: 24, frequency: 400, dutyCycle: 0);
    
        red.Start();
        green.Start();
        blue.Start();
    
        Breath(red, green, blue);
    
        red.Stop();
        green.Stop();
        blue.Stop();
    }
    
    public static void Breath(PwmChannel red, PwmChannel green, PwmChannel blue)
    {
        int r = 255, g = 0, b = 0;
    
        while (r != 0 && g != 255)
        {
            red.DutyCycle = r / 255D;
            green.DutyCycle = g / 255D;
    
            r--;
            g++;
            Thread.Sleep(10);
        }
    
        while (g != 0 && b != 255)
        {
            green.DutyCycle = g / 255D;
            blue.DutyCycle = b / 255D;
    
            g--;
            b++;
            Thread.Sleep(10);
        }
    
        while (b != 0 && r != 255)
        {
            blue.DutyCycle = b / 255D;
            red.DutyCycle = r / 255D;
    
            b--;
            r++;
            Thread.Sleep(10);
        }
    }
    
    1. 发布、拷贝、更改权限、运行

    效果图

    供参考

    1. Pulse-width modulation - Wikipedia:https://en.wikipedia.org/wiki/Pulse-width_modulation
    2. RPI4 : PWM0 & PWM1 Alternate pins - GitHub:https://github.com/raspberrypi/firmware/issues/1178
    3. Raspberry Pi GPIO Pin Alternate Functions:https://www.dummies.com/computers/raspberry-pi/raspberry-pi-gpio-pin-alternate-functions/
    4. PWM source code:https://github.com/dotnet/iot/tree/master/src/System.Device.Gpio/System/Device/Pwm
    5. 脉冲宽度调制 - 百度百科:https://baike.baidu.com/item/脉冲宽度调制/10813756
  • 相关阅读:
    链接数据库
    Ajax 密码验证
    for循环 打印菱形 空 和 实
    for 循环 正方形
    面向对象
    用正则表达式 匹配手机号码
    正则表达式
    js 中 == 和=== 有什么区别?
    js 删除
    封装函数增删改查
  • 原文地址:https://www.cnblogs.com/zhanggaoxing/p/11748663.html
Copyright © 2011-2022 走看看