专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
51单片机
红外遥控解码有时会出错,怎么回事?
2019-07-15 17:46
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
51单片机
9655
9
1416
大神们帮忙看下 我写的红外遥控解码程序 很不稳定怎么办。遥控器的客户码是00FF。可是解码显示出来有时就不是了 ,还有有时按键的解码也会出错 ,多按几次就恢复正常了,很不稳定 是不是程序有问题,还是硬件问题啊?????
红外遥控器解码.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所示。
加载中...
查看其它9个回答
一周热门
更多
>
相关问题
【东软载波ESF0654 PDS开发板活动】开箱
1 个回答
东软载波ESF0654 PDS开发板外部中断
1 个回答
东软载波ESF0654 PDS开发板高级控制定时器AD16C4T
1 个回答
用串口调试助手为什么只能在hex模式接收发送而在文本模式不行
9 个回答
触摸芯片SC02B/SC04B在地砖灯的设计方案
1 个回答
相关文章
51单片机与蓝牙模块连接
0个评论
51单片机的硬件结构
0个评论
基于51单片机的无线遥控器制作
0个评论
51单片机 AD转换
0个评论
51单片机数码管递增显示
0个评论
如何实现对单片机寄存器的访问
0个评论
基于51单片机的指纹密码锁
0个评论
×
关闭
采纳回答
向帮助了您的知道网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
51单片机
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
×
付费偷看金额在0.1-10元之间
确定
×
关闭
您已邀请
0
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
一周热门 更多>