找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 26964|回复: 37
打印 上一主题 下一主题
收起左侧

单片机红外通信(红外编码发射和红外接收解码代码)

  [复制链接]
跳转到指定楼层
楼主
ID:427492 发表于 2019-7-8 20:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
关于红外通信,网上有很多关于解码的单片机代码和视频,发射编码部分并不好找。写发射部分代码花费了不少时间,拿出来与大家分享一下。下面是我在网上找到的资料:

一、NEC 协议特征:
1.  8 位地址和 8 位命令长度
2. 每次传输两遍地址(用户码)和命令(按键值)
3. 通过脉冲串之间的时间间隔来实现信号的调制(PPM
4.  38Khz 载波
5. 每位的周期为 1.12ms(低电平)或者 2.25ms(高电平)



二、NEC  协议的典型脉冲链:

用户码和数据码中的‘0’‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲 位置调制方式(PPM)。
其中位 0 首先为 0.56ms 的高电平,然后是 0.565ms 的低电平;位 1 首先是 0.56ms的高电平,然后是 1.69ms 的低电平。


五、编程注意事项
1.红外接收头引脚信号是相反的电平 以上电平是从发射头角度来看,红外接收头引脚输出的是相反的电平。 如图,即没有数据传输时,P3.2 引脚保持为高电平,当接收到数据时,首先是引导 码,9ms 的低电平和 4.5ms 的高电平,然后是 32 位数据和 1 位停止位。一般来说, P3.2     与单片机的某中断引脚相连,当接收数据时,低电平会触发中断。

2.数据从 LSB(低位)开始发送,所以选择右移方式接收数据。 四个字节的数据都是先发送 D0,最后发送 D7。所以接收到 1 位数据后,给变量的 最高位赋值,右移。或者先右移,再给变量的最高位赋值。

3.可以用一个数组保存 32 个数据的持续时间,用于后面判断高低电平。 用定时器对两个数据(中断)之间的时间计时,并保存这个持续时间用于以后判断 是位 1 还是位 0

4.可以用 2 字节,4 字节变量存储 32 个数据,以节省代码空间

可以用两个 16 位的 int 型变量存储数据,第一个 int 变量存储用户码,第二个存储数 据码和数据反码。也可以用一个 32 long 型的变量存储所有数据。

5.判断停止位 接收到停止位后可以屏蔽红外引脚的中断,防止后面数据的干扰,解码成功后在开 启中断。

发射编码部分核心代码:
  1. #include <stc8.h>
  2. typedef unsigned char uchar;
  3. typedef unsigned int  uint;
  4. sbit irsend = P7^5;              // 红外发送
  5. sbit K = P0^7;                   // 按键总开关
  6. sbit key1 = P0^0;                // 按键1
  7. sbit key2 = P0^1;                // 按键2
  8. uint hwcount, count;             // 要进中断的总次数、用于记录进入中断次数
  9. uchar irsys[2]= {0x00,0xff};     // 16位用户码
  10. bit hsflag = 0;                  // 发送38KHz载波标志位
  11. uchar ircode;                          // 发送的红外数据

  12. void Timer1Init(void)                     // 13微秒@12.000MHz
  13. {
  14.         AUXR &= 0xBF;                         // 定时器时钟12T模式
  15.         TMOD &= 0x0F;                         // 设置定时器模式
  16.         TMOD |= 0x20;                         // 设置定时器模式
  17.         TL1 = 0xF3;                             // 设置定时初值
  18.         TH1 = 0xF3;                             // 设置定时重载值
  19.         TF1 = 0;                             // 清除TF1标志
  20.         TR1 = 0;                             // 定时器1关闭计时
  21.         ET1 = 1;                     // 开定时器1中断
  22.         EA  = 1;                     // 开总中断
  23. }

  24. void Timer1_isr() interrupt 3
  25. {
  26.         count++;
  27.         if(hsflag)                   // 有发射标志,则发射38khz
  28.         {
  29.                 irsend = ~irsend;
  30.         }
  31.         else                         // 否则不发射,即相当于发射编码中的低电平
  32.                 irsend = 1;
  33.                
  34. }

  35. void ir_SendByte()               // 红外发送一字节数据
  36. {
  37.         uchar i;
  38.         for(i=0;i<8;i++)             // 一字节八位,循环八次
  39.         {
  40.                 hwcount = 43;            // 0.56ms高电平,需要进43次定时器1中断(560/13=43)
  41.                 hsflag = 1;              // 发射38KHz载波标志
  42.                 count = 0;               // count置0,从这时起记录进入定时器1中断的次数
  43.                 TR1 = 1;                 // 定时器1开启计时
  44.                 while(count < hwcount);  // 在此等待,直到进入中断次数达到43次
  45.                 TR1 = 0;                 // 定时器1关闭计时
  46.                 if(ircode&0x01)          // 数据是从最低位开始发送的,最低位是1则要进130次中断
  47.                 {
  48.                         hwcount = 130;       // 1.69ms低电平,进中断总次数130(1690/13=130)
  49.                 }
  50.                 else                     // 最低位是0,则要进43次定时器1中断
  51.                 {
  52.                         hwcount = 43;        // 0.565ms低电平,进中断总次数43(565/13=43)
  53.                 }
  54.                 hsflag = 0;              // 低电平,不需要38kHz载波
  55.                 count = 0;
  56.                 TR1 = 1;
  57.                 while(count < hwcount);
  58.                 TR1 = 0;
  59.                 ircode = ircode >> 1;    // 将数据右移一位,即从低位到高位发送
  60.         }
  61. }
  62. void ir_Send(uchar date)
  63. {
  64.         hwcount = 692;               // (引导码中的)9ms高电平,9000/13=692
  65.         hsflag = 1;                  // 高电平需要38kHz载波
  66.         count = 0;               
  67.         TR1 = 1;
  68.         while(count < hwcount);
  69.         TR1 = 0;
  70.         hwcount = 346;               // (引导码中)4.5ms低电平,4500/13=346
  71.         hsflag = 0;                  // 低电平不需要38kHz载波
  72.         count = 0;
  73.         TR1 = 1;
  74.         while(count < hwcount);
  75.         TR1 = 0;
  76.         ircode = irsys[0];           // 发送用户码的前8位
  77.         ir_SendByte();
  78.         ircode = irsys[1];           // 发送用户码的后8位
  79.         ir_SendByte();
  80.         ircode = date;               // 发送键值
  81.         ir_SendByte();
  82.         ircode = ~date;              // 发送键值反码
  83.         ir_SendByte();
  84.         hwcount = 43;                // 0.56ms高电平,560/13=43
  85.         hsflag = 1;                  // 高电平需要38kHz载波
  86.         count = 0;
  87.         TR1 = 1;                     // 定时器1开启计时
  88.         while(count < hwcount);
  89.         TR1 = 0;                     // 定时器1关闭计时
  90.         hwcount = 43;                // (NEC协议中的停止码)0.56ms低电平
  91.         hsflag = 0;
  92.         count = 0;
  93.         TR1 = 1;
  94.         while(count < hwcount);
  95.         TR1 = 0;
  96.         irsend = 1;                  // 关闭红外发射
  97. }
  98. void main()
  99. {
  100.         K = 0;                       // 按键总开关拉低
  101.         Timer1Init();                // 定时器1初始化
  102.         while(1)
  103.         {
  104.                 if(key1 == 0)            // 按键1         
  105.                 {               
  106.                         ir_Send(0x8a);       // 发送键值8aH
  107.                 }
  108.                 if(key2 == 0)            // 按键2
  109.                 {
  110.                         ir_Send(0xa6);       // 发送键值a6H
  111.                 }
  112.         }
  113. }
复制代码


  1. #include "key.h"
  2. #define GPIO_KEY P0
  3. bit flag = 0;
  4. /**********************************************
  5. * 函数名:Check_key
  6. * 描述  :矩阵按键扫描(缺陷:不能通过按一次按键,给变量只加一)
  7. * 参数  :无
  8. * 返回值:键值
  9. * 调用  :外部调用
  10. **********************************************/
  11. //unsigned char Check_key(void)
  12. //{
  13. //        unsigned char row,col,temp1,temp2,keyvalue;
  14. //        temp1 = 0x01;
  15. //        for(row=0;row<4;row++)                // 行扫
  16. //        {
  17. //                P0 = 0xF0;                        // 先将P0.4~P0.7置高
  18. //                P0 = ~temp1;                      // 使P0.1~P0.3中有一位为0
  19. //                temp1 *= 2;                       // temp1左移一位
  20. //                if((P0 & 0xF0) < 0xF0)            // 当按键按下时,(P0 & 0xF0) 高四位不在是F,可能为7或B或D或E。
  21. //                {                                    // 这时可以确定按下的是(row+1)行
  22. //                        temp2 = 0x80;
  23. //                        for(col=0;col<4;col++)        // 列扫
  24. //                        {
  25. //                                if((P0 & temp2)==0x00)    // 当(P0 & temp2)等于0x00时,可以确定按下的位置是(col+1)列
  26. //                                {
  27. //                                        keyvalue = row*4+col; // 得到所按下按键的键值
  28. //                                        return keyvalue;      // 把得到的键值作为返回值
  29. //                                }
  30. //                                temp2 /= 2;               // temp2右移一位
  31. //                        }
  32. //                }
  33. //        }
  34. //        return 16;  // 因为定义数码管段选表中,16对应的是全灭,故无按键按下时返回16
  35. //}


  36. /*************************************************
  37. * 函数名:delay_ms
  38. * 描述  :延时函数
  39. * 参数  :xms  , xms是几延时几毫秒
  40. * 返回值:无
  41. * 调用  :内部调用
  42. *************************************************/
  43. void delay_ms(unsigned int xms)
  44. {
  45.         unsigned char i, j;
  46.         unsigned int x;
  47.         for(x=xms;x>0;x--)
  48.         {
  49.                 i = 16;
  50.                 j = 147;
  51.                 do
  52.                 {
  53.                         while (--j);
  54.                 } while (--i);
  55.         }
  56. }
  57. /*************************************************
  58. * 函数名:key_scan
  59. * 描述  :把按下的矩阵按键的键值返回
  60. * 参数  :无
  61. * 返回值:按下的键值
  62. * 调用  :外部调用
  63. *************************************************/
  64. unsigned char key_scan()
  65. {
  66.         unsigned char keyvalue1,keyvalue2,a=0;
  67.         if(flag==0)
  68.         {
  69.                 keyvalue2=16;
  70.                 flag=1;
  71.         }
  72.         GPIO_KEY = 0xf0;              // 高四位为1,低四位为0
  73.         if(GPIO_KEY != 0xf0)
  74.         {
  75.                 delay_ms(10);             // 延时消抖
  76.                 if(GPIO_KEY != 0xf0)
  77.                 {
  78.                         GPIO_KEY=0xf0;
  79.                         switch(GPIO_KEY)
  80.                         {
  81.                         case 0xe0: keyvalue1 = 3;break;     // 确定矩阵按键被按下的位置是第几列
  82.                         case 0xd0: keyvalue1 = 2;break;     // 0、1、2、3
  83.                         case 0xb0: keyvalue1 = 1;break;
  84.                         case 0x70: keyvalue1 = 0;break;
  85.                         }
  86.                         GPIO_KEY=0x0f;        
  87.                         // 确定矩阵按键被按下位置的键值:列(或0或1或2或3) + 行(或0或4或8或12)
  88.                         if((GPIO_KEY != 0x0d)||(GPIO_KEY != 0x0b)||(GPIO_KEY != 0x07))
  89.                                 keyvalue2 = keyvalue1;
  90.                         if(GPIO_KEY == 0x0d)
  91.                                 keyvalue2 = keyvalue1+4;
  92.                         if(GPIO_KEY == 0x0b)
  93.                                 keyvalue2 = keyvalue1+8;
  94.                         if(GPIO_KEY == 0x07)
  95.                                 keyvalue2 = keyvalue1+12;
  96.                         while((a<50)&&(GPIO_KEY!=0x0f))
  97.                         {
  98.                                 delay_ms(10);
  99.                                 a++;
  100.                         }
  101.                 }                        
  102.         }
  103.         if(GPIO_KEY==0xF0)
  104.                 keyvalue2 = 16;
  105.         return keyvalue2;
  106. }
复制代码

单片机红外解码源程序如下:
  1. #include <stc8.h>
  2. #include "hc595.h"
  3. typedef unsigned char uchar;
  4. typedef unsigned int  uint;
  5. sbit ir = P3^2;               // 红外接收
  6. uchar irtime;                 // 记录定时器0中断次数
  7. uchar irdata[33];             // 存放接收到的33位红外数据的每位进入中断的次数
  8. uchar bitnum;                 // 数组下标,用于记录是第几位红外数据
  9. uchar startflag;              // 开始接收标志
  10. uchar irok;                   // 33位数据收集完成标志
  11. uchar ircode[4];              // 用于存放16位用户码+8位键值+8位键值反码
  12. uchar irprosok;               // 四个码值转化完成标志
  13. uchar disnum[8];              // 把四个码值分割成8位,用于数码管显示

  14. void Int0Init(void)           // 外部中断0初始化
  15. {
  16.         IT0 = 1;                  // 下降沿触发
  17.         EX0 = 1;                  // 开启外部中断0
  18.         EA  = 1;                  // 开总中断
  19.         ir  = 1;                  // 红外接收置1
  20. }

  21. void Timer0Init(void)         // 定时器0初始化,模式:12T,晶振:12MHz
  22. {
  23.         TMOD = 0x02;              // 定时器0模式2,8位自动重装载
  24.         TH0  = 0x00;              // 256*(1/12)*12 = 0.256ms
  25.         TL0  = 0x00;
  26.         ET0  = 1;                 // 开定时器0中断
  27.         EA   = 1;                 // 开总中断
  28.         TR0  = 1;                 // 定时器0开始计时
  29. }

  30. void irpros(void)             // 码值转换
  31. {
  32.         uchar num, k, i, j;
  33.         k = 1;
  34.         for(j=0;j<4;j++)          // 四个码值,循环四次
  35.         {
  36.                 for(i=0;i<8;i++)      // 每个码值八位,循环八次
  37.                 {
  38.                         num = num >> 1;   // 从最低位开始接收
  39.                         if(irdata[k]>6)   // 判断这位数据是0还是1:(0:1.12/0.256=4.4)(1:2.25/0.256=8.8)
  40.                         {
  41.                                 num = num | 0x80;
  42.                         }
  43.                         k++;
  44.                 }
  45.                 ircode[j] = num;      // 存放码值
  46.         }
  47.         irprosok = 1;             // 码值转换完成标志
  48. }

  49. void irwork(void)             // 码值分割,用于数码管显示
  50. {
  51.         disnum[0] = ircode[0]/16;
  52.         disnum[1] = ircode[0]%16;
  53.         disnum[2] = ircode[1]/16;
  54.         disnum[3] = ircode[1]%16;
  55.         disnum[4] = ircode[2]/16;
  56.         disnum[5] = ircode[2]%16;
  57.         disnum[6] = ircode[3]/16;
  58.         disnum[7] = ircode[3]%16;
  59. }

  60. void Int0 () interrupt 0
  61. {
  62.         if(startflag)
  63.         {
  64.                 if(irtime>32 && irtime<63)    // 8~16ms
  65.                 {
  66.                         bitnum = 0;
  67.                 }
  68.                 irdata[bitnum] = irtime;      // 存放每位进中断的次数
  69.                 irtime = 0;                   // 清零,为下次计数做准备
  70.                 bitnum++;                     // 下标加一
  71.                 if(bitnum==33)                // 判断是否33位数据接收完
  72.                 {
  73.                         bitnum = 0;
  74.                         irok = 1;                 // 接收完成标志
  75.                 }
  76.         }
  77.         else
  78.         {
  79.                 irtime = 0;
  80.                 startflag = 1;
  81.         }
  82. }
  83. void Timer0() interrupt 1
  84. {
  85.         irtime++;
  86. }

  87. void main()
  88. {
  89.         Int0Init();
  90.         Timer0Init();
  91.         while(1)
  92.         {
  93.                 if(irok == 1)                 // 接收完成
  94.                 {
  95.                         irpros();
  96.                         irok = 0;
  97.                 }
  98.                 if(irprosok == 1)             // 码值转换完成
  99.                 {
  100.                         irwork();
  101.                         irprosok = 0;
  102.                 }
  103.                 display(0,disnum[4]);         // 显示键值
  104.                 display(1,disnum[5]);
  105.                 display(2,20);                // 显示"H"
  106.         }
  107. }
复制代码


全部资料51hei下载地址:
里面的东西,上面都贴出来了。这个可以当资料收藏.docx (59.45 KB, 下载次数: 197)
红外接收代码.rar (44.14 KB, 下载次数: 280)
红外发射代码.rar (35.38 KB, 下载次数: 271)

评分

参与人数 3黑币 +65 收起 理由
51heizlxz + 9
Jeff_BlindCat + 6 共享资料的黑币奖励!楼主耐心负责解答
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏51 分享淘帖 顶4 踩
回复

使用道具 举报

沙发
ID:282095 发表于 2019-7-9 10:50 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:116347 发表于 2019-7-12 19:27 | 只看该作者
感谢楼主分享
回复

使用道具 举报

地板
ID:586051 发表于 2019-7-18 09:48 | 只看该作者
谢谢楼主,请问用C52需要改哪些地方
回复

使用道具 举报

5#
ID:427492 发表于 2019-7-18 13:52 | 只看该作者
zhu6711061 发表于 2019-7-18 09:48
谢谢楼主,请问用C52需要改哪些地方

你看看红外接收、发射、按键这些端口跟你的一样不一样,不一样就要修改;同时看看定时器的晶振和模式
回复

使用道具 举报

6#
ID:427492 发表于 2019-7-18 13:55 | 只看该作者
zhu6711061 发表于 2019-7-18 09:48
谢谢楼主,请问用C52需要改哪些地方

数码管中驱动74hc595引脚不一样的话,也要修改
回复

使用道具 举报

7#
ID:586051 发表于 2019-7-23 09:59 | 只看该作者
请问楼主可以贴一下 hc595.h  和 display(0,disnum[]); 函数的代码嘛?感谢   
回复

使用道具 举报

8#
ID:427492 发表于 2019-7-23 12:05 | 只看该作者
zhu6711061 发表于 2019-7-23 09:59
请问楼主可以贴一下 hc595.h  和 display(0,disnum[]); 函数的代码嘛?感谢

/**************************************************************/
#ifndef __HC595_H__
#define __HC595_H__

#include <STC8.h>
#include <intrins.h>

#ifndef u8                            // 重命名
#define u8 unsigned char
#endif

#ifndef u16                           // 重命名
#define u16 unsigned int
#endif

sbit P_HC595_SRCLK = P3^5;            // 数据输入时钟线
sbit P_HC595_RCLK  = P3^4;            // 输出存储器锁存时钟线
sbit P_HC595_SER   = P3^7;            // 串行数据输入

void SEG_HC595send(unsigned char x);  // hc595发送一个字节数据
void display(unsigned char pos,unsigned char dat); // pos位数码管显示数字dat


#endif
/****************************************************************/
#include "hc595.h"

// 段选:dp、g、f、e、d、c、b、a
unsigned char const LedData[]=
   {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xFF , 0x00, 0xbf,0x7f,0x89};
//  "0"  "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"   "9"  "A"  "B"  "C"  "D"  "E"  "F" "全灭" "全亮" "-"  "."  "H"

// 位选:CS1、CS2、CS3、CS4、CS5、CS6、CS7、CS8
unsigned char const LedPos[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

void delay_ms(unsigned int xms)   // 延时xms毫秒
{
        unsigned char i, j;
        unsigned int x;
        for(x=xms;x>0;x--)
        {
                i = 16;
                j = 147;
                do
                {
                        while (--j);
                } while (--i);
        }
}
/*************************************************
* 函数名:Send_595
* 描述  :hc595发送一个字节数据
* 参数  :dat  (位选或段选)
* 返回值:无
* 调用  :内部调用
*************************************************/

void Send_595(unsigned char dat)
{       
        u8 i;
        for(i=0; i<8; i++)
        {
                dat <<= 1;
                P_HC595_SER   = CY;
                P_HC595_SRCLK = 0;
                _nop_();
                P_HC595_SRCLK = 1;               
        }
}

/*************************************************
* 函数名:display
* 描述  :pos位数码管显示数字dat
* 参数  :pos,dat
* 返回值:无
* 调用  :外部调用
*************************************************/

void display(unsigned char pos,unsigned char dat)
{
        Send_595(LedPos[pos]);          //
        Send_595(LedData[dat]);
        P_HC595_RCLK = 0;
        _nop_();
        P_HC595_RCLK = 1;         
        delay_ms(2);
}
/**********************************************************/
回复

使用道具 举报

9#
ID:591106 发表于 2019-8-5 11:06 | 只看该作者
注释十分详细,感谢楼主
回复

使用道具 举报

10#
ID:370231 发表于 2019-9-4 16:22 | 只看该作者
感谢楼主分享
回复

使用道具 举报

11#
ID:163623 发表于 2020-1-3 22:05 | 只看该作者
大佬stc8写的用51可以用吗
回复

使用道具 举报

12#
ID:427492 发表于 2020-1-6 12:50 | 只看该作者
cuibaigao 发表于 2020-1-3 22:05
大佬stc8写的用51可以用吗

可以,有定时器,有红外发射和接收就行
回复

使用道具 举报

13#
ID:452928 发表于 2020-1-7 19:23 | 只看该作者
大佬,强啊 ,解释很到位。找这红外发送接收好久了 阿里嘎多
回复

使用道具 举报

14#
ID:452928 发表于 2020-1-8 14:38 | 只看该作者
接收程序大体我读懂了,但是那个INT0中断服务程序中,8~16ms,引导码不是9ms+4.5ms=13.5ms么? 这样子不会影响后面数据的接收么?
回复

使用道具 举报

15#
ID:427492 发表于 2020-1-9 18:43 | 只看该作者
nls 发表于 2020-1-8 14:38
接收程序大体我读懂了,但是那个INT0中断服务程序中,8~16ms,引导码不是9ms+4.5ms=13.5ms么? 这样子不会 ...

这个if语句,判断最新接收的波段是不是引导码,不是就不解码。是的话,开始解码。对后面数据没有影响(发射不特别频繁的情况下)
回复

使用道具 举报

16#
ID:684413 发表于 2020-1-9 23:36 | 只看该作者
感谢分享
回复

使用道具 举报

17#
ID:658393 发表于 2020-2-7 20:31 | 只看该作者
没有人跟你说有错误吗?我新手找了半天错误,发射那块应该9000/26才对吧。
回复

使用道具 举报

18#
ID:658393 发表于 2020-2-7 20:33 | 只看该作者
没人跟你说有小错误吗?发射和接收解码都不一样。
回复

使用道具 举报

19#
ID:251029 发表于 2020-3-1 10:35 | 只看该作者
很好的文章,信息量大,感谢楼主的辛勤努力!
回复

使用道具 举报

20#
ID:427492 发表于 2020-3-7 11:19 | 只看该作者
HAN??? 发表于 2020-2-7 20:33
没人跟你说有小错误吗?发射和接收解码都不一样。

开发板不一样的话,是需要改参数的。我同样的两片开发板,试的结果是正确的。你应该根据自己的晶振频率去修改
回复

使用道具 举报

21#
ID:408608 发表于 2020-4-1 23:31 | 只看该作者
两片板子这样写没啥问题,不知发射有没有更好的办法
如果一片板子同时收发,这样好像会有问题
发码里面有个死循环,好像会导致收不了码,串口,数码管都无法正常显示了
回复

使用道具 举报

22#
ID:51443 发表于 2020-4-2 09:32 | 只看该作者
用楼主这个程序发码时,引导码9+4.5有时正常,有时发成9+3.3,有时发成6.6+4.5,甚至有时发成6.6+3.3。用的是stc15w104,不知道是什么原因
回复

使用道具 举报

23#
ID:427492 发表于 2020-4-2 18:41 | 只看该作者
职教电子 发表于 2020-4-2 09:32
用楼主这个程序发码时,引导码9+4.5有时正常,有时发成9+3.3,有时发成6.6+4.5,甚至有时发成6.6+3.3。用的 ...

这个要根据自己开发板使用的晶振频率,去计算要计数的个数
回复

使用道具 举报

24#
ID:427492 发表于 2020-4-2 18:47 | 只看该作者
fan233 发表于 2020-4-1 23:31
两片板子这样写没啥问题,不知发射有没有更好的办法
如果一片板子同时收发,这样好像会有问题
发码里面有 ...

我没有深入去了解这个,不太清楚其他实现方式。一个板子实现收发应该是可以实现的
回复

使用道具 举报

25#
ID:707144 发表于 2020-5-4 11:46 | 只看该作者
亲,stc8.h是什么芯片
回复

使用道具 举报

26#
ID:707144 发表于 2020-5-4 12:45 | 只看该作者
你好,请问发送完键值和键值反码之后,又发送了0.56ms的高电平和低电平是什么意思
回复

使用道具 举报

27#
ID:427492 发表于 2020-5-9 10:50 | 只看该作者
妖小白 发表于 2020-5-4 11:46
亲,stc8.h是什么芯片

stc8a8k64s4a12
回复

使用道具 举报

28#
ID:427492 发表于 2020-5-9 10:50 | 只看该作者
妖小白 发表于 2020-5-4 12:45
你好,请问发送完键值和键值反码之后,又发送了0.56ms的高电平和低电平是什么意思

结束码
回复

使用道具 举报

29#
ID:628542 发表于 2020-7-4 23:57 | 只看该作者
非常感谢楼主分享,很详细的代码
回复

使用道具 举报

30#
ID:797981 发表于 2020-7-5 20:01 | 只看该作者
首先感谢楼主的讲解和代码!收获很多!  但我有个问题,就是比如在接收发射“1”,也就是接收时低电平时,应该是37kHz的调制信号,也就是37kHz的0-1跳变序列,那不会频繁触发中断么?
回复

使用道具 举报

31#
ID:495287 发表于 2020-7-7 00:38 | 只看该作者
楼主大爱,针对网友耐心讲解。
代码书写工整简洁,吾等萌新还要学习。
回复

使用道具 举报

32#
ID:510861 发表于 2020-7-23 11:51 来自手机 | 只看该作者
感谢分享   也下载来做遥控风扇
回复

使用道具 举报

33#
ID:497922 发表于 2020-8-7 15:15 | 只看该作者
在做类似的红外收发的案子,过来学习的哈
回复

使用道具 举报

34#
ID:284050 发表于 2020-10-26 22:18 | 只看该作者
能补充一下发射部分的电路原理图吗
回复

使用道具 举报

35#
ID:210959 发表于 2021-6-27 16:36 | 只看该作者
按照楼主的方法,使用STC8F1K08芯片红外发射成功,使用定时器产生载波比使用STC硬件PWM还方便,附红外收发部分原理图。

红外接收.JPG (49.71 KB, 下载次数: 128)

红外接收.JPG

红外发送.JPG (64.64 KB, 下载次数: 112)

红外发送.JPG
回复

使用道具 举报

36#
ID:586073 发表于 2021-10-1 14:50 | 只看该作者
如果用T0的gate模式,结合int0输入,是不是可以直接测量脉宽时间,这样解码部分还可以再简洁一点。
回复

使用道具 举报

37#
ID:965487 发表于 2021-10-5 19:36 | 只看该作者
    今天无事,学习一下红外接收解码,也帖上自己仿写的程序,认为比前例子精减,但不失性能。

/*-----------------------------------------------
【实验平台】: QX-MCS51 单片机开发板
* 【外部晶振】: 11.0592mhz      
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4         

名称:遥控器红外解码数码管显示
  内容:按配套遥控器会在数码管上对应显示键码值

                  NEC 标准下的编码表示

                其中:引导码高电平约9000us 左右,低电平约4500us 左右;
                接收端:引导码低电平约9000us 左右,高电平约4500us 左右;
                用户码16 位,数据码16 位,共32位;
        发送端:        数据0 是用“高电平约560us +低电平约560us”表示。
                                数据1 可用“高电平约560us+低电平约1680us”表示

        接收端反转:数据0 是用“低电平约560us +高电平约560us”表示。
                                数据1 可用“低电平约560us+高电平约1680us”表示

------------------------------------------------*/
#include<reg52.h>            //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义

sbit IR=P3^2;                          //红外接口
sbit beep = P2^3;//蜂鸣器接口
#define DataPort P0         //定义数据端口 程序中遇到DataPort 则用P0 替换
sbit LATCH1=P2^6;                //定义锁存使能端口 段锁存
sbit LATCH2=P2^7;                //                 位锁存

unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
                                                //0-F的码表
unsigned char  irtime;        //红外用全局变量

unsigned char IRcord[4];

void delay(unsigned int i)
{
        unsigned int m,n;
        for(m=i;m>0;m--)
                for(n=114;n>0;n--);
}

void tim0_isr (void) interrupt 1 using 1  //STC89C52 11.0592M
{
  irtime++;  //用于计数2个下降沿之间的时间         每个溢出中断时长256*1.085us=277.7us
}

void EX0_ISR (void) interrupt 0 //外部中断0服务函数
{
        static unsigned char  i;             //接收红外信号处理

                if(irtime < 63 && irtime >= 33)//跳过引导码 TC9012的头码,9ms+4.5ms
             {  
                        irtime=0;
                        i=0;
                }                  
                else{
                                IRcord[i/8] >>= 1;          //i/8每处理8位换下一个元素,总的处理4个字节共32位的数据
                                 if(irtime > 6) IRcord[i/8] |= 0x80;           //位0电平时长计数上限4,位1高电平计数上限8
                            irtime = 0;
                            i++;
                        }                                                                                   //这里取6为0/1 的识别分界
                if(i > 31){ i=0; beep = 0;        delay(100); beep = 1; }
}


void TIM0init(void)//定时器0初始化
{
        TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
        TH0=0x00; //重载值
        TL0=0x00; //初始化值
        ET0=1;    //开中断
        TR0=1;   
}
void EX0init(void)
{
IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
EX0 = 1;   //使能外部中断
EA = 1;    //开总中断
}
void SMG_show(unsigned char num)
{
        P0=dofly_DuanMa[num/16];         
        LATCH1=1;
        LATCH1=0;

        P0=0xdf;           //选中第一个数码管
        LATCH2=1;
        LATCH2=0;
        delay(2);

        P0=dofly_DuanMa[num%16];         
        LATCH1=1;
        LATCH1=0;

        P0=0xbf;           //选中第二个数码管
        LATCH2=1;
        LATCH2=0;
        delay(2);
}
void main(void)
{
        EX0init(); //初始化外部中断
        TIM0init();//初始化定时器

        while(1)//主循环
        {
                SMG_show(IRcord[2]);
        }
}
回复

使用道具 举报

38#
ID:960784 发表于 2024-7-16 11:19 | 只看该作者
51heizlxz 发表于 2021-6-27 16:36
按照楼主的方法,使用STC8F1K08芯片红外发射成功,使用定时器产生载波比使用STC硬件PWM还方便,附红外收发 ...

接收也是同一个单片机吗?可以分享一下接收的原理图吗?
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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