完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
《51单片机轻松入门-基于STC15W4K系列》第18章那个红外通信例子很好用,可定义任意引脚进行接收,程序自适应5-35M时钟频率。
最佳答案
|
|
|
|
请将详细的程序内容复制出来 方便查看回答
|
|
|
|
#include #include ***it LSA = P3^5; ***it 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(); } } |
|
|
|
以下程序来源于《51单片机轻松入门-基于STC15W4K系列》, 使用时重点关注2行代码,其它代码尽量不要修改。 #define MAIN_Fosc 22.1184 ***it Ir_Pin = P3^6; // 定义红外接收输入端口 ///************* 功能说明 ************** //红外接收程序。适用于市场上用量最大的HT6121/6122及其兼容IC的编码。 //当遥控器用户码与程序定义的用户码不同时,程序会将遥控器的用户码一起从串口输出。 //使用模拟串口发送用户码与键码,波特率9600,接收端要求使用字符格式显示。 /******************************************/ #include "STC15W4K.H" #define MAIN_Fosc 22.1184 // 定义主时钟, 红外接收会自动适应,5~36MHZ,但模拟串口输出部分不能自动适应。 #define User_code 0xFD02 // 定义红外接收用户码 ***it Ir_Pin = P3^6; // 定义红外接收输入端口 ***it 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初始化完毕rn"); // 上电后串口发送一条提示信息 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键按下标志 } } } |
|
|
|
|
|
|
|
谢谢 分享
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
690 浏览 0 评论
735 浏览 1 评论
基于瑞萨FPB-RA4E2智能床头灯项目——1编译环境搭建与点亮驱动ws2812全彩LED
624 浏览 0 评论
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-LCD显示图片编程示例之介绍mmap
1099 浏览 0 评论
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
1092 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11793 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 05:05 , Processed in 0.721727 second(s), Total 86, Slave 66 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号