专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

红外通信—红外遥控器NEC解码程序

作者:寒竹子   来源:本站原创   点击数:  更新时间:2014年03月31日   【字体:

本程序所用的原理图下载: 点这里 ,单片机芯片使用的stc89c52;找到要用的部分的的原理图即可.这是一整个单片机开发板的电路图其他的忽略.

/**
  ***********************************************************************************************
  * @file       main.c
  * @author     xr
  * @date       2014年3月31日10:26:47
  * @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];//接收解码得到的数据

unsigned char code LedTable[] = { 
0xC0,  //"0"
                0xF9,  //"1"
                0xA4,  //"2"
                0xB0,  //"3"
                0x99,  //"4"
                0x92,  //"5"
                0x82,  //"6"
                0xF8,  //"7"
                0x80,  //"8"
                0x90,  //"9"
                0x88,  //"A"
                0x83,  //"B"
                0xC6,  //"C"
                0xA1,  //"D"
                0x86,  //"E"
                0x8E   //"F"
};

unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//数码管显示缓冲区

unsigned char thr0, tlr0;

void ConfigTimer0(unsigned int xms);
void ConfigTimer1();

void main()
{
ConfigTimer0(1); //定时1ms
ConfigTimer1();

while (1)
{
if (irflag)//接收到红外数据,则刷新显示
{
LedBuff[5] = LedTable[ircode[0] >> 4];//取用户码的高4位字节
LedBuff[4] = LedTable[ircode[0] & 0x0F];//取用户码的低四位字节
LedBuff[1] = LedTable[ircode[2] >> 4];//取键码的高四位
LedBuff[0] = LedTable[ircode[2] & 0x0F];//取键码的低四位
}
}
}

/**
  * @brief    定时器T0配置
  * @param    定时时间xms
  * @retval   无
  */
void ConfigTimer0(unsigned int xms)
{
unsigned int tmp;
tmp = 65536-xms*11059200/12/1000;
thr0 = (unsigned char)(tmp >> 8);
tlr0 = (unsigned char)(tmp & 0x00FF);
TMOD &= 0xF0;
TMOD |= 0x01;//T0方式1
TH0 = thr0;
TL0 = tlr0;
TR0 = 1;
EA  = 1;
ET0 = 1;
//设置定时器T0的中断优先级高于外部中断的优先级
//IP中断优先级寄存器 PT2 PS PT1 PX1 PT0 PX0
PT0 = 1;//提高T0的优先级,优先进行数码管刷新,消除数码管显示抖动
}

/**
  * @brief    数码管刷新
  * @param    无
  * @retval   无
  */
void refresh()
{
static unsigned char j = 0;

P0 = 0xFF;//消隐
P1 = (0x08 | j);//000 0 1 ADDR2 ADDR1 ADDR0
P0 = LedBuff[j++];
if (j >= 6)
j = 0;
}

/**
  * @brief    T0中断服务
  * @param    无
  * @retval   无
  */
void Timer0_ISP() interrupt 1
{
TH0 = thr0;
TL0 = tlr0;
refresh();//数码管刷新
}

/**********************红外解码*************************************/

/**
  * @brief    配置定时器T1,开启外部中断,T1用来计数
  * @param    无
  * @retval   无
  */
void ConfigTimer1()
{
TMOD &= 0x0F;//清零T1控制位
TMOD |= 0x10;//T1方式1
TH1 = 0;
TL1 = 0;//初始化计数值为0
TR1 = 0;//在没有进入外部中断前,先关闭定时器T1
ET1 = 0;//关闭T1中断,只用来计数
IT1 = 1;//设置外部中断为下降沿触发中断
EX1 = 1;//开启外部中断
}

/**
  * @brief    获得高电平时间(空闲时间)
  * @param    无
  * @retval   无
  */
unsigned int getHeighTime()
{
//在检测外部电平之前,先将红外检测引脚拉高释放
IRD = 1;

TH1 = 0;
TL1 = 0;//重新清零
TR1 = 1;//打开定时器T1开始计数
while (IRD)
{
//进行超时判断,若高电平时间大于9ms,即引导码时间,则直接退出
if (TH1 > 0x40) //(0x40*256) * (12/11059200) s = 17.7ms
{
break;//退出
}
}
TR1 = 0;//关闭计数

return (TH1*256 + TL1);//返回IRD引脚持续的高电平时T1计数值
}

/**
  * @brief    获取低电平时间(载波)
  * @param    无
  * @retval   无
  */
unsigned int getLowTime()
{
//释放IRD检测引脚
IRD = 1;
TH1 = 0;
TL1 = 0;//清零T1计数值
TR1 = 1;//启动T1计数
while (!IRD)
{
if (TH1 > 0x40) //TL1计数满则进位TH1,时间:TH1*256*12/11059200 s = 17.7ms
{ //时间大于了NEC协议的引导码载波时间9ms,进行强制退出,避免假等待
break;
}
}
TR1 = 0;//关闭计数

return (TH1*256 + TL1);//返回低电平持续的计数值 每计数一次是一个机器周期的时间即1.08us
}

/**
  * @brief    外部中断服务,检测红外信号
  * @param    无
  * @retval   无
  */
void ExINT_ISP() interrupt 2 //外部中断1中断标号为2
{
unsigned int time;//时间
unsigned char i, j;
unsigned char byte = 0;

time = getLowTime();//获取低电平T1计数值,即引导码的9ms载波
if ((time < 7833) || (time > 8755)) //范围8.5-9.5ms X=0.0085/(12/11059200)
{
//错误引导码
IE1 = 0;//清零外部中断标志
return;//退出中断
}
//符合引导码的9ms
time = getHeighTime();//获取高电平时间
if ((time < 3686) || (time > 4608)) //范围4ms-5ms
{
//不是4.5ms的空闲
IE1 = 0;//清零外部中断
return;//退出中断
}
//是正确的引导码
for (i = 0; i < 4; i++) //循环接收用户码 用户反码 键数值码 键数值反码
{
for (j = 0; j < 8; j++) //接收八位
{
//560us的载波(低电平)+560us的空闲(高电平) = 0 560us的载波(低电平)+1.68ms的空闲(高电平) = 1
time = getLowTime();//载波时间
if ((time < 322) || (time > 645)) //范围350us-700us
{
IE1 = 0;//清零外部中断标志
return;//退出中断
}
time = getHeighTime();//空闲时间
if ((time > 322) && (time < 645)) //560us的空闲
{
//bit 0
byte >>= 1;//地位在前,先接收低位
}
else if ((time > 1198) && (time < 1658)) //1300us-1800us 1.68ms的空闲
{
//bit 1
byte >>= 1;
byte |= 0x80;//高位置1
}
else
{
//无效码
IE1 = 0;
return;
}
}
ircode = byte;//接收数据
}
//全部接收完毕
irflag = 1;
IE1 = 0;//清零外部中断标志位
}

关闭窗口

相关文章