为什么我的红外接收程序在STC15F104E上用遥控按几次就不行了,有时候能按几十次??求大神指导

2019-07-15 16:09发布

为什么我的红外接收程序在STC15F104E上用遥控按几次就不行了,有时候能按几十次??
程序.zip 下载积分: 积分 -1 分
28.75 KB, 下载次数: 50, 下载积分: 积分 -1 分
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
6条回答
无量寿经
1楼-- · 2019-07-15 16:37
《51单片机轻松入门-基于STC15W4K系列》第18章那个红外通信例子很好用,可定义任意引脚进行接收,程序自适应5-35M时钟频率。 最佳答案
elecfans跑堂
2楼-- · 2019-07-15 19:25
请将详细的程序内容复制出来  方便查看回答
DHTDHT
3楼-- · 2019-07-16 00:47
elecfans跑堂 发表于 2015-9-7 14:02
请将详细的程序内容复制出来  方便查看回答

#include<reg51.h>
#include <intrins.h>
sbit LSA  = P3^5;
sbit IRIN = P3^2;
unsigned char DisplayData[8]; //用来存放要显示的8位数的值
unsigned char IrValue[6];          //用来存放读取到的红外值
unsigned char Time;
//--声明全局函数--//
void DigDisplay(); //动态显示函数
void IrInit();
void DelayMs(unsigned int );         
/*******************************************************************************
* 函数名         : DelayMs()
* 函数功能                   : 延时
* 输入           : x
* 输出                  : 无
*******************************************************************************/
void DelayMs(unsigned int x)   //0.14ms误差 0us
{
        unsigned char i;
        while(x--)
        {
                for (i = 0; i<13; i++)
                {}
        }
}
void Delay140us()                //@11.0592MHz
{
  unsigned char i, j;

        i = 2;
        j = 126;
        do
        {
                while (--j);
        } while (--i);
}
/*******************************************************************************
* 函数名         : IrInit()
* 函数功能                   : 初始化红外线接收
* 输入           : 无
* 输出                  : 无
*******************************************************************************/
void IrInit()
{
        IT0=1;//下降沿触发
        EX0=1;//打开中断0允许
        EA=1;        //打开总中断
        IRIN=1;//初始化端口
}
/*******************************************************************************
* 函数名         : ReadIr()
* 函数功能                   : 读取红外数值的中断函数
* 输入           : 无
* 输出                  : 无
*******************************************************************************/
void ReadIr() interrupt 0
{
        unsigned char j,k;
        unsigned int err;
        Time=0;                                         
        DelayMs(70);
        if(IRIN==0)                //确认是否真的接收到正确的信号
        {         
               
                err=1000;                                //1000*10us=10ms,超过说明接收到错误的信号
                /*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
                侯,程序死在这里*/       
                while((IRIN==0)&&(err>0))        //等待前面9ms的低电平过去                 
                {                       
                        Delay140us();
                        err--;
                       
                }
                if(IRIN==1)                        //如果正确等到9ms低电平
                {
                        err=470;
                        while((IRIN==1)&&(err>0))                 //等待4.5ms的起始高电平过去
                        {
                                Delay140us();
                                err--;
                        }
                        for(k=0;k<4;k++)                //共有4组数据
                        {                               
                                for(j=0;j<8;j++)        //接收一组数据
                                {

                                        err=60;               
                                        while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
                                        {
                                                Delay140us();
                                                err--;
                                        }
                                        err=500;
                                        while((IRIN==1)&&(err>0))         //计算高电平的时间长度。
                                        {
                                                Delay140us();//0.14ms
                                                Time++;
                                                err--;
                                                if(Time>30)
                                                {
                                                        EX0=1;
                                                        return;
                                                }
                                        }
                                        IrValue[k]>>=1;         //k表示第几组数据
                                        if(Time>=8)                        //如果高电平出现大于565us,那么是1
                                        {
                                                IrValue[k]|=0x80;
                                        }
                                        Time=0;                //用完时间要重新赋值                                                       
                                }
                        }
                }
                if(IrValue[2]!=~IrValue[3])
                {
                        return;       
                }
        }                       
}

/*******************************************************************************
* 函 数 名         : DigDisplay
* 函数功能                   : 使用数码管显示
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void DigDisplay()
{
switch(IrValue[2])
        {
                 case 0x45:{
                           LSA=0;
                                  
                           }break;
                 case 0x46:{
                           LSA=1;
                                  
                           }break;                    
         default:break;
        }
}
void main()
{
        IrInit();
       
        while(1)
        {
                IrValue[4]=IrValue[2]>>4;                          //高位
                IrValue[5]=IrValue[2]&0x0f;                //低位
                DigDisplay();
        }
}
无量寿经
4楼-- · 2019-07-16 01:31

以下程序来源于《51单片机轻松入门-基于STC15W4K系列》,
使用时重点关注2行代码,其它代码尽量不要修改。
#define MAIN_Fosc                22.1184       
sbit        Ir_Pin = P3^6;                        // 定义红外接收输入端口

///*************        功能说明        **************       
//红外接收程序。适用于市场上用量最大的HT6121/6122及其兼容IC的编码。
//当遥控器用户码与程序定义的用户码不同时,程序会将遥控器的用户码一起从串口输出。
//使用模拟串口发送用户码与键码,波特率9600,接收端要求使用字符格式显示。       
/******************************************/       
#include        "STC15W4K.H"
#define MAIN_Fosc                22.1184        // 定义主时钟, 红外接收会自动适应,5~36MHZ,但模拟串口输出部分不能自动适应。

#define        User_code                0xFD02                // 定义红外接收用户码  
sbit        Ir_Pin = P3^6;                        // 定义红外接收输入端口
sbit        TXD1 = P3^1;                          // 定义模拟串口发送脚
/*************        用户系统配置        **************/
#define TIME                125                              // 选择定时器时间125us, 红外接收要求在60us~250us之间
/*************        以下宏定义用户请勿修改        **************/
#define Timer0_Reload (unsigned int)(65536 - (TIME * MAIN_Fosc /12.0))  // 定时器初值
                                  
/*************        本地变量声明        **************/
unsigned char        IR_SampleCnt;                // 采样次数计数器,通用定时器对红外口检测次数累加记录
unsigned char        IR_BitCnt;                        // 记录位数
unsigned char        IR_UserH;                        // 用户码(地址)高字节
unsigned char        IR_UserL;                        // 用户码(地址)低字节
unsigned char        IR_data;                        // 键原码
unsigned char        IR_DataShit;                // 键反码
unsigned char        IR_code;                        // 红外键码                
bit                Ir_Pin_temp;                        // 记录红外引脚电平的临时变量
bit                IR_Sync;                                // 同步标志(1——已收到同步信号,0——没收到)
bit                IrUserErr;                            // 用户码错误标志
bit                IR_OK;                        // 完成一帧红外数据接收的标志(0,未收到,1,收到一帧完整数据)

/******************** 红外采样时间宏定义, 用户不要随意修改        *******************/
//数据格式: Synchro,AddressH,AddressL,data,/data, (total 32 bit).
#if ((TIME <= 250) && (TIME >= 60))                        // TIME决定测量误差,TIME太大防错能力降低,TIME太小会干扰其它中断函数执行。
        #define        IR_sample                        TIME                // 定义采样时间,在60us~250us之间,
#endif

#define IR_SYNC_MAX                (15000/IR_sample)        // 同步信号SYNC 最大时间 15ms(标准值9+4.5=13.5ms)
#define IR_SYNC_MIN                (9700 /IR_sample)        // 同步信号SYNC 最小时间 9.5ms,(连发信号标准值9+2.25=11.25ms)
#define IR_SYNC_DIVIDE        (12375/IR_sample)        // 区分13.5ms同步信号与11.25ms连发信号,11.25+(13.5-11.25)/2=12.375ms
#define IR_DATA_MAX                (3000 /IR_sample)        // 数据最大时间3ms    (标准值2.25 ms)
#define IR_DATA_MIN                (600  /IR_sample)        // 数据最小时,0.6ms   (标准值1.12 ms)
#define IR_DATA_DIVIDE        (1687 /IR_sample)        // 区分数据 0与1,1.12+ (2.25-1.12)/2 =1.685ms
#define IR_BIT_NUMBER                32                                // 32位数据

//****************************  红外接收模块  ********************************************
// 信号第1个下降沿时刻清零计数器并让计数器从0开始计数,第2个下降沿时刻计算计数器运行时间
// 因此检测的是每个信号从低电平开始到高电平结束这段时间,也就是脉冲周期。
void IR_RX_HT6121(void)
{
        unsigned char        SampleTime;                                // 信号周期
        IR_SampleCnt++;                                                        // 定时器对红外口检测次数

        F0 = Ir_Pin_temp;                                                // 保存前一次此程序扫描到的红外端口电平          
        Ir_Pin_temp = Ir_Pin;                                        // 读取当前红外接收输入端口电平
        if(F0 && !Ir_Pin_temp)                                        // 前一次采样高电平并且当前采样低电平,说明出现了下降沿
        {
                SampleTime = IR_SampleCnt;                        // 脉冲周期
                IR_SampleCnt = 0;                                        // 出现了下降沿则清零计数器
                //******************* 接收同步信号 **********************************
                if(SampleTime > IR_SYNC_MAX)                IR_Sync = 0;        // 超出最大同步时间, 错误信息。
                else if(SampleTime >= IR_SYNC_MIN)                // SYNC
                {
                        if(SampleTime >= IR_SYNC_DIVIDE)    // 区分13.5ms同步信号与11.25ms连发信号
                        {
                                IR_Sync = 1;                                    // 收到同步信号 SYNC
                                IR_BitCnt = IR_BIT_NUMBER;          // 赋值32(32位有用信号)
                        }
                }
                //********************************************************************
                else if(IR_Sync)                                                // 已收到同步信号 SYNC
                {
                        if((SampleTime < IR_DATA_MIN)|(SampleTime > IR_DATA_MAX)) IR_Sync=0;        // 数据周期过短或过长,错误
                        else
                        {
                                IR_DataShit >>= 1;                                        // 键反码右移1位(发送端是低位在前,高位在后的格式)
                                if(SampleTime >= IR_DATA_DIVIDE)        IR_DataShit |= 0x80;        // 区别是数据 0还是1

                                //***********************  32位数据接收完毕 ****************************************
                                if(--IR_BitCnt == 0)                                 
                                {
                                        IR_Sync = 0;                                        // 清除同步信号标志
                                        if(~IR_DataShit == IR_data)                // 判断数据正反码
                                        {
                                                if((IR_UserH == (User_code / 256)) && IR_UserL == (User_code % 256))
                                                {
                                                                IrUserErr = 0;            // 用户码正确
                                                }
                                                else        IrUserErr = 1;            // 用户码错误
                                                       
                                                IR_code      = IR_data;                // 键码值
                                                IR_OK   = 1;                            // 数据有效
                                        }
                                }
                                // 格式:  用户码L —— 用户码H —— 键码 —— 键反码
                                // 功能:  将 “用户码L —— 用户码H —— 键码”通过3次接收交换后存入对应字节,
                                //         这样写代码可以节省内存RAM占用,但是不如用数组保存好理解。        
                                //         键反码前面部分代码已保存好了        :IR_DataShit |= 0x80;                  
                                //**************************** 将接收的************************************************
                                else if((IR_BitCnt & 7)== 0)                // 1个字节接收完成
                                {
                                        IR_UserL = IR_UserH;                        // 保存用户码高字节
                                        IR_UserH = IR_data;                                // 保存用户码低字节
                                        IR_data  = IR_DataShit;                        // 保存当前红外字节
                                }
                        }
                }  
        }
}

/**************** Timer0初始化函数 ******************************/
void InitTimer0(void)
{
        TMOD = 0x01;                         // 16位计数方式.
        TH0 = Timer0_Reload / 256;         
        TL0 = Timer0_Reload % 256;
        ET0 = 1;                                         
        TR0 = 1;
        EA  = 1;
}  

/********************** Timer0中断函数************************/
void timer0 (void) interrupt 1
{
        IR_RX_HT6121();
        TH0 = Timer0_Reload / 256;           // 重装定时器初值   
        TL0 = Timer0_Reload % 256;           // 重装定时器初值   
}

/********************** 模拟串口相关函数************************/
void delay104us(void)
{
   unsigned char i,j,k;
   for(i=1;i>0;i--)       // 注意后面没分号
   for(j=3;j>0;j--)       // 注意后面没分号
   for(k=189;k>0;k--);    // 注意后面有分号        101
}

//模拟串口发送
void Tx1Send(unsigned char dat)                //9600,N,8,1                发送一个字节
{
        unsigned char        i;
        EA = 0;
        TXD1 = 0;
        delay104us();
        for(i=0; i<8; i++)
        {
                if(dat & 1)                TXD1 = 1;
                else                        TXD1 = 0;
                dat >>= 1;
                delay104us();
        }
        TXD1 = 1;
        EA = 1;
        delay104us();
        delay104us();
}

void PrintString(unsigned char code *puts)                    // 发送一串字符串
{
    for (; *puts != 0;        puts++)  Tx1Send(*puts);         // 遇到停止符0结束
}

/********************* 十六进制转ASCII函数 *************************/
unsigned char        HEX2ASCII(unsigned char dat)
{
        dat &= 0x0f;
        if(dat <= 9)        return (dat + '0');        //数字0~9
        return (dat - 10 + 'A');                        //字母A~F
}

/********************* 主函数 *************************/
void main(void)
{
        InitTimer0();                                    // 初始化Timer0       
        PrintString("定时器0初始化完毕 ");        // 上电后串口发送一条提示信息

        while(1)
        {
                if(IR_OK)                                     // 接收到一帧完整的红外数据
                {
                        PrintString("红外键码: 0x");                // 提示红外键码
                        Tx1Send(HEX2ASCII(IR_code >> 4));        // 键码高半字节
                        Tx1Send(HEX2ASCII(IR_code));                // 键码低半字节
                        if(IrUserErr)                                                // 用户码错误,则发送用户码
                        {
                                Tx1Send(' ');                                        // 发空格
                                Tx1Send(' ');                                        // 发空格
                                PrintString("用户码: 0x");                // 提示用户码
                                Tx1Send(HEX2ASCII(IR_UserH >> 4));        // 用户码高字节的高半字节
                                Tx1Send(HEX2ASCII(IR_UserH));                // 用户码高字节的低半字节
                                Tx1Send(HEX2ASCII(IR_UserL >> 4));        // 用户码低字节的高半字节
                                Tx1Send(HEX2ASCII(IR_UserL));                // 用户码低字节的低半字节
                        }
                        Tx1Send(0x0d);                          // 发回车
                        Tx1Send(0x0a);                          // 发回车
                        IR_OK = 0;                              // 清除IR键按下标志
                }
        }
}

无量寿经
5楼-- · 2019-07-16 03:58
 精彩回答 2  元偷偷看……
toothpick001
6楼-- · 2019-07-16 07:22
谢谢 分享

一周热门 更多>