51单片机学习 您所在的位置:网站首页 红外if耳机能接收红外数字ir广播吗 51单片机学习

51单片机学习

#51单片机学习| 来源: 网络整理| 查看: 265

在这里插入图片描述

需要利用下面这个红外接收头,OUT口会发出红外信号对应的高低电平,由于发送的速度很快,所以需要把OUT引脚接在外部中断引脚上,当OUT一旦产生下降沿,马上进中断,这样响应会更及时。 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述 外部中断引脚位于P3_2和P3_3,我的开发板把OUT接在了P3_2,利用的是下降沿触发。 外部中断比定时器中断和串口中断要简洁一些,这里使用外部中断0(Int0),当IT0=1就是下降沿触发,IT0=0就是低电平触发。 IE0为中断标志位,EX0为此中断的使能,EA为所有中断的使能,PX0设置优先级。 外部中断1(Int1)也是同理。 图中红框框出的才是控制外部中断的。 在这里插入图片描述 首先来配置外部中断:

void Int0_Init(void) { //配置外部中断 IT0 = 1; //选择下降沿触发 IE0 = 0; //中断标志位 EX0 = 1; //外部中断0使能 EA = 1; //中断使能 PX0 = 1; //优先级 } /* @brief 外部中断函数 void Int0_Routine(void) interrupt 0 { } */

在这里插入图片描述

高低电平的组合、持续时长构成了NEC编码:下面的波形就是OUT口会输出的波形。 Data中的反码可以进行数据验证。 在遥控器上按下一个按键之后,先发送一个start波形,然后发送Data,如果按住按键一直不放手,每过110ms就会发送一次repeat,相当于连续按键功能。 在这里插入图片描述 这里遥控器按键的命令码如下: 在这里插入图片描述

接下来编写红外解码的程序,主要的思路是: 建立一个IR.c红外解码模块,这个模块中利用Int0.c和Timer0.c来进行解码。 具体的解码方式: 首先定义一个变量表示当前的状态,用0来表示空闲状态,当收到下降沿时,转为1状态(1状态定义为:分辨是start还是repeat)并将定时器打开,当1状态又收到一个下降沿时,读出定时器的时长判断是start还是repeat。 如果判断为start,转为2状态(2状态定义为:开始解码32bit的Data)2状态会执行32次,数据读完之后回到0状态 如果判断为repeat,则把重发标志位的变量置1并转回0状态

所以首先要对之前写的Timer0模块进行一些改写。这次的目的不是让定时器计数进中断了,而是让它单纯的计时,下面就是改写后的Timer0.c,可以设定计时器的初始值,返回计时器的实时值,以及控制计时器的开关,计时器的返回值每多1就代表多走过了1us

#include void Timer0_Init(void) //1毫秒@11.0592MHz { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x66; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 0; //定时器0不计时 } //把16位值放入计数器 void Timer0_SetCounter(unsigned int Value) { TH0 = Value/256; TL0 = Value%256; } //返回计数器的值 unsigned int Timer0_GetCounter(void) { return (TH0 Timer0_Init(); Int0_Init(); } unsigned char IR_GetDataFlag(void) { if(IR_DataFlag) { IR_DataFlag = 0; return 1; } else return 0; } unsigned char IR_GetRepeatFlag(void) { if(IR_RepeatFlag) { IR_RepeatFlag = 0; return 1; } else return 0; } unsigned char IR_GetAddress(void) { return IR_Address; } unsigned char IR_GetCommand(void) { return IR_Command; } void Int0_Routine(void) interrupt 0 { if(IR_State == 0) //空闲 { Timer0_SetCounter(0); Timer0_Run(1); IR_State = 1; } else if(IR_State == 1) //判断是start/repeat { IR_Time = Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time > 13500-500 && IR_Time //repeat IR_RepeatFlag = 1; Timer0_Run(0); IR_State = 0; } } else if(IR_State == 2) //读取Data { IR_Time = Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time > 1120-500 && IR_Time //对应位为1 IR_Data[IR_pData/8] |= (0x01//Data已收完 IR_pData = 0; //验证数据的正确性 if((IR_Data[0] == ~ IR_Data[1]) && (IR_Data[2] == ~ IR_Data[3])) { IR_Address = IR_Data[0]; IR_Command = IR_Data[2]; IR_DataFlag = 1; } Timer0_Run(0); IR_State = 0; } } }

Command和Address要想在main中调用,就得封装成相应的Get函数,然后对应红外遥控器按键的键码可以用宏定义,IR.h如下:

#ifndef __IR_H__ #define __IR_H__ #define IR_POWER 0x45 #define IR_MODE 0x46 #define IR_MUTE 0x47 #define IR_START_STOP 0x44 #define IR_PREVIOUS 0x40 #define IR_NEXT 0x43 #define IR_EQ 0x07 #define IR_VOL_MINUS 0x15 #define IR_VOL_ADD 0x09 #define IR_0 0x16 #define IR_RPT 0x19 #define IR_USD 0x0D #define IR_1 0x0C #define IR_2 0x18 #define IR_3 0x5E #define IR_4 0x08 #define IR_5 0x1C #define IR_6 0x5A #define IR_7 0x42 #define IR_8 0x52 #define IR_9 0x4A void IR_Init(void); unsigned char IR_GetDataFlag(void); unsigned char IR_GetRepeatFlag(void); unsigned char IR_GetAddress(void); unsigned char IR_GetCommand(void); #endif

最后在main.c中调用这些函数即可,

#include #include "Delay.h" #include "LCD1602.h" #include "IR.h" unsigned char Num; unsigned char Address, Command; void main() { LCD_Init(); LCD_ShowString(1, 1, "ADDR CMD NUM"); LCD_ShowString(2, 1, "00 00 000"); IR_Init(); while(1) { if(IR_GetDataFlag() || IR_GetRepeatFlag()) { Address = IR_GetAddress(); Command = IR_GetCommand(); LCD_ShowHexNum(2, 1, Address, 2); LCD_ShowHexNum(2, 7, Command, 2); if(Command == IR_VOL_MINUS) Num --; if(Command == IR_VOL_ADD) Num ++; LCD_ShowNum(2, 12, Num, 3); } } }

在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有