羞羞小视频在线观看_羞羞视频免费入口网站_羞羞视频下载APP_男女羞羞视频软件

歡迎光臨東莞市飛江電子科技有限公司官網!
全國咨詢熱線

13926563901

18925580829

飛江淘寶店鋪

首頁>技術資料>其它單片機

STC的51單片機紅外遙控器讀碼、發(fā)射程序,已試成功

發(fā)布時間:2018-04-09   瀏覽量:

 

STC的51單片機紅外遙控器讀碼、發(fā)射程序,已試成功
wxleasyland@sina.com
2014.11.21

有一臺DVD機沒有遙控器,正好別的遙控器有的鍵可以用,但功能不一樣。

于是開展本工程,程序原為網上摘的,經過修改均已全部成功。

采用STC的51單片機,STC12C5A60S2,可以直接串口編程,而且是1T的,非常方便。

一、紅外遙控器讀碼
讀碼程序沒怎么修改就成功了。
注意:這里的延時程序是STC12C5A60S2的,如果用別的單片機,需要修改。

#include <STC\STC12C5A60S2.H>
#include <INTRINS.h>

//采用1T周期的STC12C5A60S2單片機,11.0592MHZ
//WXL:一體化接收頭默認是輸出高電平,有信號時輸出低電平;接P3.2腳。
//WXL:這里按“低位在先”

/******************************************************************/
/* 本程序的藍本從網上搜集,經修改并注釋,萬能遙控器解碼成功 */
/* 晶振:11.0592MHz */
/* 整理與測試:單片機教程網  胡琴 2012.5.15 */
/************************* 說 明 *********************************/
/* 以一個9ms的低電平和4.5ms的高電平為引導碼,后跟32位二進制代碼 */
/* 前16位為8位用戶碼及其反碼,后16位為8位的操作碼及其反碼 */
/* 以脈寬為低電平0.565ms、間隔高電平0.56ms、周期為1.125ms的組合表示"0"; */
/* 以脈寬為低電平0.565ms、間隔高電平1.685ms、周期為2.25ms的組合表示"1"。 */
/* 注意:接收碼的脈寬與間隔是對發(fā)射碼取反的,即間隔是0.565ms */
/* 解碼后共有四個十六進制碼,本程序取第三個作為識別碼 */
/*******************************************************************/

#define uchar unsigned char
uchar data IRcode[4]; //定義一個4字節(jié)的數組用來存儲代碼
uchar CodeTemp; //編碼字節(jié)緩存變量
uchar i,j,k; //延時用的循環(huán)變量
sbit IRsignal=P3^2; //HS0038接收頭OUT端直接連P3.2(INT0)
sbit P0_0=P0^0; //P0連接到 LED 上
sbit P0_1=P0^1;
sbit P0_2=P0^2;



/**************************延時0.6ms子程序**********************/
void Delay0_6ms(void) //@11.0592MHz
{
unsigned char i, j;

_nop_();
_nop_();
i = 7;
j = 112;
do
{
while (--j);
} while (--i);

}


/**************************延時0.9ms子程序**********************/
void Delay0_9ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 10;
j = 170;
do
{
while (--j);
} while (--i);
}




/***************************延時1ms子程序**********************/
void Delay1ms(void)
{
unsigned char i, j;

_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}

/***************************延時4ms子程序**********************/
void Delay4ms(void)
{
unsigned char i, j;

_nop_();
_nop_();
_nop_();
i = 44;
j = 3;
do
{
while (--j);
} while (--i);
}

/**************************** 延時子程序 ************************/
void Delay(void)
{
uchar i,j,k;
for(i=200;i>0;i--)
for(j=200;j>0;j--)
for(k=3;k>0;k--)  ;
}

/******************** 中斷0解碼服務子程序 ********************/
void int0(void) interrupt 0 using 2
{
EA = 0; //??? 可以這樣,跳入中斷,但仍可對P3.2(INT0)進行電平變化的讀取
for(k=0;k<10;k++)
{
Delay0_9ms();
if (IRsignal==1)        //如果0.9ms后IRsignal=1,說明不是引導碼,退出中斷
{
k=10;
break;
}

else if(k==9)         //如果 持續(xù)了10×0.9ms=9ms的低電平,說明是引導碼。WXL:一定是從引導碼開始
{
while(IRsignal==0);      // WXL:因為紅外頭默認輸出是高電平,故用while(IRsignal==0)很安全,而用while(IRsignal==1)則可能會進入死循環(huán)
Delay4ms();       //跳過持續(xù)4.5ms的高電平     WXL:要超過4.5ms更好
Delay0_6ms();

for(i=0;i<4;i++)     //分別讀取4個字節(jié)
{
for(j=1;j<=8;j++)    //每個字節(jié)8個bit的判斷
{
while(IRsignal==0); //等待上升沿,此處用得很好:因為0.56ms的低電平(接收時)是代碼0與1的相同部分
Delay0_9ms(); //從上升沿那一時刻開始延時0.9ms(因為0.9介于0.56(=1.125-0.56)與1.69(=2.25-0.56)之間),再判斷IRsignal
if(IRsignal==1) //  如果IRsignal是"1",高位置"1",并向右移一位
{
Delay1ms(); //為什么要延時1ms呢?因為要使IRsignal跳至低電平(即0.56ms的0與1相同部分上)
CodeTemp=CodeTemp | 0x80; //此處的算法很好
if(j<8)  CodeTemp=CodeTemp>>1;
}
else       //  如果IRsignal是"0",高位置"0",并向右移一位
if(j<8) CodeTemp=CodeTemp>>1;   //如果IRsignal是"0",則直接向右移一位,自動補"0"
}
IRcode=CodeTemp;
CodeTemp=0;
}   //end for

for(i=0;i<4;i++) //通過串口將代碼發(fā)出
{
SBUF=IRcode;
while(!TI); //等待一個字節(jié)發(fā)送完畢
TI=0;
}

Delay();
}    //end else
}   //END for
EA = 1;
}

/***********************串口初始化程序*********************/
void initUart(void)
{
TMOD |= 0x20; //
SCON = 0x50; //
PCON |= 0x80; //
TH1 = 250; // 9600 bps @ 11.0592MHz
TL1 = 250;
TR1 = 1;
}

/**************************主程序*************************/
void main()
{
//P0=0XFF;
initUart();
IT0 = 1; //INT0為負邊沿觸發(fā), (1:負邊沿觸發(fā),0:低電平觸發(fā))
EX0 = 1; //外部中斷INT0開, (1:開, 0:關 )
EA = 1; //開所有中斷

CodeTemp = 0; //初始化紅外編碼字節(jié)緩存變量
Delay();
while(1)
{

}
}






二、紅外遙控發(fā)射

網上的程序是http://gudeng614.blog.163.com/blog/static/818017420101545648734/

做發(fā)射程序費了很大波折,因為網上的程序不好用。

后來不得不用計算機的并口采集了發(fā)射數據,發(fā)現數據有異常,終于找到了問題所在。

原因是count變量是int的,對其賦值或比較時,匯編語句一句完不成,會被中斷服務程序中斷,造成count變量賦值或比較出現問題。
解決方法是必須在操作時屏蔽中斷。而flag變量是bit的,一句匯編即可完成賦值,故不會有問題。

其間還發(fā)現別的遙控器會在起始碼前加一個前脈沖,以為是這個問題,其實不是。

注意:由于13us會中斷一次,這里是采用1T的單片機。如果采用普通的51單片機,由于是12T的,不知道能不能成功。

//程序從網上修改而來
//由于中斷需要13us中斷一次,即中斷要在幾us處理完,因此需要單片機速度比較快,用24MHZ晶振才能保證正常
//但24MHZ晶振,用串口不方便
//這里采用1T周期的STC12C5A60S2單片機,11.0592MHZ,可以兼顧。
//STC12C5A60S2  引腳可灌入20mA電流,直接從正電源→紅外LED→串1K電阻→P0.0腳。
//串口1默認選T1作為波特率發(fā)生器
//TO用于中斷
//發(fā)送時,低比特位優(yōu)先

#include <STC\STC12C5A60S2.H>
#include <INTRINS.h>

sbit  P0_0 = P0^0;

static bit g_OP;            //紅外發(fā)射管的亮滅
static unsigned int g_count;       //延時計數器
static unsigned int g_endcount;    //終止延時計數
static bit g_flag;       //紅外發(fā)送標志
unsigned char g_iraddr1;     //十六位地址的第一個字節(jié)
unsigned char g_iraddr2;     //十六位地址的第二個字節(jié)


//定時器0中斷處理
void timeint(void) interrupt 1
{
  g_count++;
  if (g_flag)    g_OP=~g_OP;
  else    g_OP = 1;    //LED不點亮
  P0_0 = g_OP;
}


/////////////////////////////////////////////////////
void SendIRdata_38KHZ(unsigned int temp1, bit temp2)
{
  g_endcount=temp1;
  g_flag=temp2;
  EA=0; g_count=0; EA=1;  //避免中斷影響count置數
  while(1)
  {
   EA=0;
   if( g_count < g_endcount ) EA=1;  //避免中斷影響count比較
   else
   {
   EA=1;
   break;
   }  
  }  
}

/////////////////////////////////////////////////////
void SendIRdata_BYTE(unsigned char irdata)
{
  unsigned char i;
  for(i=0;i<8;i++)
  {
     //先發(fā)送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)
SendIRdata_38KHZ(43, 1);   //13.02*43=0.56ms

    //停止發(fā)送紅外信號(即編碼中的低電平)
     if(irdata & 1)  //判斷最低位為1還是0。   低位先發(fā)送!!
       SendIRdata_38KHZ(130, 0);         //1為寬電平,13.02*130=1.693ms
    else      SendIRdata_38KHZ(43, 0);   //0為窄電平,13.02*43=0.560ms

    irdata=irdata>>1;
  }
}

/////////////////////////////////////////////////////
void SendIRdata(unsigned char p_irdata)
{
  //有的遙控器會發(fā)一個前脈沖,如果不靈,可試試加上前脈沖
  //發(fā)送起始碼前脈沖,高電平有38KHZ載波
  //SendIRdata_38KHZ(18, 1);
  //發(fā)送起始碼前脈沖,低電平無38KHZ載波
  //SendIRdata_38KHZ(18, 0);

  //發(fā)送9ms的起始碼,高電平有38KHZ載波
  SendIRdata_38KHZ(692, 1); //13.02*692=9.010ms

  //發(fā)送4.5ms的結果碼,低電平無38KHZ載波
  SendIRdata_38KHZ(346, 0);    //13.02*346=4.505ms

  //發(fā)送十六位地址的前八位
  SendIRdata_BYTE(g_iraddr1);

  //發(fā)送十六位地址的后八位
  SendIRdata_BYTE(g_iraddr2);

  //發(fā)送八位數據
  SendIRdata_BYTE(p_irdata);

  //發(fā)送八位數據的反碼
  SendIRdata_BYTE(~p_irdata);  

  //發(fā)送總的結束位1bit
  SendIRdata_38KHZ(43, 1);     //13.02*43=0.56ms


/*  //后面這些可以不用發(fā)
  g_endcount=1766;
  g_flag=0;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   

  //發(fā)送9ms的起始碼,高電平有38KHZ載波
  g_endcount=692;   //13.02*692=9.010ms
  g_flag=1;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   

  //發(fā)送4.5ms的結果碼,低電平無38KHZ載波
  g_endcount=346;    //13.02*346=4.505ms
  g_flag=0;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   

//發(fā)送總的結束位1bit
  g_endcount=43;    //13.02*43=0.56ms
  g_flag=1;
  EA=0; g_count=0; EA=1;
  while(1){EA=0; if(g_count<g_endcount) EA=1; else { EA=1; break; }  }   

*/

  g_flag=0;


}



///////////////////////////////////////////////////////////
void main(void)
{
unsigned char com_data;    //數據字節(jié)

  g_count = 0;
  g_flag = 0;
  g_OP = 1;
  P0_0 = g_OP;   //LED接電源正極,不點亮

SCON=0x50;  //串口方式1    01 0 1 0 0 00  模式1,非多機,允許接收,無數據位8,清中斷標識TI和RI

  TMOD = 0x22; //(定時器0和1:方式2,自動重裝,8位)
TH1=253;  //11.0592MHZ,9600bps。沒有設置SMOD,故波特率沒有加倍。即:11.0592/12/3/32=9600bps
TL1=253;
TR1=1;    //啟動定時器

  TH0 = 244;
  TL0 = 244; //(WXL:即計數12次中斷一次,即11.0592MHZ晶振,機器周期是1.085us,12次*1.085=13.02us,這樣達38KHZ。  13us一次中斷,時間太短了,所以單片機要快)
  ET0 = 1;   //定時器0中斷允許
  EA = 1;    //允許CPU中斷
  TR0 = 1;   //開始計數

  g_iraddr1=0;       //地址碼
  g_iraddr2=255;     //地址反碼

RI=0;
while(1)
{
if(RI==1)
{
com_data =SBUF;
RI=0;       //要人工清RI
SendIRdata(com_data);   //發(fā)送紅外數據
TI=0;
SBUF = com_data;   //輸出字符
while(!TI) ;     //空語句判斷字符是否發(fā)完,TI=1表示發(fā)完
TI = 0;         //要人工清TI
}
}

}