51单片机学习笔记_14 红外遥控
红外传感器
遥控器通过红外 LED 发送调制后的信号,开发板上的红外接收模块接收遥控器的红外线。
单工异步,940nm 波长(还有一种 250nm 的N,可见光),EC 通信标准。
38KHz:红外线频率。
IN:发送的方波。
红外接收模块中会自动帮我们滤出 In 部分。
空闲状态:OUT 输出高电平。
发送高电平:OUT 输出高电平。
发送低电平:OUT输出低电平,代表有数据。
38kHz 属于是底层信息,所以协议层不给予展示,类似类的封装。
9ms 低+4.5ms 高:start。
后面跟四个字节数据。反码用于数据验证。
560us 低+560us 高表示0,560us 低+1690us 高表示1. 结束的最后一个高电平后面要跟一个下降沿表示终止。
一直扫描是效率很低的做法,所以 out 是接在外部中断上的。
外部中断
void main(){
LCD_Init();
LCD_ShowString(1,1,"A");
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
while(1){
LCD_ShowNum(2,1,num,2);
}
}
void Int0_Routine() interrupt 0 {
num++;
}
中断和第三个按键 P3^2 接在一起,因此按下按键3时就会下降沿触发中断。
如果改为低电平触发,即 IT0=0,按下按键就一直触发。
接收到的数据会以2位的二进制位展现在数码管上,这里遥控器上的按钮并不是按几数码管就会显示几的注意一下。重点只是在于看遥控器不同的信号单片机能否区分和识别。
//ired.h
#ifndef _ired_H
#define _ired_H
#include "public.h"
//管脚定义
sbit IRED=P3^2;
//声明变量
extern u8 gired_data[4];
//函数声明
void ired_init(void);
#endif
//ired.c
#include "ired.h"
u8 gired_data[4];//存储4个字节接收码(地址码+地址反码+控制码+控制反码)
/*******************************************************************************
* 函 数 名 : ired_init
* 函数功能 : 红外端口初始化函数,外部中断0配置
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void ired_init(void)
{
IT0=1; //下降沿触发
EX0=1; //打开中断0允许
EA=1; //打开总中断
IRED=1; //初始化端口
}
void ired() interrupt 0 //外部中断0服务函数
{
u8 ired_high_time=0;
u16 time_cnt=0;
u8 i=0,j=0;
//引导信号有9ms的低电平和4.5ms的高电平,先把这两部分读掉,并且如果太长时间引导信号没有发生相应的变化就先跳出,省的系统死机。我们给引导信号10ms和5ms的机会。
if(IRED==0)
{
time_cnt=1000;
while((!IRED)&&(time_cnt))//等待引导信号9ms低电平结束,若超过10ms强制退出
{
delay_10us(1);//延时约10us
time_cnt--;
if(time_cnt==0)return;
}
if(IRED)//引导信号9ms低电平已过,进入4.5ms高电平
{
time_cnt=500;
while(IRED&&time_cnt)//等待引导信号4.5ms高电平结束,若超过5ms强制退出
{
delay_10us(1);
time_cnt--;
if(time_cnt==0)return;
}
//接下来是读取地址、地址反码、控制、控制反码。
for(i=0;i<4;i++)//循环4次,读取4个字节数据
{
for(j=0;j<8;j++)//循环8次读取每位数据即一个字节
{
time_cnt=600;
while((IRED==0)&&time_cnt)//等待数据1或0前面的0.56ms结束,若超过6ms强制退出
{
delay_10us(1);
time_cnt--;
if(time_cnt==0)return;
}
time_cnt=20;
while(IRED)//等待数据1或0后面的高电平结束,若超过2ms强制退出
{
delay_10us(10);//约0.1ms
ired_high_time++;
if(ired_high_time>20)return;
}
gired_data[i]>>=1;//先读取的为低位,然后是高位
if(ired_high_time>=8)//如果高电平时间大于0.8ms,数据则为1,否则为0
gired_data[i]|=0x80;//最高位赋1
ired_high_time=0;//重新清零,等待下一次计算时间
}
}
}
if(gired_data[2]!=~gired_data[3])//校验控制码与反码,错误则清空后返回
{
for(i=0;i<4;i++)
gired_data[i]=0;
return;
}
}
}
main.c:
void main()
{
u8 ired_buf[3];
ired_init();//红外初始化
while(1)
{
ired_buf[0]=gsmg_code[gired_data[2]/16];//将控制码高4位转换为数码管段码
ired_buf[1]=gsmg_code[gired_data[2]%16];//将控制码低4位转换为数码管段码
ired_buf[2]=0X76;//显示H的段码
smg_display(ired_buf,6);
}
}