力大无比 发表于 2013-10-20 11:37:34

Arduino uno+w5100+yeelink实现红外转码与网络控制

本帖最后由 力大无比 于 2013-10-20 11:40 编辑

先贴两张作品图


      最近双蛋大学搞了个arduino竞赛,开学之初稍有空闲就报了个名。初中时曾玩过一阵AVR,之后一直忙于学业,现在总算有自由时间重拾单片机。好久不关注这一领域,顿时发现这几年来,单片机还是进步不少的。这是我第一次接触arduino,顿时发现软硬件方面开发系统都简约亲切不少,还是挺容易上手的。首个arduino项目,也不指望太复杂,实现个简单功能就行。
      淘宝上买了个初学者套件,整套一百七十多。原来以为各器件都是arduino专用,后来才发现市面上大多元件arduino都可以支持,而且套件中有许多不需要的器件,这样一想感觉还是挺贵的,推荐新手们分元件单独购买。


      客服还是挺好的,提供了一套详尽的资料。在看教程时,突然对红外发射接收感兴趣,于是就结合之前的想法,想做一个红外控制器。只需一个遥控器就可控制家中所有用红外控制的家电,后来知道这就是红外转码功能。
      通过程序设计控制遥控器各键功能,红外接收器接收到控制遥控器的按键后,经arduino按预先设定的对应关系,发射相应的红外指令。
      本项目使用的库文件在最后会有汇总并提供下载!

      使用IRromote库中的IRrecvDump与IRsendDemo例子分别举例了接受、发射红外代码的使用方法,基于这两个程序,构成了我的红外转码程序。
      鉴于家中和寝室的红外控制设备有限,仅针对格力空调、美的电扇、iptv创维电视设计红外转码。

开发流程一、红外转码部分1.使用IRrecvDump接受各电器红外编码普及一下知识,红外遥控器发射的其实是一连串的方波信号,接收器根据信号有无及其间隔的时间长度计算所代表的1/0信号。下图是常用的NEC编码方式(也是本项目中电扇和iptv的编码方式)。NEC编码由十六位二进制数构成,前八位是地址,后八位是命令。

发送信号时,首先是一段9ms高电平和一段4.5ms低电平作为开始标记,随后是信号内容。先是8位的地址及其反向编码(确保信息准确),再是8位的命令编码及其反向编码。最后以一小段高电平结束。知道了NEC的编码形式,我们就可以通过读取遥控器的红外指令,得到各个信号的代码,并依照其编码方式发射NEC信号。硬件部分:连接非常简单,只需将三个引脚接到指定位置即可。
红外接收头及接法:
软件部分:好在IRromte库十分强大,其IRrecvDump的example可以将读取的红外信息直接打印到Serial Monitor。例如,项目中的总控制遥控器的第一个按钮的dump结果如下:FFA25DDecoded NEC: FFA25D (32 bits)Raw (72): 18448 8900 -4450 550 -550 600 -500 600-550 550 -550 600 -500 600 -550 550 -550 550 -550 600 -1600 600 -1650 600 -1650550 -1650 600 -1650 550 -1650 600 -1600 600 -1650 550 -1650 600 -550 550 -1650600 -550 550 -550 550 -550 600 -1600 600 -550 600 -500 600 -1650 550 -550 550-1650 600 -1650 600 -1650 550 -500 600 -1650 600 26086 8900 -2200 600
“FFA25D”就是转换成16进制的编码,之后只要用它发射就行了。“NEC”代表程序已判断出这种型号的形式是NEC格式的。“32 bits”代表编码长度。后面的Raw是每个方波的长度。正值代表高电平,负值代表低电平,数值大小代表持续长度。根据NEC规则,一高一低的一组电平变化代表一个数。若560us高电平1690us低电平代表1,560us高电平560us低电平代表0,由于程序精度限制,只能以50us为倍数测量,所以只能看到近似的结果,但是这样的分辨率下分辨1与0自然是没有问题的。程序已经帮我们计算好信号的编码了,只要用就行。

一个个按钮点过去,获取各键编码具体请见附件:编码表
注意:有些编码形式特殊(如格力空调),将在第三步中阐述。注意:有些编码长度很长,需要修改IRremote.h中#define RAWBUF 200的数值以使得编码能完整dump出。

2.发射红外编码收集完所有编码后,就可以尝试发射编码了。硬件部分:参考http://www.geek-workshop.com/thread-3444-1-1.html
http://image.geek-workshop.com/forum/201302/23/192024ukkso0a8fxx1fd0b.jpg
一开始一直感觉功率不够,一定要很近才行。。于是尝试改小电阻,增加发射头数量等方式。

提示:红外线虽然肉眼不可见,但在镜头下是可以看到的!用此方法可以快速判断线路通断。改小电阻对单片机有危险,而增加发射头效果依然不理想,于是考虑用三极管放大。下图所示为电路连接图及实际测试各点电压:
不解的是为什么一直处在饱和区,哪怕减小R2也不行。。正在求教:http://www.geek-workshop.com/thread-7536-1-1.html欢迎高手们继续指点!

经大神点拨,好像红外信号是要处在饱和区的,从效果上来看还是不错的。

软件部分:IRromte库提供了多种发射编码的函数,具体可以打开头文件和cpp文件查看,代码都很容易懂。因为是NEC编码,所以使用的是voidIRsend::sendNEC(unsigned long data, int nbits),直接将刚才得到的十六进制编码值给这个函数就可以了。data代表发送的NEC编码值,nbits是编码长度。在刚才的dump中都已经告诉你了。例如IRsend irsend;irsend.sendNEC(0xFFA25D ,32);
另一种发射的函数是void IRsend::sendRaw(unsigned int buf[], int len, int hz),有些不使用编码协议的信号要用它发射。三个参数分别代表要发送的数组,数组长度,和发送红外光的频率(一般都是38(khz))。例如创维电视开机信号:unsigned int tvonoff={4500, 4400,600, 550,550,1650,600, 1600,600, 1650,550, 550,600, 500,600, 500,600, 550,550, 550,600,1600,600, 1600,600, 1650,600, 500,600, 500,600, 500,600, 550,600, 500,600,500,600, 1600,600, 1650,600, 500,600, 500,600, 500,600, 550,600, 1600,600,1600,600, 550,600, 500,600, 1600,600, 1650,550, 1650,600, 1600,600};//已去除第一个值IRsend irsend;irsend. sendRaw (tvonoff,68,38);

注意:dump中RAW的第一个值是不需要的。因为NEC编码的规范是在9ms高4.5ms低电平之后才开始,所以之前的值不是信号一部分,若加上会导致错误。同样,因为NEC一定以低电平结尾,最后一个高电平值也不是信号的一部分,但加上也不会影响发射。注意:有些编码虽然解码结果显示为NEC但只能用sendRaw发射,例如创维电视!注意:每一次发射红外信号后,一定一定需要记得加上irrecv.enableIRIn();这句来重新开启红外接收功能,否则下一个按键就不会被接收!查过代码,发射的时候好像是为了保证信号不受干扰,把Timer2 的时钟关闭了,但没有时钟,根本就不能进行红外接收(红外接收主要就是靠对高低信号计时),enableIRIn函数中有一句就是开启时钟,所以才能正常接收。

3.格力空调的编码方式及发射方式开发中遇到的一大问题就是格力空调的编码问题。格力空调不知是出于什么样的心态,特立独行地设计了自己的一套编码方式,但奇怪之处在于通过sendRaw也不能实现控制。在琢磨这点上我花了不少时间,走了不少弯路。后来在http://www.geek-workshop.com/thread-4560-1-1.html与http://www.geek-workshop.com/forum.php?mod=viewthread&tid=4691的启发下总算明白了编码机制。竟然在一个信号中间部分空出一段低电平!!前后两部分还有某种特殊关系。所以用红外接收头dump出的就是有问题的代码,当然发射不出正确的。而且与风扇等信号不同,空调遥控器发射的是状态信号,不是功能信号。每一个信号中完整包含了空调状态的所有信息(温度、模式、扫风……)所以按下升温降温后,发射的不是升降温的指令,而是当前状态加减一度后的新状态编码。编码中每一位数起什么功能都是定好的,比如说温度信息就体现在第3、4和第17、18位上。根据上述两个例子的代码,自己改了改,总算成功实现控制。心情无比激动!
4.加装温湿度传感器想法是检测室温(湿度),当达到一定温度时自动开启风扇空调。实际操作时发现实践起来十分简单,几乎没花什么时间一次就成功了。硬件部分:使用的是DHT11的温湿度传感器。

注意:引脚3不用接线!软件部分:从网上找了一个库,直接照它的代码用就行了。获取温度:int dat;int chk = DHT11.read(DHT11PIN);return dat=(float)DHT11.temperature;
获取湿度:int dat; int chk = DHT11.read(DHT11PIN);return dat=(float)DHT11.humidity;

5.加装蜂鸣器提示总不能一直用串口查看运行状态吧,最后需要实现的是用电池驱动,所以一定要加上一个指示装置表达当前运行状态,否则功能一多一定搞不清了。当时还不会lcd,就用最简单的无源蜂鸣器。
设定蜂鸣器声音含义程序调用void warning(int freq, int time)发声,通过改变两个参数实现不同声音。freq代表声音频率,1最高4最低,time代表声音时长,25最短100最长

int freqint time
Typechangebuzz(repeat times is modenumber)125
Signal sending250
Cannot find number_in_mp3350
Temperature incorrect4100
Other no function buttonSilentSilent

6.加装lcd屏幕硬件方面:之前初学者套间里提供了一块lcd1602的液晶屏,但是看到那么多接口和教程里的复杂接线就望而生畏了。后来在淘宝店里发现一块适用于1602的转I2C口芯片,将十几个口简化为四个口,就果断买下,并以我拙劣的焊接水平勉强将芯片焊上。在连线上又遇到问题了,搜了半天才发现arduino uno的I2C口在模拟口4、5。四条线从上到下分别接GND、5V、A4、A5

软件部分 :线总算连接好了,但屏幕上半片黑,下半片白,库文件找了好多都没解决,搜了好多资料,总算找到个能用的。下面这篇写得很详细,使用方法也很简单,相信看了库中示例后都能学会。最后总算在它的指导下完成了!http://forum.arduino.cc/index.php?topic=128635.msg967608之后又遇到了一个很郁闷的事情,在我信心满满把程序中需要输出结果的地方都加上lcd指令后发现输入arduino后什么动静都没了,就像死机了一样。原来以为是冲突的问题,就一条条试代码,一条条删除直到正常为止。发现保留某几条lcd指令是可以正常问题的,而另一些一旦加入必定出事。研究了好几天,一直没有明白,在我几乎放弃之际,偶然间屏幕出现了“Temperature:”这竟然是我Serial.print出来的东西!!!顿时明白Serial输出与lcd输出之间必然有冲突!!!删除所有Serial后,一切正常。切记:Serial.print与lcd.print不能同时使用!!!
7.设计的控制遥控器使用方法:
空调开关


电扇开关改变风类

Iptv开关








风扇摇头

频道减频道加

温度减温度增


改变风速
电视开关音量减音量增
0模式切换


模式切换


模式切换待机确认
123








456








789








          Mode1:Air-conditioner                                    Mode2:Fan                                 Mode3:Iptv空调模式下数字需要连续输入两个,先十位数后个位数,且范围在18-30度之间,否则报警且需重新输入

注意:IDE中的1.0.5虽然是稳定版,但引用的一些库好像不能正常通过编译,1.5.1却可以,建议使用。
视频展示:红外转码之 空调遥控
http://www.tudou.com/programs/view/pymprlhaXWw/红外转码之 风扇遥控
http://www.tudou.com/programs/view/ZWq98Lzb2bw/红外转码之 iptv电视遥控
http://www.tudou.com/programs/view/e6FSq5dY634/红外转码之 模式切换与lcd显示
http://www.tudou.com/programs/view/OHwBUXXzgH4/
下文有局部放大图到这里为止,就把红外转码部分的内容介绍完了。
二、网络控制部分红外控制的功能已经实现,接下来就是项目的优化过程。最先想到的就是基于网络实现远程控制。后来知道,这就是物联网的概念。思路是这样的,通过温湿传感器反馈当前环境的温湿度,将数据上传到网络,如果到了警示值,通过邮件、微博通知用户,用户打开控制页面,发送指令(如开空调),uno定时访问网络,当发现需要执行指令时,发射相应的红外指令(空调开启)。看了几篇相关的文章,发现在实现网络控制方面,以亿联(yeelink)和乐联网两个网站最为热门,且都提供相应的现成程序上传下载数据。有了网站的支持和网友们经验的分享,看似高霸上的网络控制其实还是可以完成的,就是与之前遇到的一样,总有一些意想不到的困难。硬件方面:联网的组件比较流行的有两种。一是本项目使用的w5100,还有就是ENC28J60。W5100使用的人比较多,而且程序提供的比较多,容易上手,但缺点是价格有点昂贵,都和uno一个价了。相比之下ENC28J60十几元的价格还是挺实惠的。另外,w5100还有microSD接口(注意不是SD,尽管大多网店都说是SD)可以实现文件读取。令人欣喜的是,我们亲爱的学校提供500元经费支持项目,那么毫不犹豫,果断w5100。W5100是uno的扩展,直接在uno上叠起来就可以使用。但是马上遇到的是端口占用问题。也不知道w5100是怎么样的设计,端口被占用不少,至少我发现D10以上端口是没法用的,也不排除有其他端口。反正,把原来的接线接上后完全没法用了。这又让我郁闷了很久,反复调试都没法解决。之前发过贴问过,还是没能解决。http://www.geek-workshop.com/thread-7377-1-1.html最后我灵机一动,经费充足,干脆就用两块uno算了。(我不是土豪)两者的通信方式就直接用红外了。也就是,原有的uno(控制uno)接线不变,新的uno搭载w5100(网络uno),并用红外发射管向红外接收器发射信号,实现单向的信息传输,且传送的信息就是控制遥控器的按键信息,发射头就放在接收头下。单向传输的特性决定了温湿度传感器不能向网络uno传输数据,所以就调整到网络uno上接收温湿度传感器值。最后加上一个重复发射按钮发射上一个信号以便调试时测试响应距离。这样就完成了硬件部分的所有连接。附上局部图:
其中下侧黄色和蓝色线连接网络uno
软件方面:必须承认,网络控制方面,最主要和最烦人的是程序和配置的问题。由于资料比较多,一开始使用的是乐联网,但是发现网关配置的东西一直搞不清楚,不仅需要网关地址还要公网地址,不知道是什么意思,不知道怎么配置,搞了半天没弄明白,就放弃了。改用亿联(yeelink),虽然功能没有乐联网那么全,但是亿联不用设置网关,而且没有传感器数量限制。Yeelink有官方库,但是我试了半天,总是不能同时上传与下载,最后还是根据某大神的代码更改完成了功能。这篇文章对我帮助很大http://hi.baidu.com/mizuda/item/fdd9c38a8e8237d9d1f8cdf6首先要了解上传下载的流程,这需要涉及到http的知识。基本原理是,连入网络后如需下载某开关值,需要先用client,print以http格式发送设备、开关编号及你的U-ApiKey号码(为了身份认证),服务器会返回一串Json代码,通过读取某一特定位置(倒数第二位)的值来判断开关的状态;如需上传,需要用client.print将待上传的值以特定的http格式,连同设备、传感器号及U-ApiKey发送。需要注意的是,下载是分发送与接收两个步骤进行的。注意:yeelink要求两次上传有最小时间间隔10s!否则传了也没用。Yeelink在警示方面做得也是不错的,主要有邮件与微博警报,可以在yeelink用户中心进行设置,方法很简单,这里也不再阐述。Yeelink还有手机app,使用起来同样很简单。视频:Yeelink网络控制 之 多设备远程控制
http://www.tudou.com/programs/view/wxgbA_44epo/Yeelink网络控制 之 风扇遥控
http://www.tudou.com/programs/view/WJu1CnqajMA/Yeelink网络控制 之 邮件警报
http://www.tudou.com/programs/view/OBjlPhrJ_kA/Yeelink网络控制 之 微博警报
http://www.tudou.com/programs/view/_T4UZ7EsGbg/
   这样,项目就基本完成了,历时一个月,走过不少弯路,但是都被一一化解,想想真是不容易。写作本文,一是备忘,更多的是希望新手们能免于重蹈我的覆辙。Arduino的功能是很强大的,也具有趣味性,但是往往一些意想不到的状况会消磨新手的兴趣。这时,类似极客工坊的网站应该承担起责任,为新手们提供技术支持与交流平台,引领新人们成长。Arduino是软硬件全部开源的单片机,所以希望大神们能多多将制作的产品与大家共享,交流开发中遇到的问题,与网友们共同交流,这也应该是arduino设计者们开源想要达到的效果。
成本估算:2012最新款 Arduino UNO R3 开发板配SUB线   *2…………¥78新版 Arduino Ethernet W5100 网络扩展板SD卡扩展…………¥40Arduino IIC/I2C/接口 LCD1602转接板 ………… ¥6.5LCD1602A液晶特价促销…………¥8.2AOSONG(奥松)DTH11温湿度传感器,DHT11温湿度模块…………¥4.5HS0038B HS0038B SIP3 红外遥控接收头 红外接收管 VISHAY…………¥1.8优质面包板/迷你小面包板/ 实验板 长8.5CM 宽5.5CM 可以组合拼接…………¥5.5GP 超霸无线话筒电池 玩具遥控器电池 6F22 9V电池 GP9V电池 *2 …………¥3.49V 电池盒带线电池盒 不带盖 开关 *2…………¥3.6蜂鸣器…………¥0.6以上¥152.1
以下材料只使用部分盒装14种长度140根优质跳线面包板线 面包板专用线 面包板跳线…………¥10.0面包线 面包板线面包板扎线 连接线测试线 实验线杜邦线一捆65条…………¥5.3常用小功率三极管包等17种170只…………¥7.51/4W五色环电阻1%精密度 金属膜电阻包 30种常用阻值每种阻值20个 …………¥5.95MM发射管 940nm红外发射管(20只) …………¥2.6线束 杜邦线彩排40P 双头1P 一头公一头母 长20CM 12股优质铜…………¥6.5网线、焊锡、按钮开关费用不计总计:¥152.1+¥37.8=¥189.9

这是我完成的首个arduino作品,欢迎大家交流指教!

最后是代码:
控制uno:
网络uno:

库文件:
红外IRremote:
lcd:
dht11:
打包:

Damn_intuition 发表于 2013-10-20 15:10:29

感谢分享,写的非常详细,非常适合新手看,哈哈哈。
:D
感觉可以给那些毕业生当毕业设计了。

平生须臾 发表于 2013-10-20 23:11:31

最近在做物联网相关的东东不怎么懂,刚好可以看看楼主的帖子学习学习

ntwhq 发表于 2013-11-2 09:12:59

“由于资料比较多,一开始使用的是乐联网,但是发现网关配置的东西一直搞不清楚,不仅需要网关地址还要公网地址,不知道是什么意思,不知道怎么配置,搞了半天没弄明白,就放弃了。”
我也有同样的疑惑,乐为网的教程写得很含糊,希望能有设置过的人来解释一下。

CALL_Me_Twenty 发表于 2013-11-26 23:02:32

lz能给我讲下格力空调编码每位代表什么吗

HeartRain 发表于 2013-11-27 14:43:30

请问你格力空调是用IRsend irsend;
irsend.sendNEC(0xFFA25D ,32);
发的还是raw

林定祥 发表于 2014-3-25 11:02:07

本帖最后由 林定祥 于 2014-3-25 11:17 编辑

我的应用和你差不多,网络这端已经通过了,现在在貌似最简单的地方卡壳了,想请教下.先用案例读遥控器代码,试过几个遥控器,得到是 “Unknown encoding:"********(32bit);重发时不知道该发什么规格,现在发
void loop() {
   
      irsend.sendNEC(0x35D20C7, 32);
      delay(3000);
      }
不知道问题出在哪?1.不知格式发NEC格式可以吗?2.取到的是8位数,后面还是32吗?3.你用了三极管放大,但是从电路看晶体管有反向作用,编码需要取反吗?

xuqin3 发表于 2014-4-1 23:41:24

本帖最后由 xuqin3 于 2014-4-1 23:43 编辑

我用这段代码连接乐联网,OK的,Nano+ENC28J60模块,代码和接线如下:

#include <EtherCard.h>
#define OUT

#define REQUEST_RATE 30000 // 3秒
//需要根据你的实际网络环境进行更改
//Mac**可修改**
static byte mymac[] = {
0x74,0x69,0x69,0x22,0x33,0x31 };
//IP**可修改**
static byte myip[] = {
192,168,1,114 };
//网关**可修改**
static byte gwip[] = {
192,168,1,1 };
//DNS**可修改**
static byte dnsip[] = {
192,168,1,1 };

// remote website name
char website[] PROGMEM = "www.lewei50.com";
char urlBuf[] PROGMEM = "/api/V1/gateway/UpdateSensors/01"; // 01应该更改为你对应的网关标识**要修改**
char apiKey[] PROGMEM = "userkey:8072aaf800ef3323742e6b2"; //需要更改为你的userkey**要修改**
byte Ethernet::buffer;   //tcp/ip缓冲区
static long timer;

// called when the client request is complete
static void my_result_cb (byte status, word off, word len) {
Serial.print("<<< reply ");
Serial.print(millis() - timer);
Serial.println(" ms");
Serial.println((const char*) Ethernet::buffer + off);
}

void setup () {
//sensors.begin();
Serial.begin(9600);
Serial.println("\n");

if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
    Serial.println( "Failed to access Ethernet controller");

ether.staticSetup(myip, gwip, dnsip);

while (ether.clientWaitingGw())
    ether.packetLoop(ether.packetReceive());
Serial.println("Gateway found");

timer = - REQUEST_RATE; // start timing out right away
}

void loop () {
ether.packetLoop(ether.packetReceive());

if (millis() > timer + REQUEST_RATE) {
    timer = millis();
    Serial.println("\n>>> REQ");
    static char buf;
    get_send_string(buf);
    if (!ether.dnsLookup(website))
      Serial.println("DNS failed");
    ether.printIp("Server: ", ether.hisip);
    ether.httpPost (urlBuf, website, apiKey, buf, my_result_cb);
}
}

void get_send_string(OUT char *p){
//sensors.requestTemperatures();
uint16_t Tc_100 =244;// 读取传感器的值,这里固定值
uint8_t whole, fract;
whole = Tc_100/10 ;// separate off the whole and fractional portions
fract = Tc_100 % 10;
sprintf(p,"[{\"Name\":\"T1\",\"Value\":\"%d.%d\"}]",whole,fract);//T1应该更改为你对应的设备标识**要修改**
}

mrone 发表于 2014-4-10 14:06:50

感觉楼主应该对arduino挺熟悉的,想请教您一个问题:就拿您这个项目来说,如果要求arduino芯片不能用线跟面包板上的元件连在一起,能实现么?

mrone 发表于 2014-4-10 14:07:18

感觉楼主应该对arduino挺熟悉的,想请教您一个问题:就拿您这个项目来说,如果要求arduino芯片不能用线跟面包板上的元件连在一起,能实现么?

for 发表于 2014-5-19 19:03:44

能控制美的空调吗?

Jone 发表于 2014-5-31 21:56:30

xuqin3 发表于 2014-4-1 23:41 static/image/common/back.gif
我用这段代码连接乐联网,OK的,Nano+ENC28J60模块,代码和接线如下:

#include


谢谢,参考一下。程序和接线,说得很清楚。

Jone 发表于 2014-5-31 21:57:18

谢谢分享。学到了很多。

ゞ從淚認識む 发表于 2014-9-7 18:22:00

楼主你是叫陈力么????

chzhewl 发表于 2014-10-29 10:39:45

很详细,谢谢分享
页: [1] 2
查看完整版本: Arduino uno+w5100+yeelink实现红外转码与网络控制