车载红外遥控之51单片机解码

对单片机的了解学习,是作为简单的遥控器解码学习的基础,因为本次DIY是通过MCU作为解码媒介的。但实验中的DIY方式又不必需要功能强大的ARM系列单片机去实现,一般0851单片机就能解决。

本实验的演示功能是通过对红外遥控键值解码后,对设定的目标键值做出响应,实验中的响应是单片机对继电器的开合、通断控制,可以简单理解为单片机检测到遥控器某个指定的按键按下,则控制继电器实现开关的切换功能,实现过程如下:

Figure 1原理图

首先是选型,由于物资条件,我们考虑成本,

所以选择的都是廉价器件,器件有车载MP3

外遥控,1318红外接收头,51系列的stc15F104w

芯片,一个11.0592MHZ的晶振,两个100pf的电

容,一个继电器,一个二极管1N4148,一个PNP三极管9012/S8550,两个200欧姆电阻。

其次是电路搭建,电路通过红外遥控接收头,将接收到的遥控编码信息发送至单片机,单片机对红外遥控的键值解码后在P3.5口输出控制信

号,控制继电器的开关效果。具体的电路原理图见

原理图所示。

 最后,实现解码功能的51程序流程图如右图

所示:首先硬件上电,软件初始化外部中断,初始

 

化定时器配置,之后是不断地轮询单片机的中断引

 

脚,检测单片机的引脚状态是否改变,如果引脚状态被改变了,说明端口有数据到来,此时单片机的定时器将在中断中被激活。定时器被激活的作用是用来给给每个二进制数据位进行定时的,将高低电平状态产生的时间存储到一个数组里面,最后将该时间值数组转换成高低电平状态。

 

 左图是红外遥控采集单片机中断引脚的高低电平时间,并将得到的时间放在irdate数组里,我们使用的红外遥控的编码是32位的编码。由引导码、用户码、数据码和数据码反码组成32位的编码方式。实验测试得到,引导码是有9ms的高电平和4.5ms的低电平组成。用户码或数据码中的每一个位可以是位‘1’,也可以是位‘0’。区分‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式。英文简写PPM。其脉冲调制是使用455KHz晶体产生的载波脉冲实现。

 

总结:通过本次实验,了解到了红外遥控编码及解码的工作原理。并实践应用51单片机解码实现继电器的吸合开关电路控制。实验中用到了单片机的外部中断配置和单片机的定时器配置。

 具体代码如下

hwjm.c
#include<stc15f104w.h>
#include"hwjm.h"
#include"delay.h"
#include"music.h"

uchar irreceok;//一整数据接收完毕
uchar irprosok;
unsigned char b;
extern unsigned char b;
//uchar irtime,irtime1;//第一步时间存储
uchar irtime;    //第一步时间存储
uchar startflag;
uchar bitnum;
uchar ircode[4];
extern unsigned char Count;
extern uchar smg_gyangji[];
//uchar display[8];

uchar irdate[33];//接收数组此为一些时间变量;0.25ms或者2.256ms
uchar anjianjiema[]={0x16,0x0c,0x18,0x5e,0x08,0x1c,0x5a,0x42,0x52,0x4a};//0-7;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
//uchar smg_gyangji[]={
//0xC0,0xF9,0xA4,0xB0,
//0x99,0x92,0x82,0xF8,
//0x80,0x90,0x88,0x83,
//0xC6,0xA1,0x86,0x8E    
//};


//////////////红外接收到数据的数据函数////////////////////////
void hwxm_irrece(void)
{
    if(startflag)//第一次红外数据为引导码不起作用所以startflag为0直接跳过
            {
                    if(irtime>30)//检测引导吗;
                    {
                            bitnum=0;
                    }
                    irdate[bitnum]=irtime;//存的是时间0.25/0.256或是2.25/0.256时刻提取计时器实计数
                    irtime=0;
                    bitnum++;//红外接收数据数组下标每次检测到一次下降沿引发中断时加一
                    if(bitnum==33)//
                    {
                            bitnum=0;
                            irreceok=1;//档主函数判断是否当一次红外数据发送并接收完毕
                    }
                            
            }
            else
            {
                startflag=1;//中断触发后中断标志变量startflag将一直为1;
                irtime=0;
            }
    

}

void hwxm_irpros(void)
{
    uchar k,i,j;
    uchar value;
    k=1;//只提取用户吗;4*8=32位;
    for(j=0;j<4;j++)//四个码
    {
            for(i=0;i<8;i++)//每个码有8位
            {
                    value=value>>1;//7ci第一次vlalue等于0右移后等于0; 
                    if(irdate[k]>6)
                    {
                            value=value | 0x80;//10000000
                    }
                    k++;
            }
            ircode[j]=value;//为2进制
        }
        irprosok=1;//对时间转化成2进制的转换完毕;
}
int.c
#include<stc15f104w.h>
#include"int.h"
#include"hwjm.h"
extern uchar ircode[4];
extern unsigned char Count;
 unsigned char Temp2;
sfr T2MOD=0xc9;
void timer0init(void)    //计时器零初始化
{
        EA=1;
        ET0=1;
        TH0=0X00;
        TL0=0X00;//工作方式0
        TMOD=0X02;
        TR0=1;
}

void timer1init(void)    //计时器1初始化//最大值是255    
{
        EA=1;
        ET1=1;
        T2H=0XDC;
        T2L=0X00;
        T2MOD=0X02;//工作方式2,8位初值自动重装8位定时器/计数器
        TR1=1;
}


void int0init(void)//中断0初始化函数
{
        EA=1;    
        EX0=1;
        IT0=1;    //为跳变触发方式,电平从高到低的负跳变有效IT0=0时为低电平有效的电平触发方式
}

////////////////////////////////////////////////////////////////////////
///////////计时器0服务函数//////////////////
void timer0() interrupt 1
{
        irtime++;
        
}

void timer1() interrupt 3
{
         TH1 = 0xDC;
         TL1 = 0x00;
         Count++;  
    
    
}
///////中断服务函数////////////////
void int0 () interrupt 0//外部中断 服务函数
{
    hwxm_irrece();
    hwxm_irpros();
    if(ircode[2]==0x45||ircode[2]==0x47)
        Temp2 = Count;
}

main.c

#include<stc15f104w.h>
#include"delay.h"
#include"music.h"
#include"hwjm.h"
#include"int.h"
///////////////////////////////
extern unsigned char b;
extern uchar ircode[4];
extern uchar smg_gyangji[];
extern uchar anjianjiema[];
unsigned char Count;
extern uchar irreceok;//一整数据接收完毕
extern uchar irprosok;

sbit JD=P3^0;
sbit D=P3^1;
void main(void)
{
    timer1init();
    timer0init();
    int0init();
    P0=0xff;
    while(1)
    {
        unsigned char b;

        
        
        

    
            if(irreceok)//判断总中断服务函数中对接收时间的存储是否接收完眎rreceok为接收完毕标志位;
            {
                    hwxm_irpros();//解码服务函数;将时间间隔大小转换成16进制数
                    irreceok=0;//解码是否完毕;
            }
            if(irprosok)
            {

                    irprosok=0;//对时间做出相应的十六进制转化完成标志清零;
                    for(b=0;b<10;b++)
                        {
                                if(ircode[2]==anjianjiema[b])
                                {
                                    delay_50us(2);
                                    if(ircode[2]==anjianjiema[0])
                                    {
                                        JD=1;
                                        D=1;
                                    }
                                    else 
                                    {
                                        JD=0;
                                        D=0;
                                                                                
                                    }
                                        

                                                    
                                }
                            }
                                        
            }        

        }
}

 

原文地址:https://www.cnblogs.com/pertor/p/7512362.html