地球人皆知,许多物联网教程作者的心中都深爱着一灯大师,所以第一个例程总喜欢点灯,高级一点的会来个“一闪一闪亮晶晶”。老周今天要扯的也是和灯有关的,但不单纯地点个灯,那样实在不好玩,缺乏乐趣。老周打算舞个龙灯,哦不,是用 LED 彩色灯带给伙伴们整点炫酷乐子。

说到这LED彩灯,咱们常见到的有两类:

1、一卷一卷的灯带,灯带是软的,底部有背胶,可以随意贴(贴电脑机箱,贴储物柜,贴手办展示盒……);

2、点阵屏,其实跟灯带一个样,只是有个框架,做成矩阵。如 3 * 3、4 * 4 等。

驱动 IC 一般是 WS2812,此货体积甚小,便于寄生于每个灯珠内。所以,每个LED灯珠都可以单独控制。而且 WS2812 允许你把灯珠串联起来,发送给它的数据可以连续设置多个灯珠。颜色由 RGB 控制,即 24 位——设置灯珠颜色要向 WS2812 发送3个字节的数据。

其实,WS2812的驱动协议不那么复杂,随便查查资料就能懂的了。当然,Nano Framework 已经有封装好的驱动,咱们不需要自己写协议。对于 ESP32,有两种驱动方案:

1、SPI 方式,此法各种开发板通用。曾记否?老周写过在树莓派生用 SPI 驱动 WS2812 的水文;

2、RMT 方式,许多 ESP32 模组都支持RMT,可以用它来驱动 WS2812。RMT 说白了就是用来发送和接收红外编码的,比如,电视遥控器、电动马桶遥控器等(空调遥控器好像特殊一些,很多模块都解码不了)。RMT 由于可以在同一周期内设定高、低电平的持续时间,使得它也能用于驱动 WS2812。

实际上,PWM 也可以的,因为一个周期内的占空比也能设定高、低电平的持续时间。只是,在 PWM 连续发生时要频繁地更改占空比,对开发板的速度有要求,还要确保代码执行得够快。Nano Fw 毕竟是封装过的,性能上会有损失的。虽然使用第三方框加会带来一些性能上的削弱,但在应用层可以提升开发效率,就像写普通 .NET 程序那样。两者总是要有一个平衡的。当然了,还是那句话,如果用其他框架做不到的事情,就必须用官方的 idf 了。性能上肯定比脚本语言高的。

好了,基本理论准备完毕,接下来,咱们开始整活。

先来看看如何用 RMT 来驱动 WS2812 的。因为这个比较新奇,所以先介绍它。红外编码协议可能会劝退不少伙伴,但,你不必担心,毕竟咱们这里不是真的用红外通信,只是借助接口协议来给 WS2812 发数据罢了,不会涉及协议编码的。而且,Nano Framework 已经封装好了,用来很省事,初始化只需要一条 new 语句就完事了。

A、硬件部分,ESP32 模块你可随意,只要有引出相关IO口就行,接口少也不要紧的,因为咱们顶多用一两根线(不含供电)。然后就是RGB灯带或者点阵屏。其实这两者本质上一样。老周这个灯带就是当初写树莓派文章时用的那个,ESP32 也是 3.6 年前买的,放在柜子里吃了几年尘螨。现在拿出来给大伙做演示,居然还能用,这质量可以的。

现在新点的开发板很多是 Type-C 接口的,不过老周这个毕竟是几年前的,是 Micro USB 接口的。啥接口没关系,可能就是找数据线麻烦些,现在很多手机是 C 口的。不过老周家里啥线都有,全都是绿联的。你没看错,老周所有数据线和转换器都是用绿联的。这不是广告,就是质量好。老周家里就是这样的:风扇是美的,因为电机静音;线材绿联的,墙插排插都是公牛的;音响器材铁三角或漫步者……老周不买小米的,小米其实就跟京东京造差不多,万能贴牌。老周记得,买硬盘唯一一次翻车的就是京造的。那个硬盘现在搭在树莓派上,专门放魔法少女动画片。

又扯远了,下面是步骤:

1、启动 VS;

2、新建 Nano 项目,选 Blank Application 项目模板就行了;

3、打开 Nuget 包管理器(方法自己百度),搜索 ws28xx esp32,然后你会找到一个【nanoFramework.Iot.Device.Ws28xx.Esp32】包。没错,它是专为 ESP32 封装,开箱即用(使用时引入 Iot.Device.Ws28xx.Esp32 命名空间)。

4、安装 nanoFramework.Iot.Device.Ws28xx.Esp32 包及相关依赖(一般自动安装);

这里介绍一下几个关键类。首先是 WS 芯片的公共基类 Ws28xx,在实例化时,咱们可以根据所使用的芯片选择派生类:Ws2812b 、Ws2812c、Sk6812 等,WS2812B 和 WS2812C 比较常见。至于你买的灯带是哪个 IC,还真不好说,比如老周这个其实是 WS2812C,可以卖家的商品介绍标注的是 WS2812B。问客服也没用的,多数是一问摇头三不知。客服客服,毫不客气地让你服得三观倒置。

这个可以上机测试,如果灯珠点亮后与你设置的颜色不对,可以换个类,比如,用 WS2812b 的结果不正确,可以换成 WS2812c 来试。WS2812b 和 WS2812c 的红色和绿色好像是反过来的。

接线就简单了,一根接 5V(没5V接口就接 3.3,或者单独供电),数据线只有一根,这里老周用 0 口,即 GPIO 0。你可以随便选其他接口,比如官方示例用的 GPIO 15。

public class Program
{
const int PxCount = 16; // 有多少个灯珠
const int DelayMS = 10; // 延时多少ms
const int DataPin = 0; // 使用哪个IO口 // 入口点
public static void Main()
{
Ws28xx ws28xx = new Ws2812c(DataPin, PxCount);
BitmapImage bmp = ws28xx.Image;
//ws28xx.ClockDivider = 2;
//ws28xx.ResetCommand = new RmtCommand(1800, false, 1850, false);
//ws28xx.OnePulse = new RmtCommand(35, true, 16, false);
//ws28xx.ZeroPulse = new(14, true, 34, false);
//Debug.WriteLine($"分频:{ws28xx.ClockDivider}"); int i = default;
int index1, index2; // 要设置的灯珠索引
while (true)
{
// 从两边向中间靠拢
for (i = 0; i < PxCount / 2; i++)
{
// 每次设置两颗灯珠
index1 = i;
index2 = PxCount - 1 - i;
bmp.SetPixel(index1, 0, Color.Red);
bmp.SetPixel(index2, 0, Color.Red);
ws28xx.Update(); // 更新
Thread.Sleep(DelayMS);
}
// 从中间向两侧扩散
for (i = PxCount / 2 - 1; i >= 0; i--)
{
index1 = i;
index2 = PxCount - 1 - i;
bmp.SetPixel(index1, 0, Color.Blue);
bmp.SetPixel(index2, 0, Color.Blue);
// 更新
ws28xx.Update();
Thread.Sleep(DelayMS);
}
}
}
}

Ws2812c 类的构造函数有三个参数:1、你用的IO号;2、宽度;3、高度。这里的宽高即灯珠个数,此处老周只点16个灯,多了怕供电不足(其实可以点更多灯珠)。第三个参数默认是1,所以如果高为1可以忽略。这个宽和高啥意思呢?对于灯带来说,你可以认为它永远只有一行,但有 N 列(N 是无限大正整数),即 width = N, height = 1。而点阵屏是矩阵,所以用点阵屏就可以设置宽和高。

Ws28xx类公开 Image 属性,类型为 BitmapImage 类(也是个通用基类)。咱们可以把LED彩灯视作一张位图,每个灯珠就是一个像素。所以,设置某个灯的颜色就要调用 SetPixel 方法,参数是x、y坐标,以及颜色。这个和普通 .NET 程序操作一样。

这个示例,老周实现的效果是:

1、红灯的点亮顺序是从两边往中间靠拢;

2、蓝灯的点亮顺序是从中间向两边扩展。

每当你修改了位图的数据,只是存在内存中,只有调用 WsXXX 实例的 Update 方法才会正式将数据发送出去。

这个点灯算法其实很简单,咱们学过数学,在等差数列中,1+n=2+(n-1)=3+(n-3)。本例中,16个灯,一半就是8,而索引是从0开始的,所以是7,即全序列的索引是 0 到 15,于是得到:0+15=15,1+14=15,2+13=15,3+12=15 …… 7+8=15。每次循环我们就设置相加等于最大索引的那两个灯。这样就能实现从中间向两边展开,顺序反过来就实现从两边向中间收拢。

运行的效果如下图所示。

细心的大伙伴会发现,上面的代码中有几行被注释掉了。这些代码用来设置参数的。不过 WS2812x 类会默认为咱们设置,除非发现默认设置的参数不正确时才要修改,

1、设置分频的分母。

ws28xx.ClockDivider = 2;

ClockDivider 用于设置分频,默认是2。目前支持的时钟是APB(外设的高级总线),频率是 80 MHz,分频2表示除以2=40MHz。也就是一个 Tick 的时间为 1/40000000 = 0.000000025 秒,换算为 0.025 微秒(us)。为什么分频不用 80 呢,这样一 Tick 就是 1 us岂不美哉?因为 WS28XX 的时序很短,比如发送 1 时,高电平持续时间为 0.7 us,低电平持续时间为 0.6 us,总时长在 1.3 us 左右。不过这类IC的时序有很多种版本,时序没有精确的时长。不管怎么说,这时间是要精确到 0.01 us的,所以,分频为80只精确到 1 us 显然不够用。分频为2精确到 0.025 us,基本能对付过去了。

2、设置高、低电平的持续时间。

ws28xx.ResetCommand = new RmtCommand(1800, false, 1850, false);
ws28xx.OnePulse = new RmtCommand(35, true, 16, false);
ws28xx.ZeroPulse = new(14, true, 34, false);

RmtCommand 类的构造函数是这样的:

RmtCommand(ushort duration1, bool level1, ushort duration2, bool level2)

咱们可以这样理解:一个周期内有两个电平,level1 和 level2,如果是true就是高电平否则低电平;duration1 描述 level1 的持续时间,duration2 描述 level2 的持续时间。假设持续时间是 100,如果分频是80,那么正好是 1us,可是咱们分频是2,就变成 100*0.025 us 了。毕竟分频后会变慢。

接下来看看 SPI 实现。

SPI 方案主要是用到了 MOSI 接口,虽然在初始化 SPI 总线时会设置几个引脚,但实际上只连接 MOSI 即可。

 // 设置引脚的功能
Configuration.SetPinFunction(23, DeviceFunction.SPI1_MOSI);
Configuration.SetPinFunction(19, DeviceFunction.SPI1_MISO);
Configuration.SetPinFunction(18, DeviceFunction.SPI1_CLOCK);
// 这里有两个参数:第一个是SPI总线ID,第二个是片选引脚,-1表示不使用
SpiConnectionSettings cset = new(1, -1)
{
Mode = SpiMode.Mode0,
ClockFrequency = 2400000, // 通信频率
DataBitLength = 8
};
// 初始化SPI设备
SpiDevice spidev = SpiDevice.Create(cset); Ws28xx ws2812 = new Ws2812b(spidev, PxCount);
// 获取图像对象
var bmp = ws2812.Image; int i = default;
// 进入循环
while (true)
{
for(i=0; i<PxCount; i++)
{
bmp.SetPixel(i, 0, Color.Blue);
ws2812.Update();
Thread.Sleep(DelayMS);
}
for(i=PxCount -1 ; i >= 0;i--)
{
bmp.SetPixel(i, 0, Color.Red);
ws2812.Update();
Thread.Sleep(DelayMS);
}
for(i=0; i<PxCount; i++)
{
bmp.SetPixel(i,0,Color.Green);
ws2812.Update();
Thread.Sleep(DelayMS);
}
for(i=PxCount -1 ;i >= 0;i--)
{
bmp.SetPixel(i, 0, Color.WhiteSmoke);
ws2812.Update();
Thread.Sleep(DelayMS);
} }

SPI 方式稍麻烦一点,用到的IO口有 18、19、23,而灯带只需连接 23 即可。注意在设置引脚功能时,如果选择 SPI1_MOSI、SPI1_CLOCK 等值,那说明用的是 SPI_1,在实例化 SpiConnectionSettings 对象时,busid 参数就是 1;如果设置功能时使用的是 SPI2_MOSI、SPI2_MISO、SPI2_CLOCK,那么实例化 SpiConnectionSettings 时 busid 是 2。虽然 ESP32 有四路 SPI,但前两路内部保留的,外设只用后两个,即 HSPI 和 VSPI,这两个名字也够奇葩的,其实用起来是一样。这破名字容易使人误认为 VSPI 是虚拟SPI,HSPI 是硬件SPI。

咱们在程序代码中指定的 SPI_1 和 SPI_2 就是 HSPI 和 VSPI。

本示例使用 32 个灯珠,在一轮循环中做四次填充:

1、从头到尾,填充蓝色;

2、从尾到头,填充红色;

3、从头到尾,填充绿色;

4、从尾到头,填充烟白色。

效果如下:

好了,今天就水到这里了。

【Nano Framework ESP32篇】WS2812 彩色灯带实验的更多相关文章

  1. 【.NET 与树莓派】控制彩色灯带(WS28XX)

    彩色灯带,相信不用老周多说,大家都知道,没准你家里的灯墙里面就有.老周的茅屋是早期建造的,所以没有预留的灯槽,明灯的话是不好看的,因此老周家里没使用灯带.不过,像柜子后面,显示器后面,书桌边沿这些地方 ...

  2. 【.NET 与树莓派】WS28XX 灯带的颜色渐变动画

    在上一篇水文中,老周演示了 WS28XX 的基本使用.在文末老周说了本篇介绍颜色渐变动画的简单实现. 在正式开始前,说一下题外话. 第一件事,最近树莓派的价格猛涨,相信有关注的朋友都知道了.所以,如果 ...

  3. [原创].NET 分布式架构开发实战五 Framework改进篇

    原文:[原创].NET 分布式架构开发实战五 Framework改进篇 .NET 分布式架构开发实战五 Framework改进篇 前言:本来打算这篇文章来写DAL的重构的,现在计划有点改变.之前的文章 ...

  4. Homekit_Dohome_智能灯带

    简介:本款产品支持音乐律动控制,可以随音乐改换颜色及频率,可以使用Homekit或者Dohome或者遥控器进行有效控制,同时Dohome App已经对接了各大智能音箱,下载Dohome App后就可以 ...

  5. MYSQL(基本篇)——一篇文章带你走进MYSQL的奇妙世界

    MYSQL(基本篇)--一篇文章带你走进MYSQL的奇妙世界 MYSQL算是我们程序员必不可少的一份求职工具了 无论在什么岗位,我们都可以看到应聘要求上所书写的"精通MYSQL等数据库及优化 ...

  6. MYSQL(进阶篇)——一篇文章带你深入掌握MYSQL

    MYSQL(进阶篇)--一篇文章带你深入掌握MYSQL 我们在上篇文章中已经学习了MYSQL的基本语法和概念 在这篇文章中我们将讲解底层结构和一些新的语法帮助你更好的运用MYSQL 温馨提醒:该文章大 ...

  7. 最新华为数通HCNP-随堂培训视频课程 大牛讲解高清带实验

    2017年最新华为数通HCNP-随堂培训视频课程 大牛讲解高清带实验 2017最新的华为中级HCNP培训,数通方向,讲解非常牛高清课程附带实验. 华为数通HCNP-2017年最新随堂培训视频(高清)\ ...

  8. 微型计算机系统实验总结(学习性实验:IO地址译码,可编程并行接口8255,交通灯控制实验 + 自主设计实验:汽车信号灯控制系统,电风扇控制器,洗衣机控制系统,霓虹灯,电梯控制系统)

    实验配套软件: https://download.csdn.net/download/qq_39932172/11221584 实验指导用书: 教师版: https://download.csdn.n ...

  9. BLE MESH 学习[1] - ESP32 篇

    BLE MESH 学习 BLE MESH 是一种蓝牙(n:m)组网的技术. 本篇先介绍 BLE MESH 到使用 ESP32 的官方示例对其进行学习讲解. 后面会进一步学习 SIG 的 BLE MES ...

  10. Entity Framework 第二篇 事务

    Entity Framework  事务 结合第一篇的代码 public class BaseRepository : ITransaction, IDisposable { private XFDb ...

随机推荐

  1. live [lɪv , laɪv] 动词读lɪv 形容词读laɪv

    live [lɪv , laɪv] 动词读lɪv 形容词读laɪv live 英 [lɪv , laɪv] 美 [lɪv , laɪv] v. 居住;住;生存;(尤指在某时期)活着;(以某种方式)生活 ...

  2. In-batch negatives Embedding模型介绍与实践

    语义索引(可通俗理解为向量索引)技术是搜索引擎.推荐系统.广告系统在召回阶段的核心技术之一.语义索引模型的目标是:给定输入文本,模型可以从海量候选召回库中快速.准确地召回一批语义相关文本.语义索引模型 ...

  3. C# NAudio 播放多个MP3文件

    C# 使用 NAudio 来播放多个MP3文件.上代码 1.引入NAudio:using NAudio.Wave; 2.定义变量: private WaveOutEvent outputDevice; ...

  4. Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别

    有个需要是需要在安装包安装初始化时安装 Microsoft Visual c++ 2013 Redistributable 也就是判断软件安装前需不需要运行 vcredist_x64.exe 和 VC ...

  5. Miracast技术详解(三):RTP & MPEG2-TS

    目录 Miracast音视频流概述 抓包准备 RTP MPEG2-TS TS分组 适配域 PCR PID PSI PAT PMT PES 总结 Miracast音视频流概述 在上一篇文章中,我们已经成 ...

  6. LinuxKernel 入侵式双向链表的设计,分析,使用

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  7. Android网络收集和ping封装库

    目录介绍 01.基础介绍 02.stetho大概流程 03.Android中应用 04.如何使用 05.案例截图如下 06.网络请求接口信息 07.如何使用ping 01.基础介绍 该工具作用 诸葛书 ...

  8. 常用命令--复制-备份--cp--mv--scp--rsync

    常用命令--复制-备份--cp--mv--scp--rsync cp cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录.它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在 ...

  9. Avalonia发布MacOS运行程序

    1 打开xxx.csproj项目文件,添加Dotnet.Bundle包: <PackageReference Include="Dotnet.Bundle" Version= ...

  10. ftp安装与配置 云服务器 CentOS7

    1.FTP的安装 #安装 yum install -y vsftpd #设置开机启动 systemctl enable vsftpd.service #启动 systemctl start vsftp ...