/**
*************************************************************************
* @file main.c
* @author xr
* @date 2014年3月31日22:30:08
* @version V1.2.3
* @brief 串口通信+紅外通信 通過串口發送紅外遙控器的解碼值到PC
* @note 單片機STC89C52RC MCU 晶振 11.0592MHZ
*************************************************************************
*/
#include <reg52.h>
void ConfigUart();
void UartSend(unsigned char dat);
void delayms(unsigned int xms);
extern bit irflag;
extern unsigned char ircode[4];
extern void ConfigInfrared();
void main()
{
ConfigUart();
ConfigInfrared();
while (1)
{
if (irflag) //接收到紅外數據
{
irflag = 0;
UartSend(ircode[0]); //發送用戶碼
delayms(100);//延時100ms
UartSend(ircode[2]); //發送鍵碼
}
}
}
/**
* @brief 延時xms
* @param xms
* @retval 無
*/
void delayms(unsigned int xms)
{
unsigned int x, y;
for (x = 0; x < xms; x++)
for (y = 0; y < 110; y++);
}
/**
* @brief 配置串口通信
* @param 無
* @retval 無
*/
void ConfigUart()
{
TMOD &= 0x0F;//清零T1控制位
TMOD |= 0x20;//T1方式2,八位自動重裝模式
TH1 = 0xFD; //波特率 = 256-1/2^SMOD*T1溢出率 X=256-11059200/12/32/波特率
TL1 = TH1;//波特率9600bps
TR1 = 1;
ET1 = 0;//只用T1的計數
SCON |= 0x50;//串口方式1 SM0 SM1 SM2 REN TB8 RB8 TI RI 0101 0000
/*
SM0 = 0;
SM1 = 1;//方式1 SM2多機通信位
REN = 1;//允許接收數據
TI = 0;//發送完成中斷標志
RI = 0;//接收完成中斷標志
*/
ES = 1;//開串口中斷
EA = 1;//開總中斷
}
/**
* @brief 串口發送一個字節數據到PC
* @param 待發送數據
* @retval 無
*/
void UartSend(unsigned char dat)
{
SBUF = dat;
//while (!TI);//等待發送完成,在中斷模式下不需要等待,否則進不了中斷
}
/**
* @brief 串口中斷
* @param 無
* @retval 無
*/
void Uart_ISP() interrupt 4 //串口中斷標號是4
{
if (TI) //等待發送完成
{ //發送完成
TI = 0;//清零
}
}
/**
**************************************************************
* @file infrared.c
* @author xr
* @date 2014年3月31日20:51:23
* @version V1.2.3
* @brief 紅外通信--紅外遙控器NEC協議解碼
* @note 單片機STC89C52RC MCU 晶振 11.0592MHZ
**************************************************************
*/
#include <reg52.h>
sbit IRD = P3^3;//紅外接收檢測端口
bit irflag = 0;//接收到數據的標志
unsigned char ircode[4];//存放紅外遙控器發送的用戶碼,用戶碼反碼 鍵碼 鍵碼反碼
/**
* @brief 紅外配置
* @param 無
* @retval 無
*/
void ConfigInfrared()
{
TH0 = 0;
TL0 = 0;//清零T0計數
TMOD &= 0xF0;
TMOD |= 0x01;//T0方式1
TR0 = 0;//在沒有紅外信號之前先關閉T0
ET0 = 0;//只用T0的計數
//外部中斷1
IT1 = 1;//設置外部中斷觸發方式為下降沿觸發
EX1 = 1;//開啟外部中斷1
}
/**
* @brief 獲得IRD紅外檢測引腳的高電平時間(空閑時間)
* @param 無
* @retval 高電平持續的計數值
*/
unsigned int getHeighTime()
{
//在檢測外部信號前,必須先將IRDIO口拉高
IRD = 1;
TH0 = 0;
TL0 = 0;//清零T0計數
TR0 = 1;//開啟T0計數
while (IRD) //持續高電平
{
//超時判斷
if (TH0 > 0x40) //當IRD持續高電平時間17.7ms,遠遠大于引導碼的9ms,是誤碼
{
break;//退出
}
}
TR0 = 0;//停止計數
return (TH0*256 + TL0);//返回高電平計數值
}
/**
* @brief 獲得IRD紅外檢測引腳的低電平時間(載波時間)
* @param 無
* @retval 低電平持續的計數值
*/
unsigned int getLowTime()
{
IRD = 1;//釋放IRD,檢測外部信號
TH0 = 0;
TL0 = 0;//清零T0計數
TR0 = 1;//開始計數
while (!IRD) //持續低電平
{
if (TH0 > 0x40) //超過18ms就是誤碼,錯誤信號
{
break;
}
}
TR0 = 0;//停止計數
return (TH0*256 + TL0);//返回低電平計數值
}
/**
* @brief 外部中斷1服務程序,檢測紅外信號
* @param 無
* @retval 無
*/
void EXINT_ISP() interrupt 2 //外部中斷標號2
{
unsigned char byte;//接收數據
unsigned char i, j;
unsigned int time;//時間
time = getLowTime();//獲得載波時間
if (time < 7833 || time > 8755) //引導碼載波是9ms,這里規定在8.5ms-9.5ms之間是9ms的載波
{
//范圍之外,誤碼
IE1 = 0;//清零外部中斷1中斷標志,為下一次再進入中斷
return;//退出中斷
}
//否則是9ms的載波
time = getHeighTime();//空閑時間
if (time < 3686 || time > 4608) //引導碼的空閑時間4.5ms 這里規定4ms-5ms是4.5ms的空閑
{
IE1 = 0;//清零中斷標志
return;//退出中斷
}
//否則是4.5ms的空閑
//開始接收用戶碼和鍵碼等
for (i = 0; i < 4; i++)
{
for (j = 0; j < 8; j++)
{
time = getLowTime();//載波
if (time < 423 || time > 608) //560us的載波和560us的空閑是0 范圍460us-660us
{
IE1 = 0;
return;
}
//560us載波
time = getHeighTime();
if (time > 423 && time < 608) //560us空閑
{
//bit '0'
byte >>= 1;//低位在前,移入一位0
}
else if (time > 1198 && time < 1658) //1.68ms的空閑是1 范圍 1300us-1800us
{
//bit '1'
byte >>= 1;//移入一位
byte |= 0x80;//移入的一位置1
}
else
{
//誤碼
IE1 = 0;
return;//退出中斷
}
}
ircode = byte;
}
//接收完成
irflag = 1;
//退出中斷時清零中斷標志
IE1 = 0;
}