美文网首页
再玩树莓派(四)小实验Demo

再玩树莓派(四)小实验Demo

作者: ChenReal | 来源:发表于2020-10-11 23:41 被阅读0次

    双节长假一晃就已余额不足了。
    其实,我节前立的Flag也早就完成了。而且对“小目标”做了些简化处理:

    • 原计划的客户端控制器,以App小游戏或者小车的遥控器的形式去实现。现在的版本是手机去App控制发光二极管开关和闪烁。
    • 考虑到我们的重点旨在驱动树莓派的GPIO做信号输出,以小游戏的形式虽然趣味性会高一些,但是似乎有点喧宾夺主。所以大好的时光,我还是决定还是花在刀刃上,在树莓派上所能显现的内容是一样的。
    • 至于遥控小车也是挺好玩的,不过手头上的配件不充足,留着下回补充好配件模块回来,再动手去弄吧。

    GPIO控制器

    上回讲过了GPIO的接线以及如何C#代码驱动它。回到我的Demo,还稍微做了一点封装,以便不用款的Led灯的重用。上一篇说到的 GpioController的静态实例,是在LedModule构造方法中注进来的。
    LedModule 是基于GPIO对Led模块的控制器,主要方法有:

    • SetOn 亮灯
    • SetOff 灭灯
    • Blink 闪烁
    • BlinkWith 与另一个Led交替闪烁
        /// <summary>
        /// Led 模块的封装
        /// </summary>
        public class LedModule
        {
            /// <summary>
            /// Pin针脚编号,采用来Board方式来自定
            /// </summary>
            public int PinIndex { get; private set; }
            /// <summary>
            /// Pin是否开启
            /// </summary>
            public bool IsOpenned { get; private set; }
            /// <summary>
            /// GpioController 实例
            /// </summary>
            public GpioController GPIO { get; private set; }
    
            /// <summary>
            /// LedModule构造方法
            /// </summary>
            /// <param name="i">PinIndex</param>
            /// <param name="ctrl">GpioController</param>
            public LedModule(int i, GpioController ctrl)
            {
                PinIndex = i;
                GPIO = ctrl;
            }
            /// <summary>
            /// OpenPin
            /// </summary>
            public void Open()
            {
                if (PinIndex < 1 || PinIndex > 40) throw new ArgumentException("index must between 1 - 40.");
                try
                {
                    if (!GPIO.IsPinOpen(PinIndex))
                    {
                        GPIO.OpenPin(PinIndex, PinMode.Output);
                    }
                    IsOpenned = true;
                }
                catch (Exception ex)
                {
                    IsOpenned = false;
                    throw ex;
                }
            }
            /// <summary>
            /// ClosePin
            /// </summary>
            public void Close()
            {
                if (IsOpenned) GPIO.ClosePin(PinIndex);
                IsOpenned = false;
            }
    
            /// <summary>
            /// 闪烁
            /// </summary>
            /// <param name="interval">闪烁的时间间隔</param>
            /// <param name="times">闪烁次数,0-代表无限次数</param>
            public void Blink(int interval, int times = 0)
            {
                if (!IsOpenned) return;
                int loop = 0;
                ThreadPool.QueueUserWorkItem((x) =>
                {
                    while (IsOpenned)
                    {
                        if (loop % 2 == 0) SetOn();
                        else SetOff();
                        Thread.Sleep(interval);
                        loop++;
                        if (times >= loop) break;
                    }
                });
            }
            /// <summary>
            /// 与另外一个LED灯一起闪烁
            /// </summary>
            /// <param name="led">另一个灯实例</param>
            /// <param name="interval">闪烁的时间间隔</param>
            /// <param name="times">闪烁次数,0-代表无限次数</param>
            public void BlinkWith(LedModule led, int interval, int times = 0)
            {
                var led1 = this;
                var led2 = led;
                int loop = 0;
                ThreadPool.QueueUserWorkItem((x) =>
                {
                    while (true)
                    {
                        if ((!led1.IsOpenned && !led2.IsOpenned) || times > loop) break;
                        if (loop % 2 == 0)
                        {
                            led1.SetOn();
                            led2.SetOff();
                        }
                        else
                        {
                            led2.SetOn();
                            led1.SetOff();
                        }
                        Thread.Sleep(interval);
                        loop++;
                    }
                });
            }
    
            /// <summary>
            /// LED亮
            /// </summary>
            public void SetOn()
            {
                if (IsOpenned) GPIO.Write(PinIndex, PinValue.High);
            }
            /// <summary>
            /// LED灭
            /// </summary>
            public void SetOff()
            {
                if (IsOpenned) GPIO.Write(PinIndex, PinValue.Low);
            }
        }
    

    手机端APP

    手机端应用,我提供用的是一个简单的H5页面。通过调用服务端WebAPI,发出控制LED的命令。


    H5App

    H5代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0,viewport-fit=cover">
        <title>Led控制器</title>
        <link href="//smallsea2016.gitee.io/lui/css/lui.css" rel="stylesheet" />
    </head>
    <body>
        <div class="ui_page_wrap">
            <header class="ui_page_hd">
                <a id="go—back" href="javascript:goBack();" class="ui_back" style="display: none;"></a>
                <a>LED控制器</a>
            </header>
            <div class="ui_page_bd">
                <h2 class="ui_list_hd">控制器</h2>
                <ul class="ui_list ui_list_arrow">
                    <li><a href='javascript:resetLed()'>重置LED</a></li>
                    <li><a href='javascript:setLed("red",2)'>红灯亮</a></li>
                    <li><a href='javascript:setLed("red",0)'>红灯关闭</a></li>
                    <li><a href='javascript:setLed("blue",2)'>蓝灯亮</a></li>
                    <li><a href='javascript:setLed("blue",0)'>蓝灯关闭</a></li>
                    <li><a href='javascript:blinkLed("red")'>红灯闪烁</a></li>
                    <li><a href='javascript:blinkLed("blue")'>蓝灯闪烁</a></li>
                    <li><a href='javascript:blinkLed("all")'>红蓝闪烁</a></li>
                </ul>
            </div>
        </div>
    </body>
    </html>
    <script src="//smallsea2016.gitee.io/lui/js/lui.js"></script>
    <script>
        function resetLed() {
            lui.request({
                type: 'POST', url: "/api/led/reset", data: "",
                success: function (res) {
                    console.log(res);
                }
            });
        }
    
        function setLed(color,cmd) {
            lui.request({
                type: 'POST', url: "/api/led/set", data: { color, cmd },
                success: function (res) {
                    console.log(res);
                }
            });
        }
    
        function blinkLed(color) {
            lui.request({
                type: 'POST', url: "/api/led/flash", data: { color },
                success: function (res) {
                    console.log(res);
                }
            });
        }
    </script>
    

    WebAPI 服务端代码

        [Controller(BaseUrl = "/api/led")]
        public class Led : BaseController
        {
            const string LedControl = "LedControl";
            [Post]
            public JsonResult Reset()
            {
                Console.WriteLine("Led Reset");
                var result = new MsgResult();
                Dispatcher.Call(LedControl, new LedEvent("reset", ""));
                return Json(result);
            }
    
            [Post]
            public JsonResult Set(string color, int cmd)
            {
                Console.WriteLine($"Led Set [{color},{cmd}]");
    
                var result = new MsgResult();
                if (!(color == "red" || color == "blue")) 
                    result.SetMessage("led color is not found");
    
                if(result.ret == 0)
                {
                    var evt = new LedEvent("", color);
                    switch (cmd)
                    {
                        case 0:
                        case 1:
                            evt.action = "off";
                            break;
                        case 2:
                            evt.action = "on";
                            break;
                    }
                    if(!string.IsNullOrEmpty(evt.action))
                        result = Dispatcher.Call(LedControl, evt);
                }
    
                return Json(result);
            }
    
            [Post]
            public JsonResult Flash(string color)
            {
                Console.WriteLine($"Led Flash [{color}]");
    
                var result = new MsgResult();
                if (!(color == "red" || color == "blue" || color == "all"))
                    result.SetMessage("led color is not found");
    
                if (result.ret == 0)
                {
                    result = Dispatcher.Call(LedControl, new LedEvent("blink", color));
                }
                return Json(result);
            }
        }
    

    代码粘贴到这里,似乎要稍微解释一下,WebAPI并没有直接操控GPIO,而是通将命令封装成LedEvent,然后通过Dispatcher.Call 事件派发出去。因此,实际上真正执行GPIO命令的是隐藏在应用内的另外一个服务——LedServerHost

        /// <summary>
        /// 树莓派GPIO Led灯操控服务
        /// </summary>
        public class LedServerHost : IHostedService, IDisposable
        {
            private GpioController controller;
            private LedModule ledRed;
            private LedModule ledBlue;
            public const string LedControl = "LedControl";
            public LedServerHost()
            {
            }
            public void Dispose()
            {
                ledRed.Close();
                ledBlue.Close();
                controller.Dispose();
                Dispatcher.Removesync(LedControl, OnLedCommand);
            }
    
            public Task StartAsync(CancellationToken cancellationToken)
            {
                controller = new GpioController(PinNumberingScheme.Board);
                ledRed = new LedModule(11, controller);
                ledBlue = new LedModule(16, controller);
    
                Dispatcher.AddAsync(LedControl, OnLedCommand);// 监听WebApi控制事件
                return Task.CompletedTask;
            }
    
            public Task StopAsync(CancellationToken cancellationToken)
            {
                this.Dispose();
                return Task.CompletedTask;
            }
    
            /// <summary>
            /// WebApi监听事件的回调方法
            /// </summary>
            /// <param name="obj"></param>
            /// <param name="evt"></param>
            /// <returns></returns>
            private Task<MsgResult> OnLedCommand(object obj, EventArgs evt)
            {
                var ledEvt = obj as LedEvent;
                var result = new MsgResult();
                Console.WriteLine($"action:{ledEvt.action} | target:{ledEvt.target}");
                switch (ledEvt.action)
                {
                    case "on":
                        SetLedOn(ledEvt);
                        break;
                    case "off":
                        SetLedOff(ledEvt);
                        break;
                    case "blink":
                        SetLedBlink(ledEvt);
                        break;
                    case "reset":
                        ledRed.Close();
                        ledBlue.Close();
                        break;
                }
    
                return Task.FromResult(result);
            }
    
            /// <summary>
            /// 设置Led闪烁
            /// </summary>
            /// <param name="ledEvt"></param>
            private void SetLedBlink(LedEvent ledEvt)
            {
                int interval = (ledEvt.interval == 0) ? 500 : ledEvt.interval;
                switch (ledEvt.target)
                {
                    case "red":
                        ledRed.Open();
                        ledRed.Blink(interval);
                        break;
                    case "blue":
                        ledBlue.Open();
                        ledBlue.Blink(interval);
                        break;
                    case "all":
                        ledRed.Open();
                        ledBlue.Open();
                        ledRed.BlinkWith(ledBlue, interval);
                        break;
                }
            }
            /// <summary>
            /// 设置Led熄灭
            /// </summary>
            /// <param name="ledEvt"></param>
            private void SetLedOff(LedEvent ledEvt)
            {
                LedModule led = null;
                if (ledEvt.target == "red") led = ledRed;
                else if (ledEvt.target == "blue") led = ledBlue;
                led?.Open();
                led?.SetOff();
            }
            /// <summary>
            /// 设置Led点亮
            /// </summary>
            /// <param name="ledEvt"></param>
            private void SetLedOn(LedEvent ledEvt)
            {
                LedModule led = null;
                if (ledEvt.target == "red") led = ledRed;
                else if (ledEvt.target == "blue") led = ledBlue;
                led?.Open();
                led?.SetOn();
            }
        }
    

    至此,我们熟悉的GpioController终于又显现出来了。我的代码也宣告粘贴完毕。国庆几天假期,我对着树莓派也就折腾这了个这样的东西出来……
    此刻,我的心情有点小兴奋,也有点小失望。兴奋的自然是自己向IoT领域的探索,终于迈出成功的小半步;失望的是个人能力所限,出来的作品确实也不够高端不够精彩。树莓派的系列就此暂告一段落,相信不久我又会回来的:)

    相关文章

      网友评论

          本文标题:再玩树莓派(四)小实验Demo

          本文链接:https://www.haomeiwen.com/subject/xvmepktx.html