张高兴的 .NET Core IoT 入门指南:(五)PWM 信号输出

什么是 PWM

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

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

640?wx_fmt=png

图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 波形可以看到占空比越高小灯越亮。

640?wx_fmt=png

图2:占空比示意图

640?wx_fmt=gif

图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.0public double DutyCycle { get; set; }// 频率,单位为 Hzpublic 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 的亮度

硬件需求

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

电路

640?wx_fmt=png

  • 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. 发布、拷贝、更改权限、运行

效果图

640?wx_fmt=gif

使用软件 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 LEDx1
220 Ω 电阻x3
杜邦线若干

电路

640?wx_fmt=png

  • 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. 发布、拷贝、更改权限、运行

效果图

640?wx_fmt=gif

供参考

  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

原文链接:https://www.cnblogs.com/zhanggaoxing/p/11748663.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET Core 3 对 IoT 应用程序的高级支持:System.Device.Gpio

System.Device.Gpio 是一个全新的 .Net Core 开源库,它旨在使 IoT(物联网)应用程序能够通过其 GPIO 引脚或其他 I/O 控制硬件与传感器、显示器和输入设备进行交互。该库是由社区维护的多个设备绑定集合来进行增强实现的。正如微软 .NET 项目…

代码阅读2

http://blog.csdn.net/u014568921/article/details/53995455 首先,要知道caffe里的卷积核都是三维的 在caffe中卷积核是三维的还是二维的? 下面分割线之间的内容来自http://blog.csdn.NET/u014114990/article/details/51125776 /*********************…

一文带你了解华为云DevCloud为何能全面领跑中国DevOps云服务市场

近日,国际权威调研机构IDC发布了《IDC MarketScape:中国DevOps云服务市场2019厂商评估》报告,该报告从战略和能力两个维度对国内主流DevOps云厂商进行了评估,报告显示,华为云位于 IDC MarketScape “中国DevOps云服务 …

[电子书制作]Excel催化剂输出内容汇总PDF及Word版本分享

Excel催化剂在2018年开始,陆续写出了230篇高质量原创性文章,将Excel催化剂插件的开发过程及使用方法全方位地通过文字的方式给广大网友们分享了。电子书下载方式同样地,为了减少大家过多繁琐的资料下载途径,电子书的下载路径和之前…

深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll文件

原文链接: Deep-dive into .NET Core primitives: deps.json, runtimeconfig.json, and dlls作者: Nate McMasterC#编译器(The C# Compiler)C#的编译器可以将cs文件转换为dll文件, 即程序集文件。程序集文件是一个便携的可执行格式文件, 借助.NET Core,它…

C# 8.0 的默认接口方法

例子直接看例子有这样一个接口: 然后有三个它的实现类: 然后在main方法里面调用: 截至目前,程序都可以成功的编译和运行。 IPerson接口变更 突然,我想对所有的人类添加一个新的特性,例如,添加一…

convolutional layer 源代码

http://blog.csdn.net/xizero00/article/details/51049858 一、 卷积层的作用简介 卷积层是深度神经网络中的一个重要的层,该层实现了局部感受野,通过这种局部感受野,可以有效地降低参数的数目。我们将结合caffe来讲解具体是如何实现卷积层的…

在.net core3.0中使用SignalR实现实时通信

最近用.net core3.0重构网站,老大想做个站内信功能,就是有些耗时的后台任务的结果需要推送给用户。一开始我想简单点,客户端每隔1分钟调用一下我的接口,看看是不是有新消息,有的话就告诉用户有新推送,但老大…

活动最后72小时:购书优惠劵,折后再折,赶紧来抢啊

1024程序员节当当网计算机图书每满100减50!满200减100!满300-150!机械工业出版社华章公司联合当当网特意为【DotNET技术圈】用户申请了一批可与满减叠加使用的“满200减30”的图书优惠码,优惠码使用后相当于:400减230 …

C# 8 新特性 - using 声明

using语句块 尽管.NET Core运行时有垃圾收集器(GC)来负责内存清理工作,但是我们还是要自己确保当非托管资源不再使用的时候应该被清理掉。以前针对实现了IDisposable接口的对象,我们经常会使用using 语句块来这样做: 这…

.Net Core3.0依赖注入DI

构建ASP.NET Core应用程序的时候,依赖注入已成为了.NET Core的核心,这篇文章,我们理一理依赖注入的使用方法。不使用依赖注入首先,我们创建一个ASP.NET Core Mvc项目,定义个表达的爱服务接口,中国小伙类实现…

.Net轻量状态机Stateless

很多业务系统开发中,不可避免的会出现状态变化,通常采用的情形可能是使用工作流去完成,但是对于简单场景下,用工作流有点大财小用感觉,比如订单业务中,订单状态的变更,涉及到的状态量不是很多&a…

Asp.net Core全局异常监控和记录日志

前言系统异常监控可以说是重中之重,系统不可能一直运行良好,开发和运维也不可能24小时盯着系统,系统抛异常后我们应当在第一时间收到异常信息。在Asp.net Core里我使用拦截器和中间件两种方式来监控异常。全局异常监控的数据最好还是写入数据…

SiteServer CMS 新版本 V6.13(2019年11月1日发布)

欢迎来到 SiteServer CMS V6.13 版本,经过两个月的连续迭代开发,V6.13版本新增了几项重要功能,我们希望你会喜欢,一些关键的亮点包括:。新增功能及BUG 修复经过两个月的连续迭代开发,V6.13 版本新增了部分功…

CUDA的global内存访问的问题

http://blog.csdn.net/OpenHero/article/details/3520578 关于CUDA的global内存访问的问题,怎么是访问的冲突,怎样才能更好的访问内存,达到更高的速度。下面先看几张图,这些图都是CUDA编程手册上的图,然后分别对这些…

C# 8 新特性 - 异步流 Asynchronous Streams

异步流 Asynchronous Streams例子 这是一个很简单的控制台程序。它有一个NumberFactory&#xff0c;它可以根据传递的参数来产生一串数字&#xff08;IEnumerable<int>&#xff09;。然后在这个程序中把每个数字都打印出来&#xff0c;同时在前边显示出当前的线程ID。 这…

__syncthreads()

http://www.cnblogs.com/dwdxdy/p/3215136.html __syncthreads()是cuda的内建函数&#xff0c;用于块内线程通信. __syncthreads() is you garden variety thread barrier. Any thread reaching the barrier waits until all of the other threads in that block also reach i…

互联网50周年!这有它的一张“出生证明”

2019 年 10 月 29 日是互联网的 50 周年&#xff0c;50 年前(1969 年 10 月 29 日)&#xff0c;加州大学洛杉矶分校的计算机将一个只有两个字母(LO)的数据包发送到斯坦福研究所的计算机上&#xff0c;这是互联网史上的第一个数据包&#xff0c;从此开启互联网时代的第一步。 当…

Eltwise_layer简介

http://www.voidcn.com/blog/thy_2014/article/p-6117416.html common_layer&#xff1a; ArgMaxLayer类&#xff1b; ConcatLayer类&#xff1a; EltwiseLayer类&#xff1b; FlattenLayer类&#xff1b; InnerProductLayer类&#xff1b; MVNLayer类&#xff1b; SilenceLaye…