(加三个链接,其余完成)
一、红外遥控简介
•红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出
•通信方式:单工,异步
•红外LED波长:940nm(人眼看不见)
•通信协议标准:NEC标准
二、硬件电路
红外发送部分
上左图,两个输入端,一个接38KHZ的方波,另一个直接接输入信号,两个NPN型的三极管,低电平导通。IN高电平,LED不亮,IN低电平时,LED是以38KHZ的频率闪着亮,目的是为了抗干扰
上右图,简化版,通过程序控制在IN口输入左下角的波形
红外接收部分
这是一体化的红外接收头的电路,其OUT口可以直接输出高低电平,在其内部会将38KHZ的波形给滤掉。在实际使用中,将OUT连接到外部中断,因为红外接收处理波形对实时性要求比较高(高低电平的宽度较短,只有几百微妙)。上右图是开发板上的红外接收部分的原理图
三、基本发送与接收
•空闲状态:红外LED不亮,接收头输出高电平(接收头没有接收到任何信号)
•发送低电平:红外LED以38KHz频率闪烁发光,接收头输出低电平(将38KHZ的波形过滤掉)
•发送高电平:红外LED不亮,接收头输出高电平
四、NEC编码
NEC编码解决的问题就是怎么去表示数据
注:该波形是接收端OUT端口的波形
按键按下时,输出Start信号,该信号是由9ms的低电平和4.5ms的高电平组成
之后是数据区,共32位,格式如上图(反码的目的是进行数据的校验)
这里的数据表示方式和传统的低电平表示0高电平表示1不同,根据上图,低电平560us高电平560us时表示0,低电平560us高电平1690us时表示1
Repeat是支持按键长按的功能,每隔110ms就会发送这样的波形(如果一直按着按键不松手的话)
实际波形图如下:
以按下KEY2为例,首先是Start波形,之后是8位的地址码0000 0000,接着是地址码的反码1111 1111,之后是指令码0110 0010,最后是指令码的反码1001 1101。指令码0110 0010为0x46,与KEY2键码对应。
遥控器键码如下:
五、51单片机的外部中断
具体可见中断章节:江科大51单片机学习笔记之定时器与中断系统_rebened小橙的博客-优快云博客
•STC89C52有4个外部中断
•STC89C52的外部中断有两种触发方式: 下降沿触发和低电平触发(不支持上升沿触发和高电平触发)
封装图
本单片机只使用了两个外部中断,本开发板使用了外部中断0(连接到了P32引脚)
外部中断寄存器:
以INT0为例,触发方式有IT0决定(IT0为1时是下降沿触发,IT0为0时是低电平触发),IE0是中断标志位,当其为1时表示触发了该中断,EX0是中断使能,EA也是中断使能(所有中断),PX0是配置中断优先级的,配置完后便课触发中断。
六、实验1
现象:LCD屏幕显示遥控器的地址吗、按键的命令码以及自定义的变量Num。按下遥控器上的按键,LCD上显示的值也会随之发生改变。按VOL+键Num值会加,按VOL-键Num值会减,且支持长按。
1、创建文件
思路:创建文件IR.c和Int0.c及其头文件。IR.c用于存放红外解码相关程序,Int0.c用于存放外部中断0的相关程序
波形时间宽度的计算:使用定时器0来计算波形高电平或低电平的宽度。本来定时器0中的计数器达到设定值时会触发中断,现在定时器0只当做计数器,不触发中断,通过计数器来计算电平宽度。例如,在下降沿时开启计数器,在上升沿时记录计数器的值,二者的差值除以频率就是这段低电平的时间长度。通过计算高低电平的宽度来判断这个信号是Start信号、0信号、1信号还是Repeat信号
(先将相关文件先添加至项目中)
2、外部中断初始化
编写Int0.c文件以及头文件
/**
* @brief 外部中断0初始化
* @param 无
* @retval 无
*/
void Int0_Init(void)
{
IT0 = 1;//下降沿触发
IE0 = 0;//中断标志位清零,也可以不设置
//中断打开
EX0 = 1;
EA = 1;
PX0 = 1;//高优先级
}
3、修改定时器函数
参考之前的中断章节
修改Timer.h和Timer.c
不需要定时器0来触发中断,故将中断部分直接注释掉,并且TR0先置为0,之后再手动开启计数
#include <REGX52.H>
/**
* @brief 定时器0初始化
* @param 无
* @retval 无
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时,先不启动
/*
//中断
ET0 = 1;//使能T0中断
EA = 1;
PT0 = 0;//设置中断优先级,为低优先级
*/
}
/**
* @brief 定时器0设置计数器值
* @param Value,要设置的计数器值,范围:0~65535
* @retval 无
*/
void Timer0_SetCounter(unsigned int Value)
{
TH0=Value/256;//取高8位
TL0=Value%256;//取低8位
}
/**
* @brief 定时器0获取计数器值
* @param 无
* @retval 计数器值,范围:0~65535
*/
unsigned int Timer0_GetCounter(void)
{
return (TH0<<8)|TL0;//将两个寄存器的值赋值到一个16位的变量上
}
/**
* @brief 定时器0启动停止控制
* @param Flag 启动停止标志,1为启动,0为停止
* @retval 无
*/
void Timer0_Run(unsigned char Flag)
{
TR0=Flag;
}
/*
//定时器0的中断处理函数
void Timer0_Routine() interrupt 1
{
static unsigned int count = 0;
//重新赋值计数器,因为计数器溢出后会变为0,要1ms产生一次中断,需要重新给计数器赋值为64535
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
//1ms产生一次中断,每次中断count+1,1000次后再进行处理,此时处理的时间间隔就为1s
count++;
if(count >= 1000)
{
count = 0;
P2_0 = ~P2_0;
}
}
*/
4、测试
测试定时器0的计数功能是否正常
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer.h"
unsigned int Time;
void main()
{
LCD_Init();
Timer0Init();
Timer0_SetCounter(0);
Timer0_Run(1);
Delayms(10);
Time=Timer0_GetCounter();
LCD_ShowNum(

本文围绕51单片机红外遥控展开,介绍了红外遥控的原理、硬件电路、NEC编码等知识,还阐述了51单片机的外部中断。通过两个实验,分别实现了LCD显示遥控器信息和用遥控器控制电机转速,详细说明了实验步骤,包括创建文件、初始化、测试等内容。
最低0.47元/天 解锁文章
1万+





