目录
- 一、红外遥控简介
- 二、硬件电路
- 三、基本发送与接收
- 四、NEC码
- 五、代码演示
- 5.1 红外遥控
- 5.2 红外遥控电机调速
- 注意:一定要看
一、红外遥控简介
红外发射装置 也就是通常我们说的红外遥控器是由键盘电路、红外编码电路、电源电路和红外发射电路组成。红外发射电路的主要元件为红外发光二极管。 它实际上是一只特殊的发光二极管;由于其内部材料不同于普通发光二极管,因 而在其两端施加一定电压时,它便发出的是红外线而不是可见光。目前大量的使用的红外发光二极管发出的红外线波长为940nm左右,外形与普通发光二极管相同。红外发光二极管有透明的,还有不透明的,在我们的红外遥控器上可以看到这个红外发光二极管。
红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出
通信方式:单工,异步
红外LED波长:940nm
通信协议标准:NEC标准
二、硬件电路
IN引脚是我们要发送波形信息的引脚,38KHZ是调制的信号加载到IN的波形上的。采用两个PNP三极管的串联,使当两个三级管的基极同时为低电平时LED才亮。
亮灭变化:当IN为高电平时,LED不发光,当IN为低电平时,LED按照38KHZ的频率,当为低电平时发光,高电平时不发光。
加上38KHZ的调制波形是为了与自然光区别,当红外光接收器接收信号时会通过滤波电路把38KHZ的波形滤掉,保留信息发送引脚发送的波形信号。
使用一个IN引脚模拟上面所讲的时序也行
接收装置:为了保证红外光接收装置接收信息的准确性,不使用IF语句,使用响应更为快送的外部中断处理。
三、基本发送与接收
空闲状态:红外LED不亮,接收头输出高电平
发送低电平:红外LED以38KHz频率闪烁发光,接收头输出低电平
发送高电平:红外LED不亮,接收头输出高电平
四、NEC码
NEC码的位定义:一个脉冲对应560us的连续载波,一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平),一个逻辑0的传输需要1.125ms(560us脉冲+560us低电平)。而红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑1应该是560us低 +1680us高,逻辑0应该是560us低+560us高。所以可以通过计算高电平时间判断接收到的数据是0还是1。
NEC遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码。引导码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反 码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
NEC码还规定了连发码(由9ms低电平+2.5m高电平+0.56ms低电平+97.94ms高电平组成),如果在一帧数据发送完毕之后,红外遥控器按键仍然没有放开,则发射连发码,可以通过统计连发码的次数来标记按键按下的长短或次数。
五、代码演示
5.1 红外遥控
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"
unsigned char Num;
unsigned char Address;
unsigned char Command;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"A");
IR_Init();
while(1)
{
if(IR_GetDataFlag() || IR_GetRepeatFlag())
{
Address=IR_GetAddress();
Command=IR_GetCommand();
LCD_ShowHexNum(2,1,Address,2);
LCD_ShowHexNum(2,5,Command,2);
if(Command==0x15)
{
Num--;
}
if(Command==0x09)
{
Num++;
}
LCD_ShowNum(2,10,Num,3);
}
}
}
Timer0.c
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
}
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;
TL0=Value%256;
}
unsigned int Timer0_GetCounter(void)
{
return(TH0<<8)|TL0;
}
void Timer0_Run(unsigned char Flag)
{
TR0=Flag;
}
IR.c
#include "Timer0.h"
#include "Int0.h"
unsigned int IR_Time;
unsigned char IR_State;
unsigned char IR_Data[4];
unsigned char IR_pData;
unsigned char IR_DataFlag;
unsigned char IR_RepeatFlag;
unsigned char IR_Address;
unsigned char IR_Command;
void IR_Init(void)
{
Timer0_Init();
Int0_Init();
}
unsigned char IR_GetDataFlag(void)
{
if(IR_DataFlag)
{
IR_DataFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetRepeatFlag(void)
{
if(IR_RepeatFlag)
{
IR_RepeatFlag=0;
return 1;
}
return 0;
}
unsigned char IR_GetAddress(void)
{
return IR_GetAddress;
}
unsigned char IR_GetCommand(void)
{
return IR_GetCommand;
}
void Int0_Routine(void) interrupt 0
{
if(IR_State==0)
{
Timer0_SetCounter(0);
Timer0_Run(1);
IR_State=1;
}
else if(IR_State==1)
{
IR_Time=Timer0_GetCounter();
Timer0_SetCounter(0);
if(IR_Time>13500-500&&IR_Time<13500+500)
{
IR_State=2;
}
else if(IR_Time>11250-500&&IR_Time<11250+500)
{
IR_RepeatFlag=1;
Timer0_Run(0);
IR_State=0;
}
else
{
IR_State=1;
}
}
else if(IR_State==2)
{
IR_Time=Timer0_GetCounter();
Timer0_SetCounter(0);
if(IR_Time>1120-500&&IR_Time<1120+500)
{
IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));
IR_pData++;
}
else if(IR_Time>2250-500&&IR_Time<2250+500)
{
IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));
IR_pData++;
}
else
{
IR_pData=0;
IR_State=1;
}
if(IR_pData>=32)
{
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;
}
}
}
Int0.c
#include <REGX52.H>
void Int0_Init(void)
{
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
}
//void Int0_Routine(void) interrupt 0
//{
//
//}
Int0.h
#ifndef __INT0_H__
#define __INT0_H__
void Int0_Init(void);
#endif
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);
#endif
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_GetAdress(void);
unsigned char IR_GetCommand(void);
#endif
5.2 红外遥控电机调速
程序在上一篇的MCU-51:单片机直流电机驱动(PWM)基础上进行修改
main.c
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Motor.h"
#include "IR.h"
unsigned char Command,Speed;
void main()
{
Motor_Init();
IR_Init();
while(1)
{
if(IR_GetDataFlag()) //如果收到数据帧
{
Command=IR_GetCommand(); //获取遥控器命令码
if(Command==IR_0){Speed=0;} //根据遥控器命令码设置速度
if(Command==IR_1){Speed=1;}
if(Command==IR_2){Speed=2;}
if(Command==IR_3){Speed=3;}
if(Speed==0){Motor_SetSpeed(0);} //速度输出
if(Speed==1){Motor_SetSpeed(50);}
if(Speed==2){Motor_SetSpeed(75);}
if(Speed==3){Motor_SetSpeed(100);}
}
Nixie(1,Speed); //数码管显示速度
}
}
Timer1.c
#include <REGX52.H>
/**
* @brief 定时器1初始化,100us@12.000MHz
* @param 无
* @retval 无
*/
void Timer1_Init(void)
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x9C; //设置定时初值
TH1 = 0xFF; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
PT1=0;
}
/*定时器中断函数模板
void Timer1_Routine() interrupt 3
{
static unsigned int T1Count;
TL1 = 0x9C; //设置定时初值
TH1 = 0xFF; //设置定时初值
T1Count++;
if(T1Count>=1000)
{
T1Count=0;
}
}
*/
Motor.c
#include <REGX52.H>
#include "Timer1.h"
//引脚定义
sbit Motor=P1^0;
unsigned char Counter,Compare;
/**
* @brief 电机初始化
* @param 无
* @retval 无
*/
void Motor_Init(void)
{
Timer1_Init();
}
/**
* @brief 电机设置速度
* @param Speed 要设置的速度,范围0~100
* @retval 无
*/
void Motor_SetSpeed(unsigned char Speed)
{
Compare=Speed;
}
//定时器1中断函数
void Timer1_Routine() interrupt 3
{
TL1 = 0x9C; //设置定时初值
TH1 = 0xFF; //设置定时初值
Counter++;
Counter%=100; //计数值变化范围限制在0~99
if(Counter<Compare) //计数值小于比较值
{
Motor=1; //输出1
}
else //计数值大于比较值
{
Motor=0; //输出0
}
}
Timer1.h
#ifndef __TIMER1_H__
#define __TIMER1_H__
void Timer1_Init(void);
#endif
Motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__
void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);
#endif
注意:一定要看
千万不要直接复制代码,因为是模块化编写,模块的代码没有往上复制(模块的代码在以往的文章中可以找到),大家一定要自己动手,跟着视频学!!!!!