打印

浅谈红外线发射的几种方法

[复制链接]
6128|28
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
老鱼探戈|  楼主 | 2011-4-21 16:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 老鱼探戈 于 2011-4-21 17:17 编辑

如果你还不太了解红外线,请谷歌一下。
如果你还不太了解红外线的使用,请看下文。

一、先说一个最笨的方法:就地延时等待发射。
   此方法适用于发射机功能简单到发射是唯一的大任务的工程项目,其他有一些诸如按键检测、RC充放电、AD检测、LED指示等功能都不会受什么影响。

   参考程序1
//*****************************************************//
//所用母体:SN8P2501B
//ICE版本号:SN8 C Studio_100702(564.158)
//初始编辑:老鱼探戈
//最后修改:2011-4-20
//*****************************************************//
#define uchar
unsigned char

#define uint
unsigned long //sonix
C编译器中的long型是16

#define
SD_LONG
24u
//
必须为偶数,单位BIT的长度:24-->24*13us=312us


uchar SendDataH;
uchar SendDataM;
uchar SendDataL;
uchar SendDataA;

extern uchar Dat_IrCont0;
extern bit FIrEnb;
//IR
发送允许38k

//***************************************//
//函数名称:void SendSync(void)
//输入参数:无
//输出参数:无
//函数功能:发射同步头
//**************************************//
void SendSync(void)
{
FIrEnb=1;
//
允许翻转


Dat_IrCont0=0;


while(Dat_IrCont0<SD_LONG);


Io_SendIR=0;


FIrEnb=0;


Dat_IrCont0=0;


while(Dat_IrCont0<5*SD_LONG);

}
//***************************************//
//函数名称:void SendEnd(void)
//输入参数:无
//函数功能:发射同步尾
//**************************************//
void SendEnd(void)
{
FIrEnb=1;
//
允许翻转


Dat_IrCont0=0;


while(Dat_IrCont0<SD_LONG);


Io_SendIR=0;

}
//***************************************//
//函数名称:void Send_Byte(uchar data0,uchar bl)
//输入参数:data0,b1
//输出参数:无
//函数功能:发射b1位数据
//**************************************//
void Send_Byte(uchar data0,uchar bl)

{ uchar i;

sbit
blow=data0:7;


for(i=0;i<bl;i++)


{


FIrEnb=1;


Dat_IrCont0=0;


while(Dat_IrCont0<SD_LONG);


Io_SendIR=0;


FIrEnb=0;


Dat_IrCont0=0;


if(blow) while(Dat_IrCont0<2*SD_LONG);


else
while(Dat_IrCont0<SD_LONG);


data0<<=1;


}

}
//****************************************//
//函数名称:void SendIR(void)
//函数功能:红外线发射一帧数据
//***************************************//
extern void SendIR(void)
{
if(!FCharge)

{

FTC0ENB=1;   //
打开38k定时器

SendSync();

Send_Byte(SendDataH,8);

Send_Byte(SendDataM,8);

Send_Byte(SendDataL,8);

Send_Byte(SendDataA,8); //
校验和

SendEnd();


FTC0ENB=0;  //
关闭38K中断,因为太快了只在发射的时候打开


}

else FTC0ENB=0;

}
//***************************************//
//函数名称:__interrupt
ISR(void)

//函数功能:中断函数,C编译器不够完美,所以嵌入汇编
//**************************************//
__interrupt
ISR(void)

{
__asm


{

PUSH

B0BCLR   FTC0IRQ          //13us
中断,用于红外线发生器

MOV        A,#10h         //
对位取反

BTS0      _FIrEnb
XOR       P5,A   //发射口为P54
INCMS     _Dat_IrCont0   //汇编中的变量将前面+"_"
}

}
   些台系的IC是内置38K57K发射的,例如佑华、一般的语音IC都有,还有sonix26系列也有。所以只需配置相应的寄存器即可实现发射功能。

红外线发射的几种方法.pdf

69.81 KB

相关帖子

沙发
老鱼探戈|  楼主 | 2011-4-21 17:18 | 只看该作者
本帖最后由 老鱼探戈 于 2011-4-21 17:25 编辑

二、上面所说的那个方法需要延时等待,在发射过程中CPU不能执行其他的功能,严重降低了CPU的效率。如果工程中还牵涉到LCD(不管是点阵的还是TN的)驱动程序、PWM控制、复合按键(长击,双击灯)、接口扩展等,后果就会很严重。这也是
老鱼下面要解决的问题。

   A、把发射函数置于中断外,这样做可以减少中断函数的负担,可以去执行更多其他的功能,但是发射编码的时间需要做进一步调整(需要考虑主循环的时间误差)。不过我们可以在接受端适当的把范围放宽。

//*****************************************************//
//所用母体:SN8P2501B
//ICE版本号:SN8 C Studio_100702(564.158)
//*****************************************************//
extern void SendRF(void);
extern uchar FSendWork0;
sbit        FSend38K        = FSendWork0:7;
sbit        FIrEnb                = FSendWork0:6;
sbit         FSyncEnd        = FSendWork0:5;
sbit         FDataOK                = FSendWork0:4;
sbit        FIRCntEnb        = FSendWork0:3;
sbit        FSyncOk                = FSendWork0:2;
sbit        FCycleOver        = FSendWork0:1;

uchar FSendWork0;
uchar SdBitCnt=0;
uchar RDataSend;   //        准备发射的数据

//==================================================
//函数名称:void SendData(uchar Data,uchar temp0)
//函数功能:数据信号发射  位格式:38K/低电平
//                      数据0        300us/300us
//                      数据1        300us/600us
//==================================================
void SendData(uchar Data,uchar temp0)
{        
        if(FDataOK) return;
        if(!FSend38K)
        {        
                IRTimeCnt0=23U;                //38K  23
                FIrEnb=1;
                FCycleOver=1;
                FSend38K=1;        
        }
        else
        {
                if((Data<<temp0)&0x80)
                        { IRTimeCnt0=34U;}        //参数需要调准               
                else  IRTimeCnt0=17U;        //低电平发射,参数需要调准
                FIrEnb=0;
                FCycleOver=1;
                FSend38K=0;                //低电平发射
                SdBitCnt++;
                if(SdBitCnt>=9)                //发射位数
                {
                        SdBitCnt=0;
                        FDataOK=1;
                }
        }        
}

//==================================================
//函数名称:void SendSync(void)
//函数功能:同步头发射  1200/300us   38K/低电平
//==================================================
void SendSync(void)
{
        if(!FSend38K)                //为0时,发射38K
        {
                IRTimeCnt0=91U;                //23
                FSend38K=1;
                FIrEnb=1;
                FCycleOver=1;
        }        
        else
        {
                IRTimeCnt0=15U;                //6
                FIrEnb=0;
                FCycleOver=1;
                FSend38K=0;
                FSyncOk=1;                //同步头完成
        }                        
}

//==================================================
//函数名称:void SendSyscEnd(void)
//输入参数:无
//输出参数:无
//函数功能:同步尾  300us/13=23
//==================================================
void SendSyscEnd(void)
{
        IRTimeCnt0=23U;                //6
        FIrEnb=1;
        FSyncEnd=1;        
        FCycleOver=1;        
}

//==================================================
//函数名称:void SendRF(void)
//输入参数:无
//输出参数:无
//函数功能:信号发射
//只发射了8位有效数据,如果想发送更多的位,只需要加
//相应的寄存器和标志位即可。
//==================================================
void SendRF(void)
{        
        if(!FGunFire)  return;//为1时发射子弹信号
        if(!FSendGunIR)        {        
                FSendGunIR=1; FTC0ENB=1;        
                FIRCntEnb=1;
            }                        
        if(!FCycleOver)
        {                                       
                if(FSyncOk)
                {
                 SendData(RDataSend,SdBitCnt);
                        if(FDataOK)
                        {
                                SendSyscEnd();        
                                if(FSyncEnd)
                                {
                                FTC0ENB=0;                        
                                FIrEnb=0;        
FIRCntEnb=0;
                                FSyncOk=0;        
FSyncEnd=0;
                                FDataOK=0;        
FSendGunIR=0;
                                FGunFire=0;        
Rfout=0;
                                }
                        }        
                }
            else
            SendSync();        
        }
}

//==================================================
//函数名称:ISR(void)
//输入参数:无
//输出参数:无
//函数功能:中断服务        
//==================================================
__interrupt  ISR(void)
{
        FTC0IRQ=0;
        if(FIrEnb)
        Rfout=~Rfout;        //13us中断
        IRTimeCnt0++;
}

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
whilebreak + 1
板凳
老鱼探戈|  楼主 | 2011-4-21 17:18 | 只看该作者
本帖最后由 老鱼探戈 于 2011-4-21 19:37 编辑

B、把发射函数置于中断中,发射编码的时间不需要做进一步调整,而且时间很准的哦。看老鱼把他写成宏了,这样用起来多方便啊,呵呵。
                             
EIR_SYNC         equ        22+1        //23*13=300us
EIR_SYNCL        equ        92+1        //92*13=1200us
EIR_38k_H        equ        22+1        //300us
EIR_Low_1        equ        44+1        //600us  
EIR_Low_0        equ        22+1        //300us
EIR_DataLng      equ        25         //发送数据总长度(位)最后一为同步尾
EIR_SendLng      equ        EIR_DataLng*2+2                 

DIR_38kCnt    reg        0x18
DIR_SdBitCnt  reg        0x19
DIR_Data0     reg        0x1A
DIR_Data1     reg        0x1B
DIR_Data2     reg        0x1C
DSendTmCnt    reg        0x1D

/*------------ 中断服务 --------------*/         
          org       08h  
          PUSH                  //保护现场            
          bcr       INTFLAG,T0IF_B    //清中断标志   
          TM_RELOAD E_25us
          btrss     FIR_Enb                        
          lgoto     LB_int_cnt                                    
          TM_RELOAD E_12_5us                    
          MIR_Int   //IR_TX        
               
          btrss     DIR_38kCnt,0    //12.5us时要两次才算一次
          lgoto     LB_Int_Out
LB_int_cnt:  
          incr      DSysClkCntms,1
                  //        ............
                  //        you other code

LB_Int_Out:
          POP                  //恢复现场
          Retie

//==================================================
//函数名称:MInt_IR
//输入参数:无   
//输出参数:无
//函数功能:红外信号发送
//用    法: 将此宏置于13us的中断中,启动发送后将自动完成,当前只能完成24位发送,
//若需要更多,需要修改EIR_DataLng,添加 DIR_Data3..., 在RLR处添加,同时注意上面的
//Goto $+x要相应地改变
//==================================================      
MIR_Int  macro            
        decrsz           DIR_38kCnt,1  
        lgoto            $+20//       20    Int_01
        bcr              PIROut   //IO_IR   
        movia            EIR_Low_0
        btrsc            DIR_Data0,7
        movia            EIR_Low_1  
        btrsc            DIR_SdBitCnt,0
        movia            EIR_38k_H
        btrss            FIR_Sync
        movia            EIR_SYNCL         
        movar            DIR_38kCnt
        bsr              FIR_Sync                        
        btrss            DIR_SdBitCnt,0                        
        lgoto            $+4
        RLR              DIR_Data2,1  //带C左移
        RLR              DIR_Data1,1
        RLR              DIR_Data0,1
        decrsz           DIR_SdBitCnt,1
        lgoto            $+7         
        bcr              FIR_Enb                 
        lgoto            $+5                              
//Int_01:                                 
        btrsc            DIR_SdBitCnt,0  
        lgoto             $+3        
        TurnB            PTA,0X02    //有2字节
        endm

      以上是老鱼常用的几种发射方法,写的不好的地方请大家指正,热切希望您有更好的方法和思路与大家分享。
     射频发射的原理是一样的,只是不需要自己产生载波信号,其实更简单。

使用特权

评论回复
地板
不光写程序| | 2011-4-21 19:00 | 只看该作者
红外遥控对战飞机:lol

使用特权

评论回复
5
老鱼探戈|  楼主 | 2011-4-21 19:33 | 只看该作者
红外遥控对战飞机:lol
不光写程序 发表于 2011-4-21 19:00

不只是能够打飞机的:lol ,红外线还有很多方面的应用
并且现在的飞机都改成2.4G和WIFI了:D

使用特权

评论回复
6
Linda_008| | 2011-4-22 15:00 | 只看该作者
老鱼,
小弟初学单片机的,用STC89C52有没有好的程序
参考下

使用特权

评论回复
7
zgs523801275| | 2011-4-22 15:06 | 只看该作者
学习了。。。。。。。。

使用特权

评论回复
8
Linda_008| | 2011-4-22 15:57 | 只看该作者
/********************************************************************************
所用IC:STC89C52
晶振12MHZ,红外线发码UPD6121G格式
UPD6121G格式:引导码 + 低8位用户码 + 高8位用户码 + 8位键数据码 + 8位键数据反码
引导码:9ms载波 + 4.5ms关断时间  用户码跟数据码的数据:先发低位到高位
*******************************************************************************/
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula = P2^0;
sbit wela = P2^1;
sbit s1 = P3^0;                                                                 /*按键1*/
sbit s2 = P3^1;                                                                  /*按键2*/
sbit led = P1^0;                              /*指示灯*/
sbit irout = P2^3;                                     /*红外发射管脚,拉低*/

/***************************************************************
函数名称:void delay40us(uint lsje_00)
输入参数:lsje_00
输出参数:无
函数功能:延时程序40us
***************************************************************/
void delay40us(uint lsje_00)
{
            uchar  kshie;                       /*2us*/
         while(lsje_00 !=0)                                         /*4us*/
         {
            for(kshie=0;kshie<10;kshie++)         /*(3*10+2)us*/
                {
                }
                lsje_00--;                                                 /*2us*/
         }
}

/**************************************************************
函数名称:void ir_38(uint lsje_01)
输入参数:lsje_01
输出参数:无
函数功能:irout输出38k载波;周期约为26us;高-8.77us,低-17us,程序长为27us
***************************************************************/
void ir_38(uint lsje_01)
{
            uchar  kshie;                                           /*2us*/
         while(lsje_01 !=0)                                   /*4us*/
         {
                 irout = 1;                              /*1us*/
                 for(kshie=0;kshie<2;kshie++)  /*(3*2+2)us*/
                 {           
                 }
                 irout = 0;                                          /*1us*/
                irout = 0;                                          /*1us*/
                 for(kshie=0;kshie<2;kshie++)  /*(3*2+2)us*/
                 {           
                 }
                lsje_01--;                                          /*2us*/
          }
}
/******************************************
函数名称:void ir_di(uint lsje_02)
输入参数:lsje_02
输出参数:无
函数功能:irout输出低,程序时长50us
******************************************/
void ir_di(uint lsje_02)
{
            uchar  kshie;                       /*2us*/
         while(lsje_02 !=0)                                         /*4us*/
         {
            irout = 0;                                             /*1us*/
                for(kshie=0;kshie<13;kshie++)         /*(3*13+2)us*/
                {
                }
                lsje_02--;                                                 /*2us*/
         }
}

/******************************************
函数名称:void fama8(uchar k)
输入参数:k
输出参数:无
函数功能:8位数据38K发码程序, 将发码数据分出0和1,发码由低位到高位,
******************************************/
void fama8(uchar k)
{
        uchar i;
        bit r,n=1;
        for(i=0;i<8;i++)
        {
                                          
                r = k&n;                   /*按位与,1与k低0位与*/
                if(r == 0)
                {
                        ir_38(24);                    /*红外逻辑0,高(38K)-650us,低-500us*/
                        ir_di(10);
                }
                else if(r == 1)
                {
                        ir_38(24);                /*红外逻辑1,高(38K)-650us,低-1700us*/
                        ir_di(33);               
             }
                 k = k>>1;
        }

}
/******************************************
函数名称:void fama32(uchar yhgao,uchar yhdi,uchar nj)
输入参数:yhgao,yhdi,nj
输出参数:无
函数功能:upd6121格式发码程序
32位,引导码--高8位用户码--低8位用户码--键码--键反码--结束码
******************************************/
void fama32(uchar yhgao,uchar yhdi,uchar nj)
{
        ir_38(325);    /*引导码 高9ms,低4.5ms*/
        ir_di(88);

        fama8(yhgao);           /*用户码40 BF*/
        fama8(yhdi);
        fama8(nj);           /*键码03反码 FC*/
        fama8(~nj);
        ir_38(22);           /*结束高*/

        ir_di(778);           /*发码时间间隔最少108ms,才可发第二贞*/
        ir_38(325);           /*结束码 高9ms,低2.25ms,高580us*/
        ir_di(41);
        ir_38(22);
}

/******************************************
函数名称:void led_shan(uint t)
输入参数:t
输出参数:无
函数功能: 当按键按下时 灯闪亮
******************************************/
void led_shan(uint t)
{
        uint n,c;
        for(c=0;c<t;c++)
        {
                for(n=0;n<5000;n++);       
                led =~led;                    
        }
}

void main()
{
        //ir_di(1000);
        while(1)
        {
                P3 = 0xff;
                if(s1 == 0)
                {
                        delay40us(125);
                        P1 = 0xff;
                        while(!s1)
                        {
                                delay40us(125);
                                led_shan(20);
                                fama32(0x40,0xbf,0x03);
                                P1 = 0xff;
                        }
                        while(!s1);
                }
        }
       
}

使用特权

评论回复
9
老鱼探戈|  楼主 | 2011-4-22 16:37 | 只看该作者
本帖最后由 老鱼探戈 于 2011-4-22 16:38 编辑

8# Linda_008

你用的延时等待发射,可以用中断来计时和IO口电平翻转,这样时间容易控制准确度
汇编能看懂吗?C语言写起来就更好了,特别是大部分人用过的51

使用特权

评论回复
10
haiping0823| | 2011-4-22 18:26 | 只看该作者
同行路过;LZ在那个遥控器厂上班!

使用特权

评论回复
11
haiping0823| | 2011-4-22 18:32 | 只看该作者
在38KHZ载波上我认为用宏来发射数据跟用CALL指令差不多的,遥控器应该很少用中断来产生载波的吧,貌似对睡眠有影响!

使用特权

评论回复
12
haiping0823| | 2011-4-22 18:41 | 只看该作者
做遥控器的单片机有2个要求:1.低功耗  2.低价格(0.6元左右 16PIN)

使用特权

评论回复
13
lixupengIC| | 2011-4-22 22:11 | 只看该作者
mark!!!!

使用特权

评论回复
14
lfb112| | 2011-4-22 22:21 | 只看该作者
啊,熟悉的SONIX,一直在用汇编,都没用过松翰的c编译器。未做过发射部分,下下来,学习学习。

使用特权

评论回复
15
老鱼探戈|  楼主 | 2011-4-23 10:05 | 只看该作者
在38KHZ载波上我认为用宏来发射数据跟用CALL指令差不多的,遥控器应该很少用中断来产生载波的吧,貌似对睡眠有影响!
haiping0823 发表于 2011-4-22 18:32

可以说是差不多的。同个程序N次使用,宏占用的ROM是CALL的N倍。
如果程序中需要多次调用我们一般使用CALL,如果是一两次而已可以考虑用宏来替代,因为宏的好处在于可以像头文件一样包含即可,放在一个固定的目录,每次都可以直接调用。
宏的作用主要体现在宏指令上,一些单片机汇编中没有的指令,比如:大于等于跳转,在范围内跳转,位不相等跳等N等。

使用特权

评论回复
16
1183146117| | 2011-4-23 10:07 | 只看该作者
不错啊 3# 老鱼探戈

使用特权

评论回复
17
yxxcf| | 2011-4-23 10:30 | 只看该作者
挺好

使用特权

评论回复
18
ningling_21| | 2011-4-23 16:35 | 只看该作者
ding ding ding!

使用特权

评论回复
19
Linda_008| | 2011-4-23 17:25 | 只看该作者
汇编以前学过,很少用。
试了用定时的,按键确认按下发码后,启动定时
108ms后发结束码,但是按下的时间如大于108ms就不行
可以加扣扣深聊吗?
四六二零二八五一
9# 老鱼探戈

使用特权

评论回复
20
老鱼探戈|  楼主 | 2011-4-23 17:27 | 只看该作者
汇编以前学过,很少用。
试了用定时的,按键确认按下发码后,启动定时
108ms后发结束码,但是按下的时间如大于108ms就不行
可以加扣扣深聊吗?
四六二零二八五一
9# 老鱼探戈  ...
Linda_008 发表于 2011-4-23 17:25


那是因为你的按键程序有问题,至少不适合你说的这个项目

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:先思而后动~ 生活迢迢几十秋,几处安乐;人生寥寥数十载,何不快活。!

11

主题

5264

帖子

251

粉丝