本帖最后由 hubaba 于 2016-3-28 23:31 编辑
1电路图
1号单片机与红外接收头连接电路如图所示,红外接收头一般都可互换使用。
程序预览: - /****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
- ★★★★★★★★★★★★★★★★★★★★★★★★
- 《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
- 作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
- 仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
- QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
- 验证信息:STC15单片机
- 邮箱:xgliyouquan@126.com
- ★★★★★★★★★★★★★★★★★★★★★★★★*/
- ///************* 功能说明 **************
- //红外接收程序。适用于市场上用量最大的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初始化完毕\r\n"); // 上电后串口发送一条提示信息
- 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键按下标志
- }
- }
- }
复制代码
|