收藏官网首页
查看: 50837|回复: 31

【MEGA64+ESP8266】之智能家居

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
跳转到指定楼层
楼主
发表于 2016-7-25 00:58:55 来自手机 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
免费使用STM32、APP自动代码生成工具
本帖最后由 Genius 于 2016-8-25 14:51 编辑

就是辣么棒!一个app就能控制所有家电、家居。
原创**,转载请注明来自:http://club.gizwits.com/thread-2939-1-1.html
作者:孤独的蛇
【开源硬件】机智云智能硬件创新大赛  http://club.gizwits.com/thread-2646-1-1.html

看到这个活动,心里痒痒的,尝试参加一下。左等右等申请的gokit3还没到,手头正好有一块N年前自己焊接的MEGA64最小系统板和一块esp8266-01,索性就用这两个设备来设计一个智能家居小系统。整体还在构思中,待构思完毕后再制作过程发布。



   通过几天的考虑,为本次设计的智能家居系统做出如下的设计:
1、通过手机APP等移动设备,连接互联网机智云,通过ESP8266进行互联网通信,获取控制命令,并将命令通过RS232串口通信传给MCU:MEGA64,最终由MEGA64对具体的设备进行控制;
2、本次智能家居可进行操作或获取信息的内容主要为:
    a、智能开关:可以通过移动客户端远程对智能开关进行控制开关的通电与断电的操作。由此可衍伸出很多电器设备的控制,只要控制电源的开和关的,都可以通过智能开关进行控制。
    b、智能调光器:可以通过移动客户端,控制各电灯的亮暗,也可以通过环境亮度来进行自动控制。
    c、智能插座:和智能开关类似,只不过这个控制的是插座的通电和断电。
    d、智能窗帘:可以对窗帘的打开和关闭进行操作,也可以设定窗帘打开的多少,从而满足亮度的需要。
    e、智能自动收衣服:通过雨滴传感器传来的数据,判断现在是否下雨来对衣架的回收或伸展,保证衣服的干燥。
    f、智能风扇:可以控制风扇的转速。
    g、智能心情灯:可根据需要对RGB灯的三种颜色进行调节,从而控制灯的颜色,随心而变,增加氛围。
    h、智能音乐播放器:可以进行音乐的播放、暂停、上一曲、下一曲、随机播放、循环播放灯操作。
    i、智能安防窗户打开报警器:可进行安防监控,如果窗户被打开了,则会远程发送报警通知。
    j、智能红外解码转发器:可对各种电器的遥控器进行解码,并存储,然后通过远程控制发出相应的红外遥控信号进行控制电器,相当于遥控器。
    k、火焰防火灾报警器:监测家里的环境是否有着火现象,如有则进行消息通知。
    l、可燃气体报警器:监测环境中是否含有可燃气体,并达到一定的浓度后进行消息通知。
    m、自动浇花器:通过检测花盆中土壤的湿度进行控制是否对花浇水。
    n、温度、湿度表:通过检测环境的温度和湿度,并上报到移动客户端显示。


以上是对本次智能家居的任务设计方案,后面则对方案进行实际的选材设计与制作。
由于实际情况的限制,本次设计的一些内容,不是实际的220V交流电的操作,而是通过模拟的方式用5V直流电进行操作。其模拟的方法和220V交流电的实际操作方法是一致的,只是有些地方需要进行电路的设计,在后期的制作过程中也会给出这些设计。【MEGA64+ESP8266】之智能家居系统结构图







【MEGA64 ESP8266】之智能家居系统结构图【MEGA64 ESP8266】之智能家居系统结构图.png.png (31.1 KB, 下载次数: 1680)

【MEGA64 ESP8266】之智能家居系统结构图【MEGA64 ESP8266】之智能家居系统结构图.png.png

智能家居-机智云接入串口通信协议文档.pdf

137.46 KB, 下载次数: 290, 下载积分: 威望 1

土壤湿度传感器模块电路图.pdf

24.87 KB, 下载次数: 158, 下载积分: 威望 1

M64_BIT_OPERATION.zip

1.9 KB, 下载次数: 162, 下载积分: 威望 1

MEGA64_ESP8266_GOKIT.zip

15.47 KB, 下载次数: 221, 下载积分: 威望 1

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
来自 22#
 楼主| 发表于 2016-8-24 17:02:18 | 只看该作者
本帖最后由 孤独的蛇 于 2016-8-24 17:08 编辑

前段时间一直跑医 院,导 致没有什么时间和心 思在上面,加上没有足够的工具,所以本次的设计只能到这里了,只是一个框架,具体的应用还是要靠自己设计。
手机APP现在没有时间去研究了,毕竟不是这方面的人。。。。只能将就使用demoAPP来进行控制了。。。。

手机APP连接设备的视频,为什么是倒立的???
http://v.youku.com/v_show/id_XMTY5NzkwMzk5Ng==.html

远程控制LED灯开关:
http://v.youku.com/v_show/id_XMTY5NzkwNzEyMA==.html

远程插座控制:这里使用LED灯来模拟开关
http://v.youku.com/v_show/id_XMTY5NzkwNzg3Mg==.html

RGB灯的控制:
http://v.youku.com/v_show/id_XMTY5NzkwOTI0MA==.html

音乐的控制:
http://v.youku.com/v_show/id_XMTY5NzkxMTM2NA==.html

直流马达的控制:
http://v.youku.com/v_show/id_XMTY5NzkxMDAwMA==.html

各种传感器:
http://v.youku.com/v_show/id_XMTY5NzkxMDcyMA==.html

遥控器的学习与控制:
http://v.youku.com/v_show/id_XMTY5NzkxMjAwNA==.html

至此,本次设计的所有东西完毕,对于手机APP,只能等到以后有时间的时候再进行研究了,弄好后我也会在这里附上的

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
来自 23#
 楼主| 发表于 2016-8-24 17:40:24 | 只看该作者
[ 项目名称 ] MEGA64+ESP8266之智能家居
[ 项目概述 ]本项目使用最平常的单片机和常见的wifi模块制作一个智能家居的简单模型,通过机智云联网进行控制操作。
[ 硬件准备 ]
1、MEGA64最小系统板
2、ESP8266wifi模块
3、RGB三色灯,LED灯数个
4、音乐播放器(WTV020-SD语音模块)
5、直流马达及驱动
6、火焰传感器、雨滴传感器、土壤湿度传感器、光传感器、可燃气体传感器、温湿度传感器
7、红外接收一体芯片B18838和红外发射二极管
8、限位开关、编码器等
[ 使用软件环境 ] AvrStudio编写C语音程序  访问密码 2eff
[ 相关源码 ]MEGA64_ESP8266_GOKIT.c  访问密码 2889  、M64_BIT_OPERATION.H  访问密码 c82d
[ 项目介绍 ]

各种资料集合:https://yunpan.cn/cMuJYXrUqqKZy  访问密码 787e


ATmega64_64L_cn.pdf (2.76 MB, 下载次数: 22)





ESP8266刷入机智云.rar (6.48 MB, 下载次数: 525)









M64_BIT_OPERATION.H (12.85 KB, 下载次数: 11)

M64_BIT_OPERATION.zip (1.9 KB, 下载次数: 23)



MEGA64_ESP8266_GOKIT.c (53.68 KB, 下载次数: 11)

MEGA64_ESP8266_GOKIT.rar (215.49 KB, 下载次数: 58)

MEGA64_ESP8266_GOKIT.zip (15.47 KB, 下载次数: 27)











WTV020-SD语音模块 SD卡语音模块 游戏机语音模块.doc (1.16 MB, 下载次数: 13)















7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
推荐
 楼主| 发表于 2016-7-28 23:21:27 | 只看该作者

    通过几天的考虑,为本次设计的智能家居系统做出如下的设计:
1、通过手机APP等移动设备,连接互联网机智云,通过ESP8266进行互联网通信,获取控制命令,并将命令通过RS232串口通信传给MCU:MEGA64,最终由MEGA64对具体的设备进行控制;
2、本次智能家居可进行操作或获取信息的内容主要为:
    a、智能开关:可以通过移动客户端远程对智能开关进行控制开关的通电与断电的操作。由此可衍伸出很多电器设备的控制,只要控制电源的开和关的,都可以通过智能开关进行控制。
    b、智能调光器:可以通过移动客户端,控制各电灯的亮暗,也可以通过环境亮度来进行自动控制。
    c、智能插座:和智能开关类似,只不过这个控制的是插座的通电和断电。
    d、智能窗帘:可以对窗帘的打开和关闭进行操作,也可以设定窗帘打开的多少,从而满足亮度的需要。
    e、智能自动收衣服:通过雨滴传感器传来的数据,判断现在是否下雨来对衣架的回收或伸展,保证衣服的干燥。
    f、智能风扇:可以控制风扇的转速。
    g、智能心情灯:可根据需要对RGB灯的三种颜色进行调节,从而控制灯的颜色,随心而变,增加氛围。
    h、智能音乐播放器:可以进行音乐的播放、暂停、上一曲、下一曲、随机播放、循环播放灯操作。
    i、智能安防窗户打开报警器:可进行安防监控,如果窗户被打开了,则会远程发送报警通知。
    j、智能红外解码转发器:可对各种电器的遥控器进行解码,并存储,然后通过远程控制发出相应的红外遥控信号进行控制电器,相当于遥控器。
    k、火焰防火灾报警器:监测家里的环境是否有着火现象,如有则进行消息通知。
    l、可燃气体报警器:监测环境中是否含有可燃气体,并达到一定的浓度后进行消息通知。
    m、自动浇花器:通过检测花盆中土壤的湿度进行控制是否对花浇水。
    n、温度、湿度表:通过检测环境的温度和湿度,并上报到移动客户端显示。


以上是对本次智能家居的任务设计方案,后面则对方案进行实际的选材设计与制作。
由于实际情况的限制,本次设计的一些内容,不是实际的220V交流电的操作,而是通过模拟的方式用5V直流电进行操作。其模拟的方法和220V交流电的实际操作方法是一致的,只是有些地方需要进行电路的设计,在后期的制作过程中也会给出这些设计。


智能家居.png (31.1 KB, 下载次数: 1671)

【MEGA64+ESP8266】之智能家居系统结构图

【MEGA64+ESP8266】之智能家居系统结构图

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
推荐
 楼主| 发表于 2016-8-17 16:38:02 | 只看该作者
汉枫LPB120模块
【三、智能插座】的设计
智能插座和智能开关的原理是一样的,这里就不再阐述。

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
推荐
 楼主| 发表于 2016-8-17 17:34:11 | 只看该作者
【五、音乐MP3控制】
这里使用的是WTV020-SD语音模块(因为手上就有这个模块了。。。有好的模块可以替换掉)
1、产品特征
  
Ø  产品支持外挂最大1G容量的SD卡;
  
Ø  支持播放4Bit ADPCM格式文件;
  
Ø  自动识别语音文件;
  
Ø  可装载6KHz~32KHz、36KHz采样率AD4音频;
  
Ø  可装载6KHz~16KHz采样率WAV音频;
  
Ø  16bitDAC及PWM音频输出;
  
Ø  最多可存放512段语音;
  
Ø  WTV020-SD-20S,WTV020-SD-16P两种模块类型;
  
  
  
  
Ø  支持微型处理器和按键控制;
  
Ø  可以调用任意段落的语音进行播放;
  
Ø  掉电保存操作数据功能;
  
Ø  加载语音无需软件辅助,直接放置语音到SD卡便可;
  
Ø  支持文件组合播放,包括静音组合;
  
Ø  工作电压:DC2.5~3.6V;
  
Ø  静态电流:16uA(不插SD卡)
  
2、产品概述
WTV020-SD模块是一款可重复擦写语音内容的大容量存储类型的语音模块,可外挂最大容量为1GB的SD卡存储器。能加载WAV格式语音和AD4格式语音。
WTV020-SD模块以WTV020SD-20S语音芯片为主控核心,具有MP3控制模式,按键一对一控制模式(3段语音跟5段语音两种),上电循环播放控制模式以及二线串口控制模式。控制模式是在芯片制样时设置的,在操作过程中不能切换各种控制模式,如需要使用哪种模式进行控制,可向我司订做。
MP3控制模式:具有播放/停止,下一曲,上一曲,音量+,音量-等功能。
按键一对一控制模式(3段语音):一个按键对应触发一个语音,具备播放3段语音及调节音量加减的功能,所有按键被默认为脉冲不可重复触发。
按键一对一控制模式(5段语音):具有三种控制方式,⑴、所有按键均为脉冲可重复触发;⑵、所有按键均为播放/停止触发(单曲不循环);⑶、所有按键均为播放/停止(单曲可循环)。
上电循环播放控制模式:上电后,不需要触发任何I/O口,直接自动播放SD卡存储器内的所有语音,并拥有断电记忆点播放功能,当断电后再上电,自动从上次的断电处继续播放语音。具有两种控制方式,⑴、P04拥有脉冲播放/暂停功能;⑵、P05拥有电平播放/暂停功能。
二线串口控制模式:由单片机通过CLK时钟和DI数据线发送数据对WTV020-SD模块进行控制。可随意播放任何一个地址的语音。此状态下,能进行语音组合播放。
语音内容更新直接通过SD卡读卡器在PC上更换。该模块支持FAT文件系统。支持6KHz~32KHz、36KHz采样率的AD4语音和6KHz~16KHz采样率的WAV音频,能自动识别语音采样率以及语音文件格式。

点击这里可以下载此文档手册 (  访问密码 8861 )

  1. //音乐设置
  2. #define STOP 0xffff        //停止播放
  3. #define PLAY 0xfffe        //播放
  4. #define PAUSE 0xfffe        //暂停
  5. #define SINGLE_CYCLE 0xfffd        //单曲循环
  6. #define STOP_CYCLE 0xfffc        //停止循环
  7. #define ALL_CYCLE 0xfffb        //所有循环
  8. #define REST PORTG_2
  9. #define DI PORTG_1
  10. #define CLK PORTG_0
  11. volatile unsigned int voice_buf[8] = {0xfff0,0xfff1,0xfff2,0xfff3,0xfff4,0xfff5,0xfff6,0xfff7};        //音量 0xf0为静音  0xf7 为音量最大
  12. volatile unsigned char voice;
  13. volatile unsigned int song_number;
复制代码
  1. void init_fun()        //初始化模块
  2. {
  3.         voice = 1;        //初始音量设置为3,        0为最小,即静音;        7为最高
  4.    
  5.     song_number = 0;        //第1首歌曲
  6.     REST = 1;
  7.     DI = 1;
  8.     CLK = 1;
  9.     reset_fun();
  10.     delay_ms(300);
  11.     sent_data(voice_buf[voice]);
  12.     sent_data(ALL_CYCLE);
  13. }

  14. void reset_fun()        //复位模块
  15. {
  16.         REST = 0;
  17.         delay_ms(6);
  18.           REST = 1;
  19.         delay_ms(6);
  20. }

  21. void sent_data(uint dat)        //发送数据
  22. {
  23.         unsigned int i;
  24.         uint j;
  25.         for(i=0;i<16;i++)
  26.         {
  27.                 CLK = 0;
  28.                 j = (dat >> (15 - i)) & 0x01;
  29.                 DI = j;
  30.                 delay_ms(2);
  31.                 CLK = 1;
  32.                 delay_ms(2);
  33.         }
  34.         DI = 1;
  35.         CLK = 1;
  36. }
  37. void next_song()        //下一曲
  38. {
  39.         song_number++;
  40.         if(song_number > 0x1ff) song_number = 0x00;
  41.         sent_data(song_number);
  42. }
  43. void pre_song()        //上一曲
  44. {
  45.         if(song_number == 0x00)
  46.         {
  47.                 song_number = 0x200;
  48.         }
  49.         song_number--;
  50.         sent_data(song_number);
  51. }
  52. void voice_up()        //音量加
  53. {
  54.         voice++;
  55.         if(voice >= 7) voice = 7;
  56.         sent_data(voice_buf[voice]);
  57. }

  58. void voice_down()        //音量减
  59. {
  60.         if(voice <= 0) voice = 1;
  61.         voice--;
  62.         sent_data(voice_buf[voice]);
  63. }
  64. void play_song(int song_num)
  65. {
  66.   song_number = song_num;
  67.   if(song_number > 0x1ff) song_number = 0x00;
  68.   sent_data(PLAY);
  69.   sent_data(song_number);
  70. }
复制代码


串口数据处理部分程序
  1. case 0x20://设置music  ok
  2.                                                                 temp1 = ((status1[3] & 0b11100000) >> 5);
  3.                                                                 status[3] = status1[3];
  4.                                                                 status[2] = status1[2];
  5.                                                                 temp2 = (((status1[2] & 0b00000001) << 3) | temp1);
  6.                                                                 if(temp2 != 0)
  7.                                                                 {
  8.                                                                         switch(temp2)
  9.                                                                         {
  10.                                                                                 case 0x01://播放/暂停
  11.                                                                                         sent_data(PLAY);break;
  12.                                                                                 case 0x02://上一曲
  13.                                                                                         pre_song();break;
  14.                                                                                 case 0x03://下一曲
  15.                                                                                         next_song();break;
  16.                                                                                 case 0x04://音量+
  17.                                                                                         voice_up();break;
  18.                                                                                 case 0x05://音量-
  19.                                                                                         voice_down();break;
  20.                                                                                 case 0x06://停止播放
  21.                                                                                         sent_data(STOP);break;
  22.                                                                                 case 0x07://单曲循环
  23.                                                                                         sent_data(SINGLE_CYCLE);break;
  24.                                                                                 case 0x08://所有循环
  25.                                                                                         sent_data(ALL_CYCLE);break;
  26.                                                                                 case 0x09://停止循环
  27.                                                                                         sent_data(STOP_CYCLE);break;
  28.                                                                                 case 0x0a://随机播放一首歌
  29.                                                                                         sent_data(random_fun(0,512));
  30.                                                                                         break;//暂时不设置
  31.                                                                         }
  32.                                                                         status[3] = (status1[3] & 0b00011111);
  33.                                                                         status[2] = (status1[2] & 0b11111110);
  34.                                                                 }
  35.                                                                 break;
复制代码
主函数中音乐相关处理程序:
  1.   //音乐处理
  2.                 if(command_music!=0)
  3.                 {
  4.                         switch(command_music)
  5.                         {
  6.                                 case 0x00:break;//无动作
  7.                                 case 0x01://播放/暂停
  8.                                 sent_data(PLAY);
  9.                                 break;
  10.                                 case 0x02://上一曲
  11.                                 pre_song();
  12.                                 break;
  13.                                 case 0x03://下一曲
  14.                                 next_song();
  15.                                 break;
  16.                                 case 0x04://音量加
  17.                                         voice_up();
  18.                                         break;
  19.                                 case 0x05://音量减
  20.                                         voice_down();
  21.                                         break;
  22.                                 case 0x06://停止
  23.                                         sent_data(STOP);
  24.                                         break;
  25.                                 case 0x07://单曲循环
  26.                                         sent_data(SINGLE_CYCLE);
  27.                                         break;
  28.                                 case 0x08://所有循环
  29.                                         sent_data(ALL_CYCLE);
  30.                                         break;
  31.                                 case 0x09://停止循环
  32.                                         sent_data(STOP_CYCLE);
  33.                                         break;
  34.                                 case 0x0a://随机播放一首歌曲
  35.                                         play_song(random_fun(0,512));
  36.                                         break;
  37.                         }
  38.                 command_music = 0;
  39.                 }
复制代码





0

主题

4

帖子

28

积分

新手上路

Rank: 1

积分
28
32#
发表于 2019-3-13 09:45:15 | 只看该作者
谢谢无私分享

0

主题

3

帖子

76

积分

注册会员

Rank: 2

积分
76
31#
发表于 2017-9-5 15:40:38 | 只看该作者
可以学习一下么

0

主题

3

帖子

76

积分

注册会员

Rank: 2

积分
76
30#
发表于 2017-9-5 15:40:01 | 只看该作者
可以学习一下么

0

主题

1

帖子

21

积分

新手上路

Rank: 1

积分
21
29#
发表于 2017-6-6 19:05:40 | 只看该作者
校园创客福利
学习了,可是楼主下次能不能把所有的文件放在一个包里?这样下载要很多金币啊,屌丝穷

0

主题

1

帖子

25

积分

新手上路

Rank: 1

积分
25
28#
发表于 2017-4-17 14:57:56 | 只看该作者
现在用mega32 的和 8266通讯当中,刚好可以借鉴一下,谢谢楼主

10

主题

112

帖子

1545

积分

金牌会员

Rank: 6Rank: 6

积分
1545
27#
发表于 2016-11-18 15:42:27 | 只看该作者
楼主好,360云盘的内容都走丢了

0

主题

2

帖子

160

积分

注册会员

Rank: 2

积分
160
26#
发表于 2016-10-15 17:01:01 | 只看该作者
你好,我正在使用wtv020模块做一个MP3播放模块,我想问一下,这些控制模式,如MP3模式、二线串口模式等五种模式,在控制的时候是如何选定我们当前是在使用MP3模式还是二线串口模式?我现在一直不能让这个模块发声~~好急好郁闷

50

主题

94

帖子

2135

积分

金牌会员

Rank: 6Rank: 6

积分
2135
25#
发表于 2016-9-9 20:20:31 | 只看该作者
楼主辛苦了,支持这么多的外设。。。

0

主题

12

帖子

394

积分

中级会员

Rank: 3Rank: 3

积分
394
24#
发表于 2016-9-6 11:53:49 | 只看该作者
免费使用STM32、APP自动代码生成工具
跟着楼主学习学习

7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
21#
 楼主| 发表于 2016-8-19 16:05:02 | 只看该作者
【十三、自动浇花】自动浇花系统

自动浇花系统的原理是根据土壤传感器检测花盆土壤的干湿度情况进行控制浇水电机(或阀门)的转动,从而使花盆内的水分保持湿润。


通过用MCU的ADC转换,可以把AO输出的数值转换成MCU可处理的数据,根据转换值的大小就可以知道土壤的干湿情况。转换值越大,则表明土壤越干,越小表示越湿润。

定义PC6为控制输出,低电平表示湿润,高电平输出表示干燥,需要浇水。从而可以控制电机或阀门的开关。
  1. #define JH_OUT PORTC_6 //自动浇花输出
复制代码
  1. //土壤湿度自动浇花,这个值可以根据需要改动,也可以通过一个数据点来进行人工设置
  2.                 if(getADC_average_value(2) > 300)
  3.                 {
  4.                         JH_OUT = 1;
  5.                 }
  6.                 else
  7.                 {
  8.                         JH_OUT = 0;
  9.                 }
复制代码









7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
20#
 楼主| 发表于 2016-8-19 13:14:21 | 只看该作者
本帖最后由 孤独的蛇 于 2016-8-19 13:24 编辑

【十二、按键处理】按键处理程序

这里设置了3个按键,分别是KEY1,KEY2,KEY3
其功能分别是:
KEY1:短按:Ari模式配置wifi;长按:AP模式配置wifi
KEY2:短按:手动上传数据;长按:重置wifi
KEY3:短按:自定义;长按:自定义
这里的功能都可以自己定义。
按键处理代码:
  1.   if(KEY1 == 1 && KEY2 == 0 && KEY3 == 0)//单独按下KEY1键
  2.                 {
  3.                         init_ok = 0;
  4.                         time_count=0;
  5.                         while(KEY1 == 1 && KEY2 == 0 && KEY3 == 0)
  6.                         {
  7.                                 delay_ms(10);
  8.                                 time_count++;
  9.                                 if(time_count>300)
  10.                                 {
  11.                                         SET_IR_LED;//打开LED提示是长按了
  12.                                 }
  13.                         }
  14.                         if(time_count>300)//时间为3秒,即长按按键
  15.                         {
  16.                                 //长按按键处理程序
  17.                                 SET_IR_LED;
  18.                                 delay_ms(1000);
  19.                                 CLR_IR_LED;
  20.                                 mcu_send_peizhi[8] = 0x01;
  21.                                 mcu_send_peizhi[9] = 0x10;
  22.                                 COM_TX_Str((unsigned char *) mcu_send_peizhi,10);//配置AP模式
  23.                         }
  24.                         else
  25.                         {
  26.                                 //短按按键处理程序
  27.                                 SET_IR_LED;
  28.                                 COM_TX_Str((unsigned char *) mcu_send_resetwifi,9);//重置wifi
  29.                                 delay_ms(2500);
  30.                                 CLR_IR_LED;
  31.                                 COM_TX_Str((unsigned char *) mcu_send_peizhi,10);//配置airlink模式
  32.                         }
  33.                 }
  34.                 if(KEY2 == 1 && KEY1 == 0 && KEY3 == 0)
  35.                 {
  36.                         time_count=0;
  37.                         while(KEY2 == 1 && KEY1 == 0 && KEY3 == 0)
  38.                         {
  39.                                 delay_ms(10);
  40.                                 time_count++;
  41.                                 if(time_count>300)
  42.                                 {
  43.                                         SET_LED_1;//打开LED提示是长按了
  44.                                 }
  45.                         }
  46.                         if(time_count>300)//时间为3秒,即长按按键
  47.                         {
  48.                                 //长按按键处理程序
  49.                                 SET_LED_1;
  50.                                 delay_ms(1000);
  51.                                 CLR_LED_1;
  52.                                 COM_TX_Str((unsigned char *) mcu_send_resetwifi,9);//重置wifi
  53.                                 init_ok = 0;
  54.                         }
  55.                         else
  56.                         {
  57.                                 //短按按键处理程序
  58.                                 SET_LED_1;
  59.                                 delay_ms(500);
  60.                                 CLR_LED_1;
  61.                                 MCU_send_mast(0x05);//MCU主动上报数据
  62.                         }
  63.                 }
  64.                 if(KEY3 == 1 && KEY1 == 0 && KEY2 == 0)
  65.                 {
  66.                         time_count=0;
  67.                         while(KEY3 == 1 && KEY1 == 0 && KEY2 == 0)
  68.                         {
  69.                                 delay_ms(10);
  70.                                 time_count++;
  71.                                 if(time_count>300)
  72.                                 {
  73.                                         SET_LED_2;//打开LED提示是长按了
  74.                                 }
  75.                         }
  76.                         if(time_count>300)//时间为3秒,即长按按键
  77.                         {
  78.                                 //长按按键处理程序
  79.                                 SET_LED_2;
  80. //这里写长按处理程序
  81.                                 CLR_LED_2;
  82.                         }
  83.                         else
  84.                         {
  85.                                 SET_LED_2;       
  86. //这里写短按处理程序
  87.                                 CLR_LED_2;
  88.                                
  89.                         }
  90.                 }
复制代码



7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
19#
 楼主| 发表于 2016-8-19 13:07:00 | 只看该作者
【十一、串口设置】串口通信设置

MEGA64有两个串口,由于我的这块板子的串口0坏了,所以本次使用的是串口1进行与wifi模块通信。

  1. <font color="#ff0000">//串口设置</font>
  2. #define baud 9600        //设置波特率的大小
  3. #define baud_setting (uint)(((ulong)F_CPU/(16*(ulong)baud))-1)        //波特率计算公式
  4. #define baud_H        (uchar)(baud_setting >> 8)        //提取高位
  5. #define baud_L        (uchar)(baud_setting)        //低位
复制代码
  1. #define start_usart1 (UCSR1B |=_BV(RXCIE1))//开启串口1中断
  2. #define stop_usart1 (UCSR1B &=~_BV(RXCIE1))//关闭串口1中断
复制代码
  1. <font color="#ff0000">//串口初始化</font>
复制代码
  1. <font color="#ff0000">//串口接收中断函数</font>
  2. ISR(USART1_RX_vect)
  3. {
  4.         uchar temp,check=0;
  5. //        UCSR1B &=~_BV(RXCIE1);        //关闭串口接收中断
  6.         stop_usart1;
  7.         temp = UDR1;
  8.         COM_TX(temp);
  9.         if(is_header == 0)//是否已经收到数据头0xffff
  10.         {
  11.                 if((last_com_dat==0xff) && (temp ==0xff))//判断上一个数据是否是0xff并且当前接收到的数据是0xff
  12.                 {
  13.                         is_header = 1;//标志已经接收到数据头了
  14.                 }
  15.         }
  16.         else//如果已经接收到了数据头0xffff
  17.         {
  18.                 if(!((last_com_dat==0xff) && (temp ==0x55)))//判断数据中是否含有0xff的数据,含有则把0xff后面的0x55给去掉
  19.                 {
  20.                         if(is_len == 0)//如果没接收完数据长度2字节数据,则继续接收
  21.                         {
  22.                                 len_count++;
  23.                                 if(len_count == 2)
  24.                                 {
  25.                                         is_len = 1;
  26.                                         dat_len = temp;//保存长度数据的低字节
  27.                                         dat_count = 0;
  28.                                         len_count = 0;
  29.                                 }
  30.                                 else
  31.                                 {
  32.                                         dat_len = (temp << 8);//保存长度数据的高字节
  33.                                 }
  34.                         }
  35.                         else//已经接收完毕长度2字节数据,后面紧接着接收数据
  36.                         {
  37.                                 COM_DAT[dat_count] = temp;
  38.                                 dat_count++;
  39.                                 if(dat_count >= dat_len)//接收数据完毕
  40.                                 {
  41.                                         dat_count = 0;
  42.                                         is_len = 0;
  43.                                         is_header = 0;
  44.                                         last_com_dat = 0;
  45.                                         check = check_fun((unsigned char *) COM_DAT,dat_len - 1);//注意,要把数据中的校验和去掉
  46.                                         check =(uchar) ((check + dat_len) % 256);
  47.                                         if(check == COM_DAT[dat_len-1])//如果校验和正确则进行数据处理
  48.                                         {
  49.                                                
  50.                                                 last_com_dat = 0;
  51.                                                 dat_count = 0;
  52.                                                 is_len = 0;
  53.                                                 is_header = 0;
  54.                                                 command_count2 = COM_DAT[1];//获取序列号
  55.                                                 if(init_ok)
  56.                                                 {
  57.                                                         if(command_count1 != command_count2)//为了排除重复接收的3次
  58.                                                         {
  59.                                                                 com_dat_ok_flag = 1;
  60.                                                         }
  61.                                                         else
  62.                                                         {
  63.                                                                 com_dat_ok_flag = 0;
  64.                                                         }
  65.                                                 }
  66.                                                 else
  67.                                                 {
  68.                                                         com_dat_ok_flag = 1;
  69.                                                 }
  70.                                         }
  71.                                         else//如果校验和不正确,则返回错误消息
  72.                                         {
  73.                                                 COM_TX_Str((unsigned char *) mcu_send_ffxx,10);//发送校验和错误消息
  74.                                         }
  75.                                         command_count1 = command_count2;
  76.                                 }
  77.                         }
  78.                 }
  79.         }
  80.         last_com_dat = temp;
  81.         //UCSR1B |=_BV(RXCIE1);        //打开串口接收中断
  82.         start_usart1;
  83. }
复制代码
主函数中的串口数据处理的部分代码:
  1. //        **********************   串口数据处理    **************************

  2.                 if(com_dat_ok_flag==1)//串口有数据传来
  3.                 {
  4.                         stop_usart1;
  5.                         com_dat_ok_flag = 0;
  6.                         init_ok = 1;
  7.                         cmd = COM_DAT[0];//获取命令值
  8.                         sn = COM_DAT[1];//获取序列号
  9. switch (cmd)
  10.                         {
  11.                                 case 0x01://回复设备信息
  12.                                         mcu_send_sbxx[0]=0;
  13.                                         mcu_send_sbxx[1]=0;//把0xff改成00,方便计算校验和,后面再改回来
  14.                                         mcu_send_sbxx[5] = sn;
  15.                                         check = check_fun((unsigned char *) mcu_send_sbxx,74);//获取校验值
  16.                                         mcu_send_sbxx[0]=0xff;//更改回正确的头数据
  17.                                         mcu_send_sbxx[1]=0xff;
  18.                                         mcu_send_sbxx[74]=check;//填写正确的校验和
  19.                                         COM_TX_Str((unsigned char *) mcu_send_sbxx,75);
  20.                                         init_ok = 1;
  21.                                         break;
  22.                                
  23.                                 case 0x03://WiFi模组读取设备的当前状态
  24.                                         action = COM_DAT[4];
  25.                                         if(action == 0x01)//WiFi模组控制设备
  26.                                         {
  27.                                                 attr_flags1 = COM_DAT[5];
  28.                                                 attr_flags2 = COM_DAT[6];
  29.                                                 attr_flags3 = COM_DAT[7];
  30.                                                 attr_flags4 = COM_DAT[8];
  31.                                                 for(i=0;i<14;i++)
  32.                                                 {
  33.                                                         status1[i] = COM_DAT[i+9];
  34.                                                 }
  35.                                                 //开始控制MCU
  36.                                                 switch(attr_flags1)
  37.                                                 {
  38.        
复制代码



7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
18#
 楼主| 发表于 2016-8-19 12:58:55 | 只看该作者
【十、温湿度传感器】温湿度的获取

本次设计使用的温湿度传感器的型号为:DHT11。
      DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。



  1. /**************************
  2. 作用:读取8位数据
  3. 说明:有两种方法实现
  4. ***************************/
  5. unsigned char DHT11_Read_Byte()
  6. {
  7.         unsigned char i,U8comdata=0,U8temp;
  8.         unsigned char U8FLAG;
  9.         unsigned int i1=0;
  10.         for(i=0;i<8;i++)          
  11.         {
  12.                 U8FLAG=2;       
  13.                 while((!DHT)&&U8FLAG++);
  14.                 if(U8FLAG==1){break;}
  15.                 /**********方法一**********/               
  16.                 i1=1;
  17.                 while(i1)
  18.                 {
  19.                 i1++;
  20.                 if(!DHT)break;
  21.                 }
  22.                 U8temp=0;
  23.                 //26-28us高电平为0 70us高电平为1
  24.                 if(i1>50)U8temp=1;
  25. /***********方法二***********/       
  26.   /*
  27.                 delay_us(30);
  28.                   U8temp=0;
  29.             if(DHT)U8temp=1;
  30.                    U8FLAG=2;
  31.         while((DHT)&&U8FLAG++);          
  32.                    if(U8FLAG==1){break;}//超时则跳出循环
  33. */   
  34.                 U8comdata <<= 1;
  35.                 U8comdata |= U8temp;         
  36.         }//rof
  37.         return U8comdata;
  38. }
  39. /**********************************
  40. 作用:读取温湿度值
  41. 说明:DHT11无小数位,所以只需提取高8位即可
  42. 返回值:高8位湿度,低8位温度
  43. **********************************/       
  44. unsigned int DHT11_Read()
  45. {       
  46.         unsigned char U8FLAG;
  47.         unsigned char U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,
  48.         U8RH_data_L_temp,U8checkdata_temp;
  49.         //主机拉低18ms
  50.         DHTout;
  51.         DHTL;
  52.         delay_ms(18);
  53.         DHTH;
  54.         DHTin;
  55.         DHTH;
  56.         //总线由上拉电阻拉高 主机延时>20us
  57.         delay_us(30);
  58.         //主机设为输入 判断从机响应信号
  59.         //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行          
  60.         if(!DHT)               
  61.         {
  62.                 U8FLAG=2;
  63.                 //判断从机是否发出 80us 的低电平响应信号是否结束         
  64.                 while((!DHT)&&U8FLAG++);
  65.                 if(U8FLAG==1){return 0;}
  66.                 U8FLAG=2;
  67.                 /************************/
  68.                 //注意:假如你还有中断,要考虑中断服务函数运行所需时间以及中断周期
  69.                 //中断服务程序运行大于20us或定时周期较短(小于几十毫秒)最好在此加中断关闭函数,否则数据读取出错
  70.                 /************************/
  71.                 cli();//关总中断注意要放在这  若不初始化定时器则数据一切正常
  72.                 //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
  73.                 while((DHT)&&U8FLAG++);
  74.                 if(U8FLAG==1){return 0;}
  75.                 //数据接收状态       
  76.                 /********************************/
  77.                 //注意:
  78.                 //关中断不可放在此,此处可能使数据为原来的2倍(第一位丢失没读到:此时还在中断服务程序内,全部数据左移1位):间歇性出现
  79.                 /********************************/
  80.                 U8RH_data_H_temp=DHT11_Read_Byte();        //湿度整数
  81.                 U8RH_data_L_temp=DHT11_Read_Byte();        //湿度小数
  82.                 U8T_data_H_temp=DHT11_Read_Byte();        //温度整数
  83.                 U8T_data_L_temp=DHT11_Read_Byte();        //温度小数
  84.                 U8checkdata_temp=DHT11_Read_Byte();        //校验和
  85.                 sei();//开总中断
  86.                 DHTin;
  87.                 DHTH;
  88.                 //数据校验
  89.                 U8FLAG=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
  90.                 if(U8FLAG==U8checkdata_temp)
  91.                 {
  92.                         return ((U8RH_data_H_temp<<8)+U8T_data_H_temp);//U8checkdata=U8checkdata_temp;
  93.                 }
  94.         }
  95.         return 0;//错误数据返回0,主函数可根据此来判断数据可靠性
  96. }
复制代码
















7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
17#
 楼主| 发表于 2016-8-19 12:51:22 | 只看该作者
注册成为机智云开发者,手机加虚拟设备快速开发
【九、ADC模数转换】各种传感器的数据值获取

在本次设计中,有5个传感器值是模拟信号,需要将其转换成为数字值才能进行处理。
在MEGA64中,模数转换器的特点如下:
• 10 位 精度
• 0.5 LSB 的非线性度
• ± 2 LSB 的绝对精度
• 65 - 260 μs 的转换时间
• 最高分辨率时采样率高达15 kSPS
• 8 路复用的单端输入通道
• 7 路差分输入通道
• 2 路可选增益为10x 与200x 的差分输入通道
• 可选的左对齐ADC 读数
• 0 - VCC 的 ADC 输入电压范围
• 可选的2.56V ADC 参考电压
• 连续转换或单次转换模式
• 中断源自动触发ADC 启动
• ADC 转换结束中断
• 基于睡眠模式的噪声抑制器


这里,需要5路ADC转换,分别是:
1、火焰传感器
2、可燃气体传感器
3、土壤湿度传感器
4、雨水传感器
5、亮度传感器

  1. //ADC单通道读取数据函数
  2. //输入:通道编号,如0,1,2-7
  3. //返回值:0-1023
  4. unsigned int ADC_Read(uchar pinx)
  5. {
  6.         uint ADC_Temp=0;
  7.         uchar ADC_L,ADC_H;
  8.         //ADCSRA=0;//关闭ADC
  9.         ADMUX= (0x40 | pinx);     //AD的转换结果右对齐(ADLAR=0),
  10.                                         //参考电压是AVCC,AD的输入通道是pinx,pinx=0 --> PC0(ADC0),
  11.         ADCSRA=0xc1;    //ADC使能(ADEN),单次转换模式(ADFR),2分频
  12.     delay_ms(1);
  13.         ADCSRA=0;//关闭ADC
  14.         ADC_L = ADCL;
  15.         ADC_H = ADCH;
  16.         ADC_Temp =(unsigned int) ((ADC_H << 8) | ADC_L);
  17.         //输出16位的ADC值,精度只有高10位,低6位无效,如果只需要8位精度,则只需要提取高8位即可
  18.         return(ADC_Temp);
  19. }
复制代码


7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
16#
 楼主| 发表于 2016-8-19 12:40:37 | 只看该作者
【八、红外发射】红外学习并发射

通过【七、红外解码】后,我们将解码得到的遥控器数据存放在MCU里的EEPROM中,其存放规则为:
1、一个电视遥控器最多存放29个遥控键值,另外加上遥控器的设备码高位和设备码低位,一个电视遥控器一共占用31个字节空间。这里设计可以存放电视遥控器3组,则存放在EEPROM中的地址分别是:
        电视遥控器1:0-30;
        电视遥控器2:31-61;
        电视遥控器3:62-92;
2、一个空调遥控器最多存放10个遥控键值,另外再加上遥控器的设备码高位和设备码低位,一个空调遥控器一共占用12个字节空间。这里同样也设计了3组空调遥控器,存放在EEPROM中的地址分别是:
        空调遥控器1:93-104;
        空调遥控器2:105-116;
        空调遥控器3:117-128;
下面是这些遥控器存放的地址定义:
  1. #define DS_IR_ADDR_1 0        //电视1红外数据存放首地址
  2. #define DS_IR_ADDR_2 31        //电视2红外数据存放首地址
  3. #define DS_IR_ADDR_3 62        //电视3红外数据存放首地址
  4. #define KT_IR_ADDR_1 93        //空调1红外数据存放首地址
  5. #define KT_IR_ADDR_2 105        //空调2红外数据存放首地址
  6. #define KT_IR_ADDR_4 117        //空调3红外数据存放首地址
复制代码
这里把数据存放在MEGA64的EEPROM中,则需要相应的读写程序:
  1. <font color="#ff0000">/*</font>
复制代码
在红外解码的程序中,把解码得到的数据存放在EEPROM中,其中存放的代码为:
  1. if(ir_first)<font color="#ff0000">//这里判断是否是解码的第一个数据,如果是,则需要存放设备码高地位在前两个地址</font>
  2.                                 {
  3.                                         EEPROM_write(ir_addr, IRCOM[0]);//存放设备码高位
  4.                                         ir_addr++;
  5.                                         EEPROM_write(ir_addr, IRCOM[1]);//存放设备码低位
  6.                                         ir_addr++;
  7.                                         EEPROM_write(ir_addr, IRCOM[2]);//存放数据键值
  8.                                         ir_addr++;
  9.                                         ir_first = 0;
  10.                                 }
  11.                                 else<font color="#ff0000">//这里不是第一个数据了,则不需要存储设备码了,直接存储数据值</font>
  12.                                 {
  13.                                         EEPROM_write(ir_addr, IRCOM[2]);//存放数据键值
  14.                                         ir_addr++;
  15.                                 }
复制代码
下面,我们来看看红外发射的原理
红外接收是接收38KHz的载波,如果接收到38KHz的信号,则输出低电平;如果没有接收到38KHz的载波信号,则输出高电平。
根据上述原理,我们要发射的信号则需要38KHz的载波,那么数据值中,需要输出高电平的我们就停止发射38KHz载波,数据值中是低电平的,我们就发射38KHz的载波,这样就可以把数据发射出去了。
38KHz载波的发生:
38KHz载波的发生,这里用到T0定时器:
  1. TCCR0 |= ( _BV(COM00) | _BV(WGM01) | _BV(CS01) );//CTC模式,比较匹配时取反,8分频,IR发送38KHz
复制代码
  1. //T0比较匹配中断,13.02066us中断一次,即13.02066us改变一次输出的电平,38KHz的方波
  2. ISR(TIMER0_COMP_vect)
  3. {
  4.         start_count++;//这里计算时间长度
  5. }
复制代码
  1. /************  <font color="#ff0000">红外发射函数 </font> **************/
  2. void IR_Send_Data(uchar *IR_Data)<font color="#ff0000">//4字节数组,分别是高地址,低地址,数据,数据反码</font>
  3. {
  4.         uchar i,j,dat;
  5.         uint end_count;
  6. TCNT0 = 0;
  7.         OCR0 = 17;
  8.         TIMSK |= _BV(OCIE0);//打开T0比较匹配中断
  9.         TCCR0 |= _BV(COM00);//引脚关联,发射载波
  10. <font color="#ff0000">        //发送9ms的起始码</font>
  11. start_count = 0;
  12.         while(start_count < MS_9);//发送9ms的载波信号,即9ms的低电平
  13. //发送4.5ms的结果码,解码后的高电平
  14.         TCCR0 &=~_BV(COM00);//引脚不关联,停止发射载波
  15.         ES_IR = 0;
  16.         start_count = 0;
  17.         while(start_count < MS_4_5);//发送4.5ms的解码后的高电平
  18.         for(j=0;j<4;j++)
  19.         {
  20.                 dat = IR_Data[j];
  21.                 for(i=0;i<8;i++)
  22.                 {
  23.                         //先发送0.56ms的载波信号(即解码后的低电平)
  24.                         TCCR0 |= _BV(COM00);//引脚关联
  25.                         start_count = 0;
  26.                         while(start_count < DAT_0);
  27.                         //停止发送载波信号
  28.                         if((dat & 0x01) == 1)        //判断是否为1
  29.                         {
  30.                                 end_count = DAT_1;
  31.                         }
  32.                         else
  33.                         {
  34.                                 end_count = DAT_0;
  35.                         }
  36. TCCR0 &=~_BV(COM00);//引脚不关联,即停止载波发射
  37.                         ES_IR = 0;
  38.                         start_count = 0;
  39.                         while(start_count < end_count);
  40.                         dat = dat >> 1;
  41.                 }
  42.         }
  43.         //发送1位结束码
  44.         TCCR0 |=_BV(COM00);//引脚关联,发射载波
  45.         start_count = 0;
  46.         while(start_count < DAT_0);
  47.         //结束编码
  48.         TCCR0 &=~_BV(COM00);//引脚不关联,停止载波发射
  49.         ES_IR = 0;
  50.         TIMSK &= ~_BV(OCIE0);//关闭TO比较匹配中断
  51.         TCCR0 &=~_BV(COM00);//引脚不关联,停止载波发射
  52.         ES_IR = 0;        //关闭红外发射器
  53. }
复制代码
  1. <font color="#ff0000">/*</font>
复制代码
下面是在处理串口数据时的部分关于遥控器的处理代码:
  1. case 0x08://设置TVremote1  ok
  2.                                                                 temp1 = status1[4];
  3.                                                                 temp2 = ((temp1 & 0b11111000) >> 3);
  4.                                                                 status[4] = temp1;
  5.                                                                 COM_TX(0xaa);COM_TX(0xaa);COM_TX(temp2);COM_TX(0xaa);COM_TX(0xaa);
  6.                                                                 if(temp2 != 0)
  7.                                                                 {
  8.                                                                         get_ircode_send(DS_IR_ADDR_1 , temp2);
  9.                                                                         status[4] = (temp1 & 0b00000111);
  10.                                                                 }
  11.                                                                 break;
  12.                                                         case 0x10://设置TVremote2  ok
  13.                                                                 temp1 = status1[3];
  14.                                                                 temp2 = (temp1 & 0b00011111);
  15.                                                                 status[3] = temp1;
  16.                                                                 COM_TX(0xaa);COM_TX(0xaa);COM_TX(temp2);COM_TX(0xaa);COM_TX(0xaa);
  17.                                                                 if(temp2 != 0)
  18.                                                                 {
  19.                                                                         get_ircode_send(DS_IR_ADDR_2 , temp2);
  20.                                                                         status[3] = (temp1 & 0b11100000);
  21.                                                                 }
  22.                                                                 break;
复制代码
  1. case 0x40://设置TVremote3 OK
  2.                                                                 temp1 = status1[2];
  3.                                                                 temp2 = ((temp1 & 0b00111110) >> 1);
  4.                                                                 status[2] = temp1;
  5.                                                                 COM_TX(0xaa);COM_TX(0xaa);COM_TX(temp2);COM_TX(0xaa);COM_TX(0xaa);
  6.                                                                 if(temp2 != 0)
  7.                                                                 {
  8.                                                                         get_ircode_send(DS_IR_ADDR_3 , temp2);
  9.                                                                         status[2] = (temp1 & 0b11000001);
  10.                                                                 }
  11.                                                                 break;
  12.                                                         case 0x80://设置KTremote1 OK
  13.                                                                 temp1 = ((status1[2] & 0b11000000) >> 6);
  14.                                                                 status[2] = status1[2];
  15.                                                                 status[1] = status1[1];
  16.                                                                 temp2 = (((status1[1] & 0b11111100) << 2) | temp1);
  17.                                                                 COM_TX(0xaa);COM_TX(0xaa);COM_TX(temp2);COM_TX(0xaa);COM_TX(0xaa);
  18.                                                                 if(temp2 != 0)
  19.                                                                 {
  20.                                                                         get_ircode_send(KT_IR_ADDR_1 , temp2);
  21.                                                                         status[2] = (status1[2] & 0b00111111);
  22.                                                                         status[1] = (status1[1] & 0b11111100);
  23.                                                                 }
  24.                                                                 break;
复制代码
详细请看所有代码。


7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
15#
 楼主| 发表于 2016-8-17 21:24:34 | 只看该作者
本帖最后由 孤独的蛇 于 2016-8-17 21:26 编辑

【七、红外解码】
1838一体化红外接收头是我们最常用的红外接收元器件。它被广泛的应用于电视机、空调、电冰箱以及电视机顶盒等需要红外遥控的电器上。根据名称后面的“38”可知,这个是38KHz载波的器件。
我国基本上是用的遥控器都是遵循NEC的编码方式。所以,这里以NEC红外遥控的编码方式为例。

NEC红外遥控编码方式:它的指令格式依次为,引导码+设备码高位+设备码低位+数据码+数据反码。引导码用于通知红外遥控信号的来临,由9毫秒的低电平加4.5毫秒的高电平组成;设备码高位、设备码低位、数据码、数据反码都是1个字节。设备码高位与设备码低位组成一个16位的设备码,一般用来识别红外遥控器,就是说,假如你的空调的遥控器设备码是88,你家的电视遥控设备码是55,你用电视的遥控对空调就不起作用,如果你家的电视遥控和空调遥控的设备码相同,那你拿上电视的遥控对着空调按一番,说不定就出什么乱子了。数据码用于识别用户的功能,如加减声音、换台等按键发出的数据码都是不一样的。数据反码与数据码是反码的关系,用于校验数据码接收正确与否。

口述一下红外遥控按下以后,接收头OUT引脚的变化:首先是9ms的低电平,然后是4.5ms的高电平,然后将会出现设备码高位,设备码低位,数据码,数据反码,这4个码的逻辑1是560us低电平+1680us高电平,逻辑0是560us低电平+560us高电平。



上图是从网上获取的一张图。

此外,用户如果一直按着一个键不放,将会发送重发码。重发码是跟在按键码后面的,它由9ms低电平+2.5ms高电平+560us低电平+97ms高电平组成,由重发码的规律,我们可以看出,当单片机观察到9ms低电平时,后面如果是4.5ms高电平,就是第一次按的按键码,如果9ms后面跟的是2.5ms高电平,就是重发码。




上图是单片机MEGA64接1838的电路图,1838输出端接入的是PD4(IC1),即MEGA64的输入捕捉引脚1,通过单片机的输入捕捉功能,就可以把红外数据解码出来。其原理是:
当收到引导码信号时,开始计算时间长度,是否符合引导码规律,然后把捕捉的电平设置为下降沿触发,计算4.5ms宽度,再次反转触发方式,变为上升沿触发,计算宽度,再翻转电平触发方式,一次类推,直到接收完32位数据。通过解码得到的数据,即可知道发射的是什么了。
MEGA64红外解码程序如下:
定时器1输入捕捉初始化:

  1. /*
  2. 红外线解码外部捕捉初始化,使用TC1的外部捕捉
  3. PD4为红外接收器数据引脚,设置PD4为输入方式
  4. */
  5. void ICP1_Init()
  6. {
  7.         DDRD&=~_BV(P4);
  8.         PORTD|=_BV(P4);//设置为上拉模式,提高解码可靠性
  9.         
  10.         TCCR1A |= _BV(WGM10);
  11.         TCCR1B |= (_BV(WGM12) | _BV(CS12) | _BV(ICES1));//8为PWM 256分频
  12.         TIMSK |= _BV(TICIE1);//输入捕捉中断
  13. //        COM_TX(TIMSK);
  14.         E_UP;
  15. }
复制代码
定时器1溢出中断,一个作用是用来判断是否红外接收超时,另外一个作用就是180秒的心跳信号
  1. //定时器1溢出中断函数
  2. ISR(TIMER1_OVF_vect)   
  3. {
  4.         time_count++;
  5.         time_xintiao++;

  6.         if((time_count > 1) && (start_ir == 1))//定时器1溢出中断时间,根据8ms的解码超时来算,2 * 23.14814 * 255 ==> 11805us 溢出一次需要23.14814 * 255us = 5902.777us
  7.         {
  8.                 IRReceiveCurrentBit = 0;//重置IR接收位为第0位,为下次接收做准备
  9.                 E_UP; //设置输入捕获 上升沿有效
  10.                 ICP_Parity = 0;     
  11.                 Stop_T1;
  12.                 time_count = 0;
  13.                 //start_ir = 0;//关闭IR超时计数
  14.                 CLR_IR_LED;
  15. //                COM_TX('-');
  16.         }
  17.         if(time_xintiao > 30494)//如果心跳计时时间大于180秒,则重启wifi模块
  18.         {
  19.                 time_xintiao = 0;
  20.                 //重启wifi
  21.                 PORTC_5 = 0;
  22.                 delay_ms(30);
  23.                 PORTC_5 = 1;
  24.         }
  25. }
复制代码
解码程序:
  1. //定时器计数器1输入捕捉中断函数
  2. ISR(TIMER1_CAPT_vect)
  3. {
  4.   if(ir_in)
  5.   {
  6.             if(ICP_Parity==0)//捕获中断奇偶次计数 1时为偶次 并在此时判断脉宽
  7.             {
  8.               ICP_Parity++;
  9.               E_DOWN; //设置输入捕获 下降沿有效
  10.               Start_T1;
  11.             }
  12.             else
  13.             {
  14.                   Stop_T1;
  15.               ICP_Parity=0;
  16.               E_UP;//设置输入捕获 上升沿有效
  17.                   Pulse_length = ICR1L;
  18.                   Pulse_length =((ICR1H<<8) | Pulse_length);
  19.               //Pulse_length=ICR1;
  20.               if(IRReceiveCurrentBit==0)
  21.               {
  22.                 if(Pulse_length>=152&&Pulse_length<239)// 如果是引导码 (4.5ms) 进入下一个bitde读取
  23.                         //根据定时器的分频来设置,如16MHz的,8分频,0.5us中断一次,则4500us / 0.5us = 9000 ,我们这里取3.5ms - 5.5ms都默认是对的
  24.                 {
  25.                                 IRReceiveCurrentBit++;
  26.                         }
  27.               }
  28.               else if(IRReceiveCurrentBit<33) //接收32位数据
  29.               {
  30.                         IRcode>>=1;
  31.                 if(Pulse_length<83 && Pulse_length>61) //判断shi否为 1 ( 1.685 ms) 1.4-1.9ms都对
  32.                 IRcode|=0x80000000;
  33.                 IRReceiveCurrentBit++;
  34.                 if(IRReceiveCurrentBit==33)
  35.                 {
  36.                           IRCOM[0] = (unsigned char) IRcode;
  37.                           IRCOM[1] = (unsigned char) (IRcode >> 8);
  38.                           IRCOM[2] = (unsigned char) (IRcode >> 16);
  39.                           IRCOM[3] = (unsigned char) (IRcode >> 24);

  40.                   if(IRCOM[2]==(unsigned char)(~IRCOM[3]))
  41.                           {
  42.                     SET_IR_LED;    //开启IR信号指示灯
  43.                     IRReceiveEffective=1; //数据有效
  44.                                 if(ir_first)
  45.                                 {
  46.                                         EEPROM_write(ir_addr, IRCOM[0]);//存放设备码高位
  47.                                         ir_addr++;
  48.                                         EEPROM_write(ir_addr, IRCOM[1]);//存放设备码低位
  49.                                         ir_addr++;
  50.                                         EEPROM_write(ir_addr, IRCOM[2]);//存放数据键值
  51.                                         ir_addr++;
  52.                                         ir_first = 0;
  53.                                 }
  54.                                 else
  55.                                 {
  56.                                         EEPROM_write(ir_addr, IRCOM[2]);//存放数据键值
  57.                                         ir_addr++;
  58.                                 }
  59.                   }
  60.                   delay_ms(5); //因为32位数据后面还有一个信号上跳变,所以要适当延时,延时0.65ms以上即可
  61.                 }
  62.               }
  63.             }
  64.         }//if(ir_in)
  65. }
复制代码
以上程序会将接收到的红外数据存放在MRGA64的EEPROM中保存,为下次控制使用。

至此,红外解码结束。





7

主题

44

帖子

116

积分

注册会员

Rank: 2

积分
116
14#
 楼主| 发表于 2016-8-17 20:56:52 | 只看该作者

续【六、PWM】


续:

自动调光原理:
当光敏电阻输入的电信号越大,则说明环境越暗,则需要把灯调的更亮,即把PWM值调的更高。
  1. #define auto_PWM_MIN 600 //自动调光限度最小值,当低于这个值的时候,直接熄灭,PWM为0
  2. #define auto_PWM_MAX 1000 //自动调光限度最大值,当超过这个值的时候,直接点亮,PWM为255
复制代码
映射函数:
  1. long map(long x, long in_min, long in_max, long out_min, long out_max)
  2. {
  3. return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  4. }
复制代码
PWM信号输出函数:
  1. /* PWM信号输出 void PWM_OUT(unsigned char num,unsigned char val)
  2. 输入参数1:unsigned char num 哪一路PWM信号。1:OC1A第一路PWM 2:OC1B第二路PWM 3:OC3A(RGB中的R) 4:OC3B(RGB中的G) 5:OC3C(RGB中的B)
  3. 输入参数2:unsigned char val PWM信号值
  4. */
  5. void PWM_OUT(unsigned char num,unsigned char val)
  6. {
  7. switch(num)
  8. {
  9. case 1://OC1A PB5 PWM1
  10. if(val == 0)//如果PWM值为0,即关闭,则直接把相应的管脚设为0
  11. {
  12. TCCR1A &=~_BV(COM1A1);//关闭OC1A引脚关联
  13. //TIMSK &= ~_BV(OCIE1A);//关闭输出比较A中断
  14. PORTB &=~_BV(P5);//输出低电平
  15. }
  16. else
  17. {
  18. OCR1A = val;
  19. TCCR1A |= _BV(COM1A1);//打开OC1A引脚关联
  20. //TIMSK &= ~_BV(OCIE1A);//关闭输出比较A中断
  21. }
  22. break;
  23. case 2://OC1B PB6 PWM2
  24. if(val == 0)//如果PWM值为0,即关闭,则直接把相应的管脚设为0
  25. {
  26. TCCR1A &=~_BV(COM1B1);//关闭OC1B引脚关联
  27. //TIMSK &= ~_BV(OCIE1B);//关闭输出比较B中断
  28. PORTB &=~_BV(P6);//输出低电平
  29. }
  30. else
  31. {
  32. OCR1B = val;
  33. TCCR1A |= _BV(COM1B1);//打开OC1B引脚关联
  34. //TIMSK &= ~_BV(OCIE1B);//关闭输出比较B中断
  35. }
  36. break;
  37. case 3://OC3A PE3 R
  38. if(val == 0)//如果PWM值为0,即关闭,则直接把相应的管脚设为0
  39. {
  40. TCCR3A &=~_BV(COM3A1);//关闭OC3A引脚关联
  41. //TIMSK &= ~_BV(OCIE3A);//关闭输出比较A中断
  42. PORTE &=~_BV(P3);//输出低电平
  43. }
  44. else
  45. {
  46. OCR3A = val;
  47. TCCR3A |= _BV(COM3A1);//打开OC3A引脚关联
  48. //TIMSK &= ~_BV(OCIE3A);//关闭输出比较A中断
  49. }
  50. break;
  51. case 4://OC3B PE4 G
  52. if(val == 0)//如果PWM值为0,即关闭,则直接把相应的管脚设为0
  53. {
  54. TCCR3A &=~_BV(COM3B1);//关闭OC3B引脚关联
  55. //TIMSK &= ~_BV(OCIE3B);//关闭输出比较A中断
  56. PORTE &=~_BV(P4);//输出低电平
  57. }
  58. else
  59. {
  60. OCR3B = val;
  61. TCCR3A |= _BV(COM3B1);//打开OC3B引脚关联
  62. //TIMSK &= ~_BV(OCIE3B);//关闭输出比较A中断
  63. }
  64. break;
  65. case 5://OC3C PE5 B
  66. if(val == 0)//如果PWM值为0,即关闭,则直接把相应的管脚设为0
  67. {
  68. TCCR3A &=~_BV(COM3C1);//关闭OC3C引脚关联
  69. //TIMSK &= ~_BV(OCIE3C);//关闭输出比较A中断
  70. PORTE &=~_BV(P5);//输出低电平
  71. }
  72. else
  73. {
  74. OCR3C = val;
  75. TCCR3A |= _BV(COM3C1);//打开OC3C引脚关联
  76. //TIMSK &= ~_BV(OCIE3C);//关闭输出比较A中断
  77. }
  78. break;
  79. default:break;
  80. }
  81. }
复制代码
自动调光函数:
  1. //自动调光,输入为光敏电阻的值,这里最好是取几次的平均值
  2. void auto_PWM(unsigned int val)
  3. {
  4. unsigned int x;
  5. x = (unsigned int)map(val,auto_PWM_MIN,auto_PWM_MAX,0,255);
  6. PWM_OUT(1,x);
  7. }
复制代码
取5次ADC的输入值求平均值:
  1. //获取ADC5次结果,去掉最大最小值后的平均值,输入为ADC序号,0-7
  2. unsigned int getADC_average_value(unsigned char num)
  3. {
  4. unsigned int max;
  5. unsigned int min;
  6. unsigned int val[5];
  7. unsigned char x,y,j;
  8. unsigned long sum_val;
  9. unsigned int average_value;//取5次ADC结果,去掉最大最小的平均值
  10. for(y=0;y<5;y++)
  11. {
  12. val[y] = ADC_Read(num);
  13. }
  14. max = val[0];
  15. min = val[0];//把ary[0]都赋值给max和min
  16. x = 0;
  17. y = 0;
  18. for (j=1; j<5; j++) //求最大、最小
  19. {
  20. if (max<val[j])
  21. {
  22. max = val[j];//有比max大的就赋值给max
  23. y = j;
  24. }
  25. if (min>val[j])
  26. {
  27. min = val[j];//有比min小的就赋值给min
  28. x = j;
  29. }
  30. }
  31. //已经寻找出最大最小值了
  32. sum_val = 0;
  33. for(j=0;j<5;j++)
  34. {
  35. if((j != x) && (j != y) )//不是最大最小值
  36. {
  37. sum_val = sum_val + val[j];
  38. }
  39. }
  40. average_value = (unsigned int)sum_val / 3;//取平均值
  41. return average_value;
  42. }
复制代码



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入Q群 返回顶部

版权与免责声明 © 2006-2024 Gizwits IoT Technology Co., Ltd. ( 粤ICP备11090211号 )

快速回复 返回顶部 返回列表