小白跟做江科大51单片机之红外遥控

时间:2024-03-16 21:24:10

1.通过外部寄存器编写代码,实现按下独立按键num数字++展示在LCD1602上的功能

STC89C52的外部中断有两种触发方式: 下降沿触发和低电平触发

此例中选择下降沿触发模式

此时mian.c编码

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"

unsigned char num;

void main()

     IT0=1;     //下降沿触发
     IE0=0;     //中断请求标志位清0
     EX0=1;     //外部中断打开
     EA=1;      //所有中断打开
     PX0=1;     //高优先级,确保其不会被其他中断打断
     LCD_Init();
     
    while(1)
    {
        LCD_ShowNum(2,1,num,3);
    }
}

void T1_time() interrupt 0
{
  num++;
}
2.模块化中断部分

以下部分我参照这位老哥的笔记进行编写

江科大自化协51单片机学习笔记(红外遥控部分)_单片机红外遥控器寄存器怎么设置-CSDN博客https://blog.csdn.net/lonelypasserby/article/details/128837798江科大笔记的思路是IR.C里面集成Int0.c和Time0.c,然后通过IR.C解码

Int0.c主要负责中断部分

#include <REGX52.H>

/**
  * @brief  外部中断初始化
  * @param  无
  * @retval 无
  */
void Int0_Init(void)
{
     IT0=1;     //下降沿触发
   IE0=0;     //中断请求标志位清0
   EX0=1;     //外部中断打开
   EA=1;      //所有中断打开
   PX0=1;     //高优先级,确保其不会被其他中断打断
}

/*外部中断0中断函数模板
void Int0_Routine(void) interrupt 0
{
    
}
*/

Time0.c赋负责计时

#include <REGX52.H>

//用于计时,不需要中断
void Timer0_Init(void)        //1毫秒@12.000MHz
{
    
    TMOD &= 0xF0;            //设置定时器模式
    TMOD |= 0x01;         //设置定时器模式
    TL0 = 0;                //设置定时初始值为0用于计时
    TH0 = 0;                //设置定时初始值为0用于计时
    TF0 = 0;                //清除TF0标志
    TR0 = 0;                //外部控制
}


/**
  * @brief 参数为标志位Flag,通过标志位控制计时器的启动与停止
  * @param
  *  @retval
  */
void Timer0_Run(unsigned char Flag)
{
    TR0=Flag;
}

/**
  * @brief 定时器0设置计数器值
  * @param
  *  @retval
  */
void Timer0_SetCounter(unsigned int Value)

    TH0=Value/256;
    TL0=Value%256;
}

/**
  * @brief 定时器0取到计数器值
  * @param
  *  @retval
  */
unsigned int Timer0_GetCounter(void)
{
    return (TH0<<8)|TL0;
}

根据上图编写IR.C代码,IR.C负责解码,注意要在IR.h中引入宏定义

#include <REGX52.H>
#include "Int0.h"
#include "time0.h"

unsigned int  IR_Time;           //用于存储每次计时器取出的时间值,便于判断信号类型
unsigned char IR_State;      /*0为空闲状态、1为等待信号状态(等待Start和Repeat信号)、
                               2为读取数据状态*/
unsigned char IR_Data[4];        //数据共有4个字节共32位
unsigned char IR_pData;          //指向数据位数的指针
unsigned char IR_DataFlag;       //为0表示数据解码未完成,为1表示数据解码已完成
unsigned char IR_RepeatFlag;     //为0表示数据不重写,为1表示数据重写
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;
}

/**
  * @brief  红外遥控获取收到的地址数据
  * @param  无
  * @retval 收到的地址数据
  */
unsigned char IR_GetAddress(void)
{
    return IR_Address;
}

/**
  * @brief  红外遥控获取收到的命令数据
  * @param  无
  * @retval 收到的命令数据
  */
unsigned char IR_GetCommand(void)
{
    return IR_Command;
}


void Int0_Routine(void) interrupt 0
{
    //IR_State==0空闲状态,红外LED不亮,接收头输出高电平
    if(IR_State==0)
    {
        Timer0_SetCounter(0);      //定时计数器清0
        Timer0_Run(1);                //定时器启动
        IR_State=1;                      //置状态为1
    }
    /*等待信号状态1:取出计时器数据后清0,
    判断信号为Start信号还是Repeat信号,
    若为Start信号,则进入读取数据状态;若为Repeat信号,则将IR_RepeatFlag置1,
    停止计时,回到空闲状态;*/
    else if(IR_State==1)
    {
        IR_Time=Timer0_GetCounter();    //获取上一次中断到此次中断的时间
        Timer0_SetCounter(0);    //定时计数器清0
        //如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
        if(IR_Time>12442-500 && IR_Time<12442+500)
        {
            IR_State=2;            //置状态为2
        }
        //如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
        else if(IR_Time>10368-500 && IR_Time<10368+500)
        {
            IR_RepeatFlag=1;    //置收到连发帧标志位为1
            Timer0_Run(0);        //定时器停止
            IR_State=0;            //置状态为0
        }
        else                    //接收出错
        {
            IR_State=1;            //置状态为1
        }

    }
    else if(IR_State==2)        //状态2,接收数据
    {
        IR_Time=Timer0_GetCounter();    //获取上一次中断到此次中断的时间
        Timer0_SetCounter(0);    //定时计数器清0
        //如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
        if(IR_Time>1032-500 && IR_Time<1032+500)
        {
            IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));    //数据对应位清0
            IR_pData++;            //数据位置指针自增
        }
        //如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
        else if(IR_Time>2074-500 && IR_Time<2074+500)
        {
            IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));    //数据对应位置1
            IR_pData++;            //数据位置指针自增
        }
        else                    //接收出错
        {
            IR_pData=0;            //数据位置指针清0
            IR_State=1;            //置状态为1
        }
        if(IR_pData>=32)        //如果接收到了32位数据
        {
            IR_pData=0;            //数据位置指针清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;    //置收到连发帧标志位为1
            }
            Timer0_Run(0);        //定时器停止
            IR_State=0;            //置状态为0
        }
    }

}

4.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
 

5.mian.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,"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_ADD)
            {
                num++;
            }
            if(command==IR_VOL_MINUS)
            {
                num--;
            }
            LCD_ShowNum(2,12,num,3);
        }
    }

}

6.结果展示

红外遥控