收藏官网首页

【MEGA64+ESP8266】之智能家居

查看数: 43564 | 评论数: 31 | 收藏 6
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2016-7-25 00:58

正文摘要:

本帖最后由 Genius 于 2016-8-25 14:51 编辑 就是辣么棒!一个app就能控制所有家电、家居。 原创**,转载请注明来自:http://club.gizwits.com/thread-2939-1-1.html 作者:孤独的蛇 【开源硬件】机智云智能硬件 ...

回复

孤独的蛇 发表于 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,只能等到以后有时间的时候再进行研究了,弄好后我也会在这里附上的
孤独的蛇 发表于 2016-8-17 16:38:02
【三、智能插座】的设计
智能插座和智能开关的原理是一样的,这里就不再阐述。
孤独的蛇 发表于 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.                 }
复制代码





sunwaywu 发表于 2019-3-13 09:45:15
谢谢无私分享
abc123456 发表于 2017-9-5 15:40:38
可以学习一下么
abc123456 发表于 2017-9-5 15:40:01
可以学习一下么
老顽童 发表于 2017-6-6 19:05:40
学习了,可是楼主下次能不能把所有的文件放在一个包里?这样下载要很多金币啊,屌丝穷
dudu林 发表于 2017-4-17 14:57:56
现在用mega32 的和 8266通讯当中,刚好可以借鉴一下,谢谢楼主
maomaodemao 发表于 2016-11-18 15:42:27
楼主好,360云盘的内容都走丢了
Michael_hl 发表于 2016-10-15 17:01:01
你好,我正在使用wtv020模块做一个MP3播放模块,我想问一下,这些控制模式,如MP3模式、二线串口模式等五种模式,在控制的时候是如何选定我们当前是在使用MP3模式还是二线串口模式?我现在一直不能让这个模块发声~~好急好郁闷
true 发表于 2016-9-9 20:20:31
楼主辛苦了,支持这么多的外设。。。
BADAO 发表于 2016-9-6 11:53:49
跟着楼主学习学习
孤独的蛇 发表于 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.                 }
复制代码



孤独的蛇 发表于 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.        
复制代码



孤独的蛇 发表于 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. }
复制代码


孤独的蛇 发表于 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;
复制代码
详细请看所有代码。


孤独的蛇 发表于 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号 )

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