红外遥控解码有时会出错,怎么回事?

2019-07-15 17:46发布

大神们帮忙看下 我写的红外遥控解码程序 很不稳定怎么办。遥控器的客户码是00FF。可是解码显示出来有时就不是了 ,还有有时按键的解码也会出错 ,多按几次就恢复正常了,很不稳定 是不是程序有问题,还是硬件问题啊?????
IMG_20150304_181221.jpg
IMG_20150304_181240.jpg
红外遥控器解码.png
红外遥控器解码.zip 下载积分: 积分 -1 分
145.59 KB, 下载次数: 43, 下载积分: 积分 -1 分
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
9条回答
无量寿经
2019-07-16 09:18
从入门到精通STC8051单片机核心技术》节选。QQ群:324284310,QQ:347305156    验证:STC单片机、STM32等,不能为空。例18.4  红外接收数据,使用一个定时器模拟外中断方式,并通过串口发送接收到的用户码与键码,晶振:22.1184MHz,波特率9600, 要求串口助手按字符格式显示。程序思路:设置定时器125uS(允许范围:60us~250us)定时检测一次红外输入口电平,若某一次采样值为高电平并且紧接着的一次采样值为低电平,说明出现了下降沿,清零一个计数器变量IR_SampleCnt,退出程序继续125uS的定时检测,并且不断的对检测次数进行累加,累加值放到变量IR_SampleCnt中,在下一次出现下降沿时,变量IR_SampleCnt中的值就代表了2次下降沿之间的脉冲周期(IR_SampleCnt×125uS),根据每一次的脉冲周期即可识别出同步信号与32位数据。程序优点:通用性极强,可使用任意IO口接收红外数据,红外接收部分自适应晶振频率5~36M,模拟串口输出部分需要根据晶振频率调整延时函数参数,此程序移植时只需更改红外接收引脚定义与模拟串口发送引脚即可。程序缺点:程序复杂。但通用性强,只占用一个定时器,移植非常简单,建议优先选用。程序代码如下。///*************    功能说明    **************  //当遥控器用户码与程序定义的用户码不同时,程序会将遥控器的用户码一起从串口输出。/******************************************/    #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,收到一帧完整数据)#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){  // 由第一章介绍的软件计算得出    }//模拟串口发送void Tx1Send(unsigned char dat)     //9600,N,8,1     发送一个字节{  //……   }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键按下标志        }    }}程序运行效果如图18-11所示。


未命名.JPG

一周热门 更多>