IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Windows 10 IoT开发:声控灯的实现(树莓派3)

    汪宇杰发表于 2016-04-03 04:05:09
    love 0

    在很多楼道中,声控灯的应用很广泛,拍一下手就可以开灯。现在有了树莓派3和Windows 10 IoT,要自己实现一个声控灯也很简单。

    我买的声音传感器型号是FC-04,这个网上Windows 10 IoT的资料几乎没有,不过根据它的电器说明还是很容易琢磨出来用法的。和其他传感器类似,首先第一步是校准。

    一、校准FC-04声音传感器

    在安静的环境中将VCC接入树莓派的DC 3.3输出v,GND接入电源负极(Ground),这时候电源指示灯会亮起,证明你买到的FC-04没有爆掉。

    如果你的开关指示也亮起,是正常现象,说明声音太灵敏,在安静的环境中也识别出了声音,需要校准。

    用指甲或者螺丝刀慢慢旋转蓝色菊花的菊花芯子,一边旋转一边对着传感器头部的麦克风说“微软大法好”,直到开关指示熄灭的一瞬间,那个阈值就是介于你的安静环境(基准)和有声音(你说话)之间正正好好的值。

    这时候你可以试试发出别的声音,比如“FARK”,“XIET”,或者拍手,开关指示灯在有声音的情况下应该会闪动,证明校准完成。

    二、连接树莓派

    这个传感器有2个输出,DO和AO,如果你买到的FC-04只有一个输出也没问题,用法完全一样。这里我只用到DO,意思是数字输出。

    前面第一步已经把VCC和GND接好了,剩下的就是把DO连接到树莓派的一个GPIO端口上,我用的是GPIO 06。

    然后还有个灯要连,随便搞个LED小灯,把短脚(负极)接到GROUND,和FC-04的GROUND共用一条线路,把LED的长脚(正极)连接到树莓派的一个GPIO端口上,我选择的是GPIO 05。

    注意,很多LED的例子里接法和我是相反的,比如微软Windows 10 IoT的第一个例子 Blinky 里面是通过向LED输出低电平(控制短脚)来开关LED的,我个人比较喜欢输出高电平表示LED亮起,低电平表示熄灭,所以我才把长脚接到GPIO上去。

    三、爆代码

    首先,我们有2个接在GPIO上的元器件,FC-04和LED,所以爆2个属性出来,代表他们的GPIO针脚。

    打开MainPage.xaml.cs,把这两行代码敲进去

    public GpioPin LedPin { get; set; }
    
    public GpioPin SoundPin { get; set; }
    

    然后还有个变量保存LED的开关状态:

    public bool IsLightOn { get; set; }

    接下来注册Loaded事件:

    public MainPage()
    {
        this.InitializeComponent();
        Loaded += OnLoaded;
    }
    

    初始���GPIO控制器

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        var controller = GpioController.GetDefault();
        if (null != controller)
        {
    
        }
    }

    LED是高电平输出表示开,所以第一次启动的时候要关灯,输出低电平

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        var controller = GpioController.GetDefault();
        if (null != controller)
        {
            LedPin = controller.OpenPin(5);
            LedPin.SetDriveMode(GpioPinDriveMode.Output);
            LedPin.Write(GpioPinValue.Low); // set light to off at start up
        }
    }

    FC-04的GPIO 06端口是接受信号的,所以是输入

    SoundPin = controller.OpenPin(6);
    SoundPin.SetDriveMode(GpioPinDriveMode.Input);
    

    然后问题就是怎么检测有没有输入了。主要有两种做法,一种是通过事件:

    //
    // Summary:
    //     Occurs when the value of the general-purpose I/O (GPIO) pin changes, either because
    //     of an external stimulus when the pin is configured as an input, or when a value
    //     is written to the pin when the pin in configured as an output.
    public event TypedEventHandler<GpioPin, GpioPinValueChangedEventArgs> ValueChanged;
    

    一种是拿个DispatcherTimer定时去查询状态。这里我用事件来做,因为Timer并不能实时监测声音传入,interval大了,灯会变迟钝,只有连续的声音才能启动和关闭。如果你把interval调成很小,那么你的灯炮开关会在很短的时间内完成启动和关闭,基本没法用。

    事件处理代码如下:

    SoundPin.ValueChanged += (pin, args) =>
    {
        var pinValue = SoundPin.Read();
        if (pinValue == GpioPinValue.Low)
        {
            Debug.WriteLine("Sound Detected!");
            LedPin.Write(IsLightOn ? GpioPinValue.Low : GpioPinValue.High);
            IsLightOn = !IsLightOn;
        }
    };
    

    这里有个技巧,args参数自带的args.Edge不要去用,它和Read()方法得到的值不是一个意思,不能判断有没有声音的。最实时的做法就是用ValueChanged事件+Read()。

    然后因为FC-04检测到声音时候会在DO输出低电平,所以我判断的是pinValue == GpioPinValue.Low。开灯关灯的代码很直白,没啥好说的。

    最后完整代码如下:

    using System.Diagnostics;
    using Windows.Devices.Gpio;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace SoundLight
    {
        public sealed partial class MainPage : Page
        {
            public GpioPin LedPin { get; set; }
    
            public GpioPin SoundPin { get; set; }
    
            public bool IsLightOn { get; set; }
    
            public MainPage()
            {
                this.InitializeComponent();
                Loaded += OnLoaded;
            }
    
            private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
            {
                var controller = GpioController.GetDefault();
                if (null != controller)
                {
                    LedPin = controller.OpenPin(5);
                    LedPin.SetDriveMode(GpioPinDriveMode.Output);
                    LedPin.Write(GpioPinValue.Low); // set light to off at start up
    
                    SoundPin = controller.OpenPin(6);
                    SoundPin.SetDriveMode(GpioPinDriveMode.Input);
    
                    SoundPin.ValueChanged += (pin, args) =>
                    {
                        var pinValue = SoundPin.Read();
                        if (pinValue == GpioPinValue.Low)
                        {
                            Debug.WriteLine("Sound Detected!");
                            LedPin.Write(IsLightOn ? GpioPinValue.Low : GpioPinValue.High);
                            IsLightOn = !IsLightOn;
                        }
                    };
                }
            }
        }
    }
    

    别忘了在你的XAML中加入纳德拉的头像,保证DEMO时候得到微软大法的保佑,不容易爆。

    四、运行

    启动工程之后,拍手,开灯。再拍手,关灯。

    拍手时候FC-04的开关指示会亮起:



沪ICP备19023445号-2号
友情链接