项目介绍

ML-L3是用于尼康部分型号相机的无线红外遥控器,可以通过红外方式来控制快门的释放,支持B门拍摄。官方售价100RMB左右,山寨版售价10RMB左右。虽然也能实现基本的遥控功能,但是功能还是比较单一,如不能实现定时拍摄,即用来拍摄制作延时视频的素材。本篇文章介绍如何通过Arduino、MCU或FPGA来控制红外发射器,产生快门指令从而实现无线遥控快门的功能。

拆解ML-L3遥控器

为了实现ML-L3遥控器的功能,我们首先要了解无线遥控器的原理。当然最好的方式就是拆解一个ML-L3,然后看看内部的电路,然后测出红外的编码。但是手头又没有这样的一个遥控器,有国外的网友已经拆解了并且测出了红外编码的波形,如下图。

官方遥控器PCB板:

山寨遥控器PCB板:

从PCB板来看,果然还是官方的用料更足一些,通过测量红外发射引脚,在按下按钮时,红外发射头会发出一串脉冲信号,如下图所示:

其中黑色的部分是38KHz的PWM方波,空白部分是低电平,以上波形就表示一个快门指令。

红外遥控协议主要有两种:NEC协议和Philips RC-5协议,NEC采用PWM方式调制,RC-5采用PPM方式调制。其中使用最多的是NEC协议,38KHz载波,一般是由引导码+地址码+地址反码+数据+数据反码构成。其中逻辑0和逻辑1的编码如下:

基于Arduino的实现

好了,知道了快门指令的红外波形,我们只需要写个函数实现这一串脉冲信号就可以了。Arduino开发板,我手头上有的是Circuit Playground Express这款开发板,板载一对红外发射接收头,和两路按键,对于我们的功能已经是足够用了。在使用前需要先安装Cortex-M0的库。

程序非常简单,按下按键时,发出一个快门指令:


#include <Adafruit_CircuitPlayground.h> #define IR_Pin 25
#define Led_Pin 13
#define ButtonA_Pin 4
#define ButtonB_Pin 5 #define LED_ON digitalWrite(Led_Pin, LOW)
#define LED_OFF digitalWrite(Led_Pin, HIGH)
#define LED_SET(x) digitalWrite(Led_Pin, x) #define IR_ON digitalWrite(IR_Pin, HIGH)
#define IR_OFF digitalWrite(IR_Pin, LOW) #define GET_BUTTONA() digitalRead(ButtonA_Pin)
#define GET_BUTTONB() digitalRead(ButtonB_Pin) int sts = 0; void setup()
{
pinMode(IR_Pin, OUTPUT);
pinMode(Led_Pin, OUTPUT);
pinMode(ButtonA_Pin, INPUT_PULLDOWN);
pinMode(ButtonB_Pin, INPUT_PULLDOWN); Serial.begin(9600);
} //Nikon ML-L3 红外遥控器快门编码:38KHz=26us
void loop()
{
if (GET_BUTTONA())
{
delay(10);
if (GET_BUTTONA())
{
sts = !sts;
LED_SET(sts);
Serial.println("Right button pressed!");
OneShot();
}
}
while (GET_BUTTONA()); //等待松开
} void OneShot()
{
int i = 0;
for (i = 76; i > 0; i--) //2100ms
{
IR_ON; //13.5
delayMicroseconds(12);
IR_OFF; //13.7
delayMicroseconds(12);
}
IR_OFF;
delay(28); //2803us
for (i = 15; i > 0; i--) //393us
{
IR_ON;
delayMicroseconds(12);
IR_OFF;
delayMicroseconds(12);
}
IR_OFF;
delayMicroseconds(1580); //1611us for (i = 15; i > 0; i--)
{
IR_ON;
delayMicroseconds(12);
IR_OFF;
delayMicroseconds(12);
}
delayMicroseconds(3580);
for (i = 15; i > 0; i--)
{
IR_ON;
delayMicroseconds(12);
IR_OFF;
delayMicroseconds(12);
}
IR_OFF;
}

基于STM32的实现

在STM32F103上的实现也是非常简单,主要用到了GPIO控制和精确延时函数。红外控制引脚和按键引脚可根据需要来调整。

//根据Nikon ML-L3红外遥控器编码协议,产生快门指令
void OneShot(void)
{
int i = 0;
for(i = 76; i > 0; i--) //2100ms
{
IR_ON; //13.5
delay_us(12);
IR_OFF; //13.7
delay_us(12);
}
IR_OFF;
delay_ms(28); //2803us
for(i = 15; i > 0; i--) //393us
{
IR_ON;
delay_us(12);
IR_OFF;
delay_us(12);
}
IR_OFF;
delay_us(1580); //1611us for(i = 15; i > 0; i--)
{
IR_ON;
delay_us(12);
IR_OFF;
delay_us(12);
}
delay_us(3580);
for(i = 15; i > 0; i--)
{
IR_ON;
delay_us(12);
IR_OFF;
delay_us(12);
}
IR_OFF;
}

基于FPGA的实现

对于FPGA来说,这种波形的产生,时间可以控制的更精确,这取决于FPGA的时钟,时钟越高精度越高,而且可控性更强一些,就是实现起来稍微麻烦一些。

Verilog文件

module ml_l3_pulse_gen( 

input clk_50M,  //20ns
input rst_n,
input trig, //negedge trig output pulse
); parameter T1_2000US = 100000;
parameter T2_28000US = 1400000;
parameter T3_400US = 20000;
parameter T4_1580US = 79000;
parameter T5_400US = T3_400US;
parameter T6_3580US = 179000;
parameter T7_400US = T3_400US; parameter T1_STS = 1;
parameter T2_STS = 2;
parameter T3_STS = 3;
parameter T4_STS = 4;
parameter T5_STS = 5;
parameter T6_STS = 6;
parameter T7_STS = 7;
parameter T8_STS = 8;
parameter T0_STS = 0;
parameter TIME_38KHZ = 658; reg [7:0] cur_sts;
reg [31:0] cnt_38khz;
reg [31:0] cnt;
reg [31:0] cnt_max; reg en;
reg pwm_38k;
reg trig_reg; assign pulse = (en) ? pwm_38k : 0; always @ (posedge clk_50M)
begin
trig_reg <= trig;
end always @ (posedge clk_50M)
begin
if(!rst_n)
cnt_max <= 0;
else
begin
case (cur_sts)
T0_STS : cnt_max <= 0;
T1_STS : cnt_max <= T1_2000US;
T2_STS : cnt_max <= T2_28000US;
T3_STS : cnt_max <= T3_400US;
T4_STS : cnt_max <= T4_1580US;
T5_STS : cnt_max <= T5_400US;
T6_STS : cnt_max <= T6_3580US;
T7_STS : cnt_max <= T7_400US;
default : cnt_max <= 0;
endcase
end
end always @ (posedge clk_50M)
begin
if(!rst_n)
en <= 0;
else
begin
case (cur_sts)
1,3,5,7 : en <= 1;
2,4,6,0 : en <= 0;
default : en <= 0;
endcase
end
end always @ (posedge clk_50M)
begin
if(!rst_n)
cnt <= 0;
else
begin
if(cur_sts != T0_STS && cnt < cnt_max)
cnt <= cnt + 1;
else
cnt <= 0;
end
end always @ (posedge clk_50M)
begin
if(!rst_n)
cur_sts <= T0_STS;
else
begin
case (cur_sts)
T0_STS:
if(trig_reg & !trig)
cur_sts <= T1_STS;
T1_STS:
if(cnt == T1_2000US)
cur_sts <= T2_STS;
T2_STS:
if(cnt == T2_28000US)
cur_sts <= T3_STS;
T3_STS:
if(cnt == T3_400US)
cur_sts <= T4_STS;
T4_STS:
if(cnt == T4_1580US)
cur_sts <= T5_STS;
T5_STS:
if(cnt == T5_400US)
cur_sts <= T6_STS;
T6_STS:
if(cnt == T6_3580US)
cur_sts <= T7_STS;
T7_STS:
if(cnt == T7_400US)
cur_sts <= T0_STS;
default :
cur_sts <= T0_STS;
endcase
end
end /* 38KHz counter */
always @ (posedge clk_50M)
begin
if(!rst_n)
cnt_38khz <= 0;
else
begin
if(en && cnt_38khz < TIME_38KHZ)
cnt_38khz <= cnt_38khz + 1;
else
cnt_38khz <= 0;
end
end /* generate 38KHz pwm */
always @ (posedge clk_50M)
begin
if(!rst_n)
pwm_38k <= 0;
else if(cnt_38khz == TIME_38KHZ)
pwm_38k <= ~pwm_38k;
end endmodule

仿真test bench 文件

`timescale 1ns/100ps

module ml_l3_pulse_gen_tb;

parameter SYSCLK_PERIOD = 20;// 50MHZ

reg SYSCLK;
reg NSYSRESET;
reg trig; wire pulse; initial
begin
SYSCLK = 1'b0;
NSYSRESET = 1'b0;
trig = 0;
end initial
begin
#(SYSCLK_PERIOD * 10 )
NSYSRESET = 1'b0;
trig = 0;
#(SYSCLK_PERIOD * 1000 )
NSYSRESET = 1'b1;
#(SYSCLK_PERIOD * 10 )
trig = 1;
#SYSCLK_PERIOD
trig = 0;
end always @(SYSCLK)
#(SYSCLK_PERIOD / 2.0) SYSCLK <= !SYSCLK; ml_l3_pulse_gen ml_l3_pulse_gen_0 (
// Inputs
.clk_50M(SYSCLK),
.rst_n(NSYSRESET),
.trig(trig), // Outputs
.pulse(pulse)
); endmodule

实际使用效果

对于实际的脉冲时间,不用特别的精确,误差不要太大就行,最好使用示波器测量以下脉冲的时间。对于制作好的遥控器,只需要在相机周围按下按钮就可实现遥控快门。相机机身的红外接收头前后各有一个,可以方便在不同的位置遥控。如下图所示。

总结

这款尼康ML-L3红外遥控器的实现原理非常简单,可扩展性强,可以根据需要自己添加功能,如添加固定时间间隔拍摄,固定张数拍摄,用于拍摄制作延时视频所需要的图片素材。当然,也可以使用手机上的遥控器来实现这个功能。

代码获取

以上代码已经开源在Github和Gitee平台,地址如下。

  • Github开源地址: https://github.com/whik/nikon-wireless-remote-control-ML-L3-DIY.git
  • Gitee开源地址 : https://gitee.com/whik/nikon-wireless-remote-control-ML-L3-DIY.git

没有使用代码托管平台的朋友,可以在公众号后台回复【尼康遥控器】也可以获取代码。

参考资料

文中的ML-L3拆解图,Arduino代码参考自以下链接内容。

推荐阅读


  • 我的个人博客:www.wangchaochao.top
  • 我的公众号:mcu149

手把手教你DIY尼康ML-L3红外遥控器的更多相关文章

  1. 手把手教你DIY一个春运迁徙图(一)

    换了新工作,也确定了我未来数据可视化的发展方向.新年第一篇博客,又逢春运,这篇技术文章就来交给大家如何做一个酷炫的迁徙图(支持移动哦).(求star 代码点这里) 迁徙图的制作思路分为静态的元素和变换 ...

  2. 手把手教你吧Python应用到实际开发 不再空谈悟法☝☝☝

    手把手教你吧Python应用到实际开发 不再空谈悟法☝☝☝ 想用python做机器学习吗,是不是在为从哪开始挠头?这里我假定你是新手,这篇文章里咱们一起用Python完成第一个机器学习项目.我会手把手 ...

  3. 手把手教你用Pytorch-Transformers——实战(二)

    本文是<手把手教你用Pytorch-Transformers>的第二篇,主要讲实战 手把手教你用Pytorch-Transformers——部分源码解读及相关说明(一) 使用 PyTorc ...

  4. 手把手教你做个人 app

    我们都知道,开发一个app很大程度依赖服务端:服务端提供接口数据,然后我们展示:另外,开发一个app,还需要美工协助切图.没了接口,没了美工,app似乎只能做成单机版或工具类app,真的是这样的吗?先 ...

  5. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(四)-使用Travis自动部署Hexo(2)

    前言 前面一篇文章介绍了Travis自动部署Hexo的常规使用教程,也是个人比较推荐的方法. 前文最后也提到了在Windows系统中可能会有一些小问题,为了在Windows系统中也可以实现使用Trav ...

  6. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(三)-使用Travis自动部署Hexo(1)

    前言 前面两篇文章介绍了在github上使用hexo搭建博客的基本环境和hexo相关参数设置等. 基于目前,博客基本上是可以完美运行了. 但是,有一点是不太好,就是源码同步问题,如果在不同的电脑上写文 ...

  7. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(二)-Hexo参数设置

    前言 前文手把手教从零开始在GitHub上使用Hexo搭建博客教程(一)-附GitHub注册及配置介绍了github注册.git相关设置以及hexo基本操作. 本文主要介绍一下hexo的常用参数设置. ...

  8. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(一)-附GitHub注册及配置

    前言 有朋友问了我关于博客系统搭建相关的问题,由于是做开发相关的工作,我给他推荐的是使用github的gh-pages服务搭建个人博客. 推荐理由: 免费:github提供gh-pages服务是免费的 ...

  9. UWP Jenkins + NuGet + MSBuild 手把手教你做自动UWP Build 和 App store包

    背景 项目上需要做UWP的自动安装包,在以前的公司接触的是TFS来做自动build. 公司要求用Jenkins来做,别笑话我,之前还真不晓得这个东西. 会的同学请看一下指出错误,不会的同学请先自行脑补 ...

随机推荐

  1. 扛把子组20191031-8 alpha week 1/2 Scrum立会报告+燃尽图 06

    此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/9916 一.小组情况 队名:扛把子 组长:孙晓宇 组员:宋晓丽 梁梦瑶 ...

  2. VueRouter爬坑第二篇-动态路由

    VueRouter系列的文章示例编写时,项目是使用vue-cli脚手架搭建. 项目搭建的步骤和项目目录专门写了一篇文章:点击这里进行传送 后续VueRouter系列的文章的示例编写均基于该项目环境. ...

  3. C#音频截取与原文匹配2:使用ffmpeg处理音频文件

    ffmpeg获取音频时间 ffmpeg转换音频格式(单声道,16000hz,16bit  wav) ffmpeg截取音频 不知道是不是错觉,感觉ffmpeg比NAudio要快啊~ 那么这就是第二个版本 ...

  4. html基础——a标签

    a标签:超链接/锚点链接  实现页面跳转  只占据自己内容大小的位置 超链接: 使用 target="_self":表示在本页面跳转到 href 中的地址 target=" ...

  5. 图解AQS的设计与实现,手摸手带你实现一把互斥锁!

    AQS是并发编程中非常重要的概念,它是juc包下的许多并发工具类,如CountdownLatch,CyclicBarrier,Semaphore 和锁, 如ReentrantLock, ReaderW ...

  6. 2场 J -Subarray

    题意: 长度为1e91e9的(1,−1)(1,−1)序列,下标从00到1e9−11e9−1,已知有nn个区间为11,其他为−1−1, 问存在多少个区间的和>1>1(保证∑1≤i≤nr[i] ...

  7. PostgreSQL的使用向导

    目录 数据库 创建数据库 进入数据库 查看版本 查看当前时间日期 简单的select 获得帮助命令 退出psql客户端 创建表 weather和cities表的创建 删除表 插入数据 数据库导出成cs ...

  8. 【Python成长之路】python 基础篇 -- global/nonlocal关键字使用

    1 课程起源 有一次在工作中编写python工具时,遇到一个 问题:从配置文件读取变量A后,无法在内存中把A的值改变成新的内容.为了解决"更新内存中变量"的这个问题,查找了一些帖子 ...

  9. Docker数据挂载

    Docker数据管理 在容器中管理数据主要有两种方式: 数据卷(Volumes) 挂载主机目录(Bind mounts) 数据卷 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很 ...

  10. MySQL必知必会(创建计算字段(field))

    #字段(field)基本上和列(column)的意思相同 SELECT Concat(vend_name, ' (', vend_country, ')') FROM vendors ORDER BY ...