这几天我用树莓派实现了一个模仿车库遥控门的设备,分享给大家。(优酷视频 http://v.youku.com/v_show/id_XMTU3ODk1NDY2OA==.html )

一、遥控模块


首先介绍一下我用的遥控器和接收板,这种遥控模块在中国随处可以买到,基本都是长这样的。很多卷帘门、车库门都是用这种遥控模块的。做无线电实验购买的是非锁的版本,注意最好同时购买天线。天线用的是50欧姆单芯导线,其实就是个铜丝,注意购买时候要看好频率,中国大陆的无线电许可频率是315MHz,国外也有用443MHz的,我买的遥控器是315MHz。注意遥控器发射频率和接收频率要匹配就行。遥控接收端芯片是PT2272-M4,M4的意思是点动模式,即按住遥控器按钮输出高电平,松开停止输出。遥控板的ANT端焊接天线,方向要是竖直向上的(相对你的设备)。

遥控板的接口有7个:

接口

含义

GND

电源负极

5V

5V电源输入

D0

对应遥控器按钮

D1

对应遥控器按钮

D2

对应遥控器按钮

D3

对应遥控器按钮

VT

有效信号输出

其中,D0-D3对应遥控器上的A,B,C,D四个按钮。至于哪个是哪个,每个型号的模块不太一样,需要自己做试验。VT会在D0-D3中任何一个有信号的情况下输出高电平。也就是按下遥控器上的任意按钮,VT都会输出。

要格外注意的是,D0-D3,以及VT输出的电压都是5V。然而树莓派的GPIO端口接收电压是3.3V,所以要根据电压分配定律用2个电阻分压到3.3V。

电压分配定律是指在串联电路中,各负载分到的电压与其阻抗成正比关系。依此原理所实作的电路又被称为分压器。

在只有两个阻抗的串联电路中,电压分配定律公式如下:

所以,我采用一个4.7K和一个10K电阻,代入公式:

Vout = 5 x (10000 / (4700 + 10000))

约等于3.4v,是树莓派可以接受的。

二、步进电机


我用的步进电机驱动板是ULN2003的,步进电机型号是28BYJ-48,之前在博客上已经写过一篇ULN2003驱动步进电机的文章了,可以点击此处阅读。所以这里就不再叙述如何使用了。

三、物理连接


简要概括,ULN2003遥控板的IN1-4对应GPIO端口5,6,13,19。遥控板的VT对应GPIO04。树莓派上的2个5V输出分别给遥控板和步进电机供电。连接如下图:

步进电机需要自己做个支架,我用的是M3口径的电钻,在雪糕棒上打孔做的。

四、爆代码


首先,要用到一个这篇文章里的Uln2003驱动类,把它引入工程。

定义一个枚举类型,表示门的开关状态,还要定义一个bool类型表示电机是否正在操作中。

public bool IsBusy { get; set; }

private DoorStatus Status { get; set; }

enum DoorStatus
{
    Open,
    Closed
}

定义GPIO控制器、ULN2003步进电机驱动、遥控器VT端GPIO端口等

public GpioController Controller { get; set; }

public GpioPin PinVT { get; set; }

public Uln2003Driver Uln2003Driver { get; set; }

public CancellationTokenSource Cts { get; private set; }

定义开门、关门的方法:

private async Task OpenDoorAsync()
{
    Cts = new CancellationTokenSource();

    await LogMessageAsync("Opening Door...");
    await Uln2003Driver.TurnAsync(90, TurnDirection.Left, Cts.Token);
    Status = DoorStatus.Open;
    await LogMessageAsync("Door is Open.");
}

private async Task CloseDoorAsync()
{
    Cts = new CancellationTokenSource();

    await LogMessageAsync("Closing Door...");
    await Uln2003Driver.TurnAsync(90, TurnDirection.Right, Cts.Token);
    Status = DoorStatus.Closed;
    await LogMessageAsync("Door is Closed.");
}

主要逻辑:

Controller = GpioController.GetDefault();
if (null != Controller)
{
    TxtMessage.Text += "[OK] GPIO Controller Initialized." + Environment.NewLine;

    Uln2003Driver = new Uln2003Driver(Controller, 5, 6, 13, 19);
    TxtMessage.Text += "[OK] Uln2003Driver Initialized on 5,6,13,19." + Environment.NewLine;

    Status = DoorStatus.Closed;

    PinVT = Controller.OpenPin(4);
    PinVT.SetDriveMode(GpioPinDriveMode.Input);
    TxtMessage.Text += "[OK] VT Initialized on GPIO 04." + Environment.NewLine;
    PinVT.ValueChanged += async (sender, args) =>
    {
        if (!IsBusy && PinVT.Read() == GpioPinValue.High && Status != DoorStatus.Open)
        {
            IsBusy = true;
            await LogMessageAsync("Remote Signal Received on VT.");
            await OpenDoorAsync();
            await Task.Delay(2000);
            await CloseDoorAsync();
            IsBusy = false;
        }
    };
}

完整工程在我的GitHub上:https://github.com/EdiWang/Windows-IoT-Projects/tree/master/Edi.RPi.RemoteDoorControl 

五、运行


按下遥控器任意按键,雪糕棒勃起。2秒后自动降下。