51单片机嵌入式开发教程:使用STC89C52RC解码HX1838红外信号并进行数码管显示和LED显示

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

STC89C52RC 之HX1838红外解码NEC+数码管+串口打印+LED显示

  • STC89C52RC 之HX1838红外解码NEC+数码管+串口打印+LED显示
  • 1 概述
  • 2 硬件电路
  • 2.1 遥控器
  • 2.2 红外接收器电路
  • 2.3 STC89C52单片机电路
  • 2.4 数码管显示电路
  • 2.5 串口打印电路
  • 2.6 LED显示电路
  • 3 工程代码实现
  • 3.1 红外接收程序
  • 3.2 定时器程序
  • 3.3 数码管显示程序
  • 3.4 外部中断程序
  • 3.5 串口打印程序
  • 3.6 演示效果
  • 4 设计总结

  • STC89C52RC 之HX1838红外解码NEC+数码管+串口打印+LED显示

    HX1838红外解码NEC+数码管+串口打印+LED显示

    1 概述

    对于C51单片机的设计思路,你可以使用类似的步骤来实现红外解码、数码管显示和LED显示的功能。下面是一个简单的设计思路:

    (1) 连接HX1838红外解码器、数码管和LED到C51单片机。将HX1838的信号引脚连接到C51单片机的外部中断引脚(例如INT0),数码管的CLK引脚连接到C51单片机的某个IO口引脚,数码管的DIO引脚连接到C51单片机的另一个IO口引脚,LED连接到C51单片机的某个IO口引脚。
    (2) 在C51的程序中,定义并初始化所需的IO口和外部中断。
    (3) 编写中断服务函数来处理红外解码。当外部中断触发时,读取HX1838接收到的红外信号,并进行解码。
    (4) 根据解码结果,使用适当的算法将解码结果转换为数码管的显示数据。
    (5) 将数码管的显示数据发送到数码管的CLK和DIO引脚上,以控制数码管显示解码结果。
    (6) 根据解码结果的状态,设置LED的引脚状态,以控制LED的显示。
    (7) 通过循环等待的方式,持续接收和处理红外信号,并更新数码管和LED的显示。

    2 硬件电路

    2.1 遥控器

    外部遥控器的编码见下图:

    2.2 红外接收器电路

    红外接收器电路见下图:

    2.3 STC89C52单片机电路

    单片机接口电路见下图:

    2.4 数码管显示电路

    数码管显示电路接口电路见下图,在数码管0和1进行显示16进制的红外线接收码:
    在之前的章节,有相关数码管数显实现的方法,大家可以翻一翻。

    2.5 串口打印电路

    串口打印电路接口电路见下图(其实用下载电路也能实现串口的通讯):

    2.6 LED显示电路

    LED显示电路电路见下图:
    根据不同的接收数据码,在8个LED灯进行显示,当对应位置为1时,led不亮。

    3 工程代码实现

    工程、主程序及includes.h如下:

    //main.c文件

    #include "includes.h"
    
    
    
    /******************************************************************/
    /*                    微秒延时函数  //10us                         */
    /******************************************************************/
    void delay_us(unsigned int us)//delay us
    {
    	while(us--)
    	{
    	}
    }
    
    /******************************************************************/
    /*                    微秒延时函数                                */
    /******************************************************************/
    void delay_ms(unsigned int Ms)//delay us
    {
    	while(Ms--)
    	{
    		delay_us(100);
    	}
    }
    
    /*------------------------------------------------
                        延时子程序
    ------------------------------------------------*/
    void delay(unsigned int cnt) 
    {
     while(--cnt);
    }
    
    
    
    
    /*------------------------------------------------
                        主函数
    ------------------------------------------------*/
    void main (void)
    {
    	sys_timer_init();
    	
    	sys_exit_init();
    	
    	sys_uart_init();
    	
    	
    //	sys_ledtube_on2();
    //	
    //	sys_ledtube_on1();
    	
    	delay(10);
    	
    	//首先定义处于什么状态,
    	//tx1838_type = 1;
    	
    	
    	printf("Hello world~~");
    	while (1)
    	{
    //		sys_tx1838_test();
    		if(tx1838_flag)
    		{
    			tx1838_flag = 0;
    			hx1838_transform(tx1838_value);
    		}
    		
    		sys_keynum_ledon(tx1838_value>>4,0);
    		delay_ms(10);
    		sys_keynum_ledon(tx1838_value&0xF,1);
    		delay_ms(10);
    	}
    }
    

    //includes.h文件

    #ifndef __INCLUDES_H__
    #define __INCLUDES_H__
    
    //#include<reg52.h> 
    
    #include<intrins.h> //汇编指令_nop_
    #include<stdio.h> 	//标准输入输出
    
    //_nop_(); 产生一条NOP指令
    //作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
    //NOP指令为单周期指令,可由晶振频率算出延时时间。
    
    //8051 为每个机器周期 12 时钟
    //对于12M晶振,延时1uS。
    //11.0592M晶振,延时1.0851uS。
    
    //对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。
    
    
    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
    #include "STC89C5xRC_RDP.h"
    
    //应用层头文件
    //#include "c51_gpio.h"
    #include "c51_ledtube.h"
    //#include "c51_key.h"
    #include "c51_timer.h"
    #include "c51_exit.h"
    //#include "c51_lcd1602.h"
    //#include "c51_iic.h"
    #include "c51_tx1838.h"
    #include "c51_uart.h"
    
    
    extern void delay(unsigned int cnt);
    extern void delay_us(unsigned int us);//delay us;
    extern void delay_ms(unsigned int Ms);//delay Ms;
    
    
    #endif
    

    3.1 红外接收程序

    实现红外nec解码和根据码位不同,在printf打印不同的字符串。
    //c51_tx1838.c文件

    #include "includes.h"
    
    
    unsigned char tx1838_cnt = 0;
    unsigned char tx1838_type = 0;
    unsigned char tx1838_flag = 0;
    unsigned char tx1838_repeat_flag = 0;
    
    
    unsigned char tx1838_value = 0;
    unsigned char tx1838_data[4] = {0};
    unsigned int  tx1838_time = 0;
    
    
    //void sys_tx1838_test(void)
    //{
    //	unsigned int time = 0;
    //	if(!NEC)
    //	{
    //		while(!NEC);		//等待低电平结束
    //		TH0 = 0;
    //		TL0 = 0;
    //		delay_us(1);
    //		if(tx1838_type==4)
    //		{
    //			tx1838_type =1;
    //		}
    //		else
    //		{
    //			while(NEC)			//等待数据位计时
    //			{
    //				if(TH0>30)
    //				{
    //					tx1838_type =1;
    //					break;
    //				}
    //			}
    //		}
    //		time =(TH0<<8)+TL0; //取得脉冲宽度
    //	
    //		switch(tx1838_type)
    //		{
    //			case 1:
    //			{
    //				if(time>3000 && time<7000) //接收到数据
    //				{
    //					tx1838_type = 2;
    //					
    //					tx1838_cnt = 0;		//接收位数量清0
    //					tx1838_data[0] = 0;
    //					tx1838_data[1] = 0;
    //					tx1838_data[2] = 0;
    //					tx1838_data[3] = 0;
    //				}
    //				else if(time>2000 && time<3000)//接收到重复码
    //				{
    //					tx1838_type = 3;
    //				}
    //				else
    //				{
    //					tx1838_type = 1;
    //				}
    //				break;
    //			}
    //			case 2:
    //			{
    //				tx1838_cnt ++ ;
    //				if(time>168 && time<800) //接收到数据位为0的时间长度
    //				{
    
    //				}
    //				else 
    //				{
    //					if(time>1100 && time<1800) //接收到数据位为1的时间长度
    //					{
    //						if(tx1838_cnt<=8)
    //						{
    //							tx1838_data[0] |= (1<<(tx1838_cnt-1));
    //						}
    //						else if(tx1838_cnt<=16)
    //						{
    //							tx1838_data[1] |= (1<<(tx1838_cnt-9));
    //						}
    //						else if(tx1838_cnt<=24)
    //						{
    //							tx1838_data[2] |= (1<<(tx1838_cnt-17));
    //						}
    //						else if(tx1838_cnt<=32)
    //						{
    //							tx1838_data[3] |= (1<<(tx1838_cnt-25));
    //						}
    //						else
    //						{
    //							tx1838_type = 1;
    //							
    //							tx1838_cnt = 0;		//接收位数量清0
    //							tx1838_data[0] = 0;
    //							tx1838_data[1] = 0;
    //							tx1838_data[2] = 0;
    //							tx1838_data[3] = 0;
    //						}
    //					}
    //					else //重新解码 //接收到引导码或者结束码,或者接收到的是重复码,本章节不进行演示
    //					{
    //						tx1838_type = 1;
    //						
    //						tx1838_cnt = 0;		//接收位数量清0
    //						tx1838_data[0] = 0;
    //						tx1838_data[1] = 0;
    //						tx1838_data[2] = 0;
    //						tx1838_data[3] = 0;
    //					}
    //				}
    //				
    //				if(tx1838_cnt>=32)
    //				{
    //					tx1838_type = 4;
    //					
    //					switch(tx1838_data[3])//判断数码值
    //					{
    //						case 255:sys_keynum_ledon(0);break;//0 显示相应的按键值
    //						case 254:sys_keynum_ledon(1);break;//1
    //						case 253:sys_keynum_ledon(2);break;//2
    //						case 252:sys_keynum_ledon(3);break;//3
    //						case 251:sys_keynum_ledon(4);break;//4
    //						case 250:sys_keynum_ledon(5);break;//5
    //						case 249:sys_keynum_ledon(6);break;//6
    //						case 248:sys_keynum_ledon(7);break;//7
    //						case 247:sys_keynum_ledon(8);break;//8
    //						case 246:sys_keynum_ledon(9);break;//9 显示相应的按键值
    
    //					}
    //				}
    //				break;
    //			}
    //			case 3: //重复码
    //			{
    //				tx1838_type = 1;
    //				sys_keynum_ledon(11);
    //				break;
    //			}
    //			case 4: //结束码
    //			{
    //				tx1838_type = 1;
    //				
    //				tx1838_cnt = 0;		//接收位数量清0
    //				
    //				break;
    //			}
    //			case 5:
    //			{
    //				break;
    //			}
    //			default:
    //				tx1838_type = 1;
    //				break;
    //		}
    //			
    //	}
    //}
    
    
    
    void sys_nec_test(void)
    {
    	if(tx1838_type==0)				//状态0,空闲状态
    	{
    		timer0_set(0);				//定时计数器清0
    		timer0_run(1);				//定时器启动
    		tx1838_type=1;				//置状态为1
    	}
    	else if(tx1838_type==1)			//状态1,等待Start信号或Repeat信号
    	{
    		tx1838_time=timer0_get();	//获取上一次中断到此次中断的时间
    		timer0_set(0);				//定时计数器清0
    		//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
    		if(tx1838_time>12442-500 && tx1838_time<12442+500)
    		{
    			tx1838_type=2;			//置状态为2
    		}
    		//如果计时为11.25ms,则接收到了repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
    		else if(tx1838_time>10368-500 && tx1838_time<10368+500)
    		{
    			tx1838_repeat_flag=1;	//置收到连发帧标志位为1
    			timer0_run(0);		//定时器停止
    			tx1838_type=0;		//置状态为0
    		}
    		else					//接收出错
    		{
    			tx1838_type=1;			//置状态为1
    		}
    	}
    	else if(tx1838_type==2)		//状态2,接收数据
    	{
    		tx1838_time=timer0_get();	//获取上一次中断到此次中断的时间
    		timer0_set(0);	//定时计数器清0
    		//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
    		if(tx1838_time>1032-500 && tx1838_time<1032+500)
    		{
    			tx1838_data[tx1838_cnt/8]&=~(0x01<<(tx1838_cnt%8));	//数据对应位清0
    			tx1838_cnt++;			//数据位置指针自增
    		}
    		//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
    		else if(tx1838_time>2074-500 && tx1838_time<2074+500)
    		{
    			tx1838_data[tx1838_cnt/8]|=(0x01<<(tx1838_cnt%8));	//数据对应位置1
    			tx1838_cnt++;			//数据位置指针自增
    		}
    		else					//接收出错
    		{
    			tx1838_cnt=0;			//数据位置指针清0
    			tx1838_type=1;			//置状态为1
    		}
    		if(tx1838_cnt>=32)		//如果接收到了32位数据
    		{
    			tx1838_cnt=0;			//数据位置指针清0
    			if((tx1838_data[0]==~tx1838_data[1]) && (tx1838_data[2]==~tx1838_data[3]))	//数据验证
    			{
    				//地址		:tx1838_data[0]
    				//地址反码	:tx1838_data[1]
    				//数据		:tx1838_data[2]
    				//数据反码	:tx1838_data[3]
    				
    				tx1838_value = tx1838_data[2];
    				P1 = tx1838_value;
    				tx1838_flag=1;	//红外遥控获取收到数据帧标志位
    			}
    			timer0_run(0);		//定时器停止
    			tx1838_type=0;			//置状态为0
    		}
    	}
    }
    
    
    void hx1838_transform(unsigned char cmd)
    {
    	/*
    	#define TX1838_CH0			0x45
    #define TX1838_CH1			0x46
    #define TX1838_CH2			0x47
    #define TX1838_VOL1			0x44
    #define TX1838_VOL2			0x40
    #define TX1838_VOL3			0x43
    #define TX1838_EQ1			0x07
    #define TX1838_EQ2			0x15
    #define TX1838_EQ3			0x09
    #define TX1838_0			0x16
    #define TX1838_100			0x19
    #define TX1838_200			0x0D
    #define TX1838_1			0x0C
    #define TX1838_2			0x18
    #define TX1838_3			0x5E
    #define TX1838_4			0x08
    #define TX1838_5			0x1C
    #define TX1838_6			0x5A
    #define TX1838_7			0x42
    #define TX1838_8			0x52
    #define TX1838_9			0x4A
    	*/
    	switch(cmd)
    	{
    		case TX1838_CH0:
    			printf("Receice cmd : TX1838 receice is TX1838_CH0 !\r\n");
    			break;
    		case TX1838_CH1:
    			printf("Receice cmd : TX1838 receice is TX1838_CH1 !\r\n");
    			break;
    		case TX1838_CH2:
    			printf("Receice cmd : TX1838 receice is TX1838_CH2 !\r\n");
    			break;
    		case TX1838_VOL1:
    			printf("Receice cmd : TX1838 receice is TX1838_VOL1 !\r\n");
    			break;
    		case TX1838_VOL2:
    			printf("Receice cmd : TX1838 receice is TX1838_VOL2 !\r\n");
    			break;
    		case TX1838_VOL3:
    			printf("Receice cmd : TX1838 receice is TX1838_VOL3 !\r\n");
    			break;
    		case TX1838_EQ1:
    			printf("Receice cmd : TX1838 receice is TX1838_EQ1 !\r\n");
    			break;
    		case TX1838_EQ2:
    			printf("Receice cmd : TX1838 receice is TX1838_EQ2 !\r\n");
    			break;
    		case TX1838_EQ3:
    			printf("Receice cmd : TX1838 receice is TX1838_EQ3 !\r\n");
    			break;
    		case TX1838_0:
    			printf("Receice cmd : TX1838 receice is TX1838_0 !\r\n");
    			break;
    		case TX1838_100:
    			printf("Receice cmd : TX1838 receice is TX1838_100 !\r\n");
    			break;
    		case TX1838_200:
    			printf("Receice cmd : TX1838 receice is TX1838_200 !\r\n");
    			break;
    		case TX1838_1:
    			printf("Receice cmd : TX1838 receice is TX1838_1 !\r\n");
    			break;
    		case TX1838_2:
    			printf("Receice cmd : TX1838 receice is TX1838_2 !\r\n");
    			break;
    		case TX1838_3:
    			printf("Receice cmd : TX1838 receice is TX1838_3 !\r\n");
    			break;
    		case TX1838_4:
    			printf("Receice cmd : TX1838 receice is TX1838_4 !\r\n");
    			break;
    		case TX1838_5:
    			printf("Receice cmd : TX1838 receice is TX1838_5 !\r\n");
    			break;
    		case TX1838_6:
    			printf("Receice cmd : TX1838 receice is TX1838_6 !\r\n");
    			break;
    		case TX1838_7:
    			printf("Receice cmd : TX1838 receice is TX1838_7 !\r\n");
    			break;
    		case TX1838_8:
    			printf("Receice cmd : TX1838 receice is TX1838_8 !\r\n");
    			break;
    		case TX1838_9:
    			printf("Receice cmd : TX1838 receice is TX1838_9 !\r\n");
    			break;
    		default:
    			printf("Receice cmd : TX1838 receice err!\r\n");
    			break;
    	}
    }
    

    //c51_tx1838.h文件

    #ifndef __C51_TX1838_H__
    #define __C51_TX1838_H__
    
    
    #define  NEC 	P32 //红外线接收头  
    
    
    #define TX1838_CH0			0x45
    #define TX1838_CH1			0x46
    #define TX1838_CH2			0x47
    #define TX1838_VOL1			0x44
    #define TX1838_VOL2			0x40
    #define TX1838_VOL3			0x43
    #define TX1838_EQ1			0x07
    #define TX1838_EQ2			0x15
    #define TX1838_EQ3			0x09
    #define TX1838_0			0x16
    #define TX1838_100			0x19
    #define TX1838_200			0x0D
    #define TX1838_1			0x0C
    #define TX1838_2			0x18
    #define TX1838_3			0x5E
    #define TX1838_4			0x08
    #define TX1838_5			0x1C
    #define TX1838_6			0x5A
    #define TX1838_7			0x42
    #define TX1838_8			0x52
    #define TX1838_9			0x4A
    
    
    
    extern unsigned char tx1838_cnt;
    extern unsigned char tx1838_type;
    extern unsigned char tx1838_flag;
    extern unsigned char tx1838_repeat_flag;
    extern unsigned char tx1838_value;
    extern unsigned char tx1838_data[4];
    extern unsigned int tx1838_time;
    
    
    //extern void sys_tx1838_test(void);
    extern void sys_nec_test(void);
    extern void hx1838_transform(unsigned char cmd);
    
    
    #endif
    

    3.2 定时器程序

    定时器主要是配合解码时时间长短判断接收数据的0和1。

    //c51_timer.c文件

    #include "includes.h"
    
    
    void sys_timer_init(void)
    {
    	sys_timer0_init();
    	sys_timer1_init();
    	sys_timer2_init();
    	sys_wdog_init();
    	clr_wdg();
    }
    
    
    /*------------------------------------------------
                        定时器初始化子程序
    ------------------------------------------------*/
    void sys_timer0_init(void)
    {
    	TMOD &= 0xF0;
    	TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
    	TH0=0x00;	      //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
    	TL0=0x00;
    	//EA=1;            //总中断打开 等最后一个中断打开
    	//ET0=1;           //定时器中断打开
    	TF0=0;           //定时器标志清零
    	TR0=0;           //定时器开关打开
    }
    
    /*------------------------------------------------
                        定时器初始化子程序
    ------------------------------------------------*/
    void sys_timer1_init(void)
    {
    	TMOD |= 0x20;	  //使用模式2,	     
    	TH1=0x05;	      //给定初值,这里使用定时器最大值从5开始计数一直到255溢出
    	TL1=0x00;
    	//EA=1;            //总中断打开
    	//ET1=1;           //定时器中断打开
    	
    	//TR1=1;           //定时器开关打开
    }
    
    
    /*------------------------------------------------
                        定时器初始化子程序
    ------------------------------------------------*/
    void sys_timer2_init(void)
    {
    	RCAP2H = 0/256;//
    	RCAP2L = 0/256;
    	//ET2=1;                     //打开定时器中断
    	//EA=1;                      //打开总中断
      
    	//TR2=1;                     //打开定时器开关
    }
    
    /**
      * @brief  定时器0设置计数器值
      * @param  Value,要设置的计数器值,范围:0~65535
      * @retval 无
      */
    void timer0_set(unsigned int Value)
    {
    	TH0=Value/256;
    	TL0=Value%256;
    }
     
    /**
      * @brief  定时器0获取计数器值
      * @param  无
      * @retval 计数器值,范围:0~65535
      */
    unsigned int timer0_get(void)
    {
    	return ((TH0<<8)|TL0);
    }
    
    /**
      * @brief  定时器0启动停止控制
      * @param  Flag 启动停止标志,1为启动,0为停止
      * @retval 无
      */
    void timer0_run(unsigned char Flag)
    {
    	TR0=Flag;
    }
    
    
    
    void sys_wdog_init(void)
    { 
    	//WDT_CONTR = 0x35;
    }
    
    void clr_wdg(void)
    {
    	//WDT_CONTR = 0x35;
    }
    
    
    /*------------------------------------------------
                     定时器中断子程序
    ------------------------------------------------*/
    void Timer0_isr(void) interrupt 1
    {
    	TH0=0x00;		  //重新赋值
    	TL0=0x00;
    
    	//sys_led_test1(); //流水灯操作
    }
    
    
    /*------------------------------------------------
                     定时器中断子程序
    ------------------------------------------------*/
    void Timer1_isr(void) interrupt 3
    {
    
    	//sys_led_test1(); //流水灯操作
    	
    }	
    
    
    
    
    /*------------------------------------------------
                     定时器中断子程序
    ------------------------------------------------*/
    void Timer2_isr(void) interrupt 5//定时器2中断
    {
        TF2=0;
        //sys_led_test1(); //流水灯操作
    }
    

    //c51_timer.h文件

    #ifndef __C51_TIMER_H__
    #define __C51_TIMER_H__
    
    
    
    
    
    
    extern void timer0_set(unsigned int Value);
    extern unsigned int timer0_get(void);
    extern void timer0_run(unsigned char Flag);
    
    extern void sys_timer_init(void);
    extern void sys_timer0_init(void);
    extern void Timer0_isr(void);
    extern void sys_timer1_init(void);
    extern void Timer1_isr(void);
    extern void sys_timer2_init(void);
    extern void Timer2_isr(void);
    
    extern void sys_wdog_init(void);
    extern void clr_wdg(void);
    
    #endif
    

    3.3 数码管显示程序

    实现数码管显示遥控器的发送码。

    //c51_ledtube.c文件

    #include "includes.h"
    
    // 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
    unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,\
    		                  	 0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F
    
    
    
    ///********************************************************
    //函数名称:sys_ledtube_on1
    //函数功能:点亮一个数码管全为亮起来
    //入口参数:
    //出口参数:
    //修    改:
    //内    容:
    //********************************************************/
    //void sys_ledtube_on1(void)
    //{
    //	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
    //	P0=0xFF;//取显示数据,段码
    //	P2=0;  	//取位码
    //}
    
    ///********************************************************
    //函数名称:sys_ledtube_on2
    //函数功能:显示一组数据
    //入口参数:
    //出口参数:
    //修    改:
    //内    容:
    //********************************************************/
    //static unsigned char ledtube_cnt = 0;
    //void sys_ledtube_on2(void)
    //{
    //	ledtube_cnt++;
    //	if(ledtube_cnt>7)
    //	{
    //		ledtube_cnt = 0;
    //	}
    //	P0 = 0x00;				//防止切换数码管瞬间有虚影出现
    //	P2 = 0x00;
    //	P0 = EL[ledtube_cnt];	//取显示数据,段码
    //	P2 = ledtube_cnt;  		//取位码
    //	
    //	//根据人眼适应虚影缓冲时间为50ms左右
    //	//我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
    //	delay(100); 			
    //}
    
    
    /********************************************************
    函数名称:sys_keynum_ledon
    函数功能:显示按键数值
    入口参数:按键数值
    出口参数:
    修    改:
    内    容:
    ********************************************************/
    void sys_keynum_ledon(unsigned char num,unsigned char pn)
    {
    	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
    	P0 = 0x00;		//防止切换数码管瞬间有虚影出现
    	P2 = pn;  		//取位码
    	P0 = EL[num];	//取显示数据,段码
    }
    

    //c51_ledtube.h文件

    #ifndef __C51_LEDTUBE_H__
    #define __C51_LEDTUBE_H__
    
    
    extern unsigned char const EL[];
    
    //extern void sys_ledtube_on1(void);
    //extern void sys_ledtube_on2(void);
    
    extern void sys_keynum_ledon(unsigned char num,unsigned char pn);
    
    
    #endif
    

    3.4 外部中断程序

    实现在有数据过来时,下降沿触发解码程序。

    //c51_exit.c文件

    #include "includes.h"
    
    
    
    
    void sys_exit_init(void)
    {
    	IT0=1;         //边沿触发
    	EX0=1;         //外部中断0开
    	IE0=0;		   //中断标志清零
    	//PX0 = 1;		 //中断优先级不配置
    	EA = 1;
    	
    	//EX1=1;         //外部中断1开
    	//IT1=0;         //电平触发
    	//IT1=1;         //边沿触发,IT1=0表示电平触发
    }
    
    
    /*------------------------------------------------
                     外部中断程序
    ------------------------------------------------*/
    void Exit0_isr(void) interrupt 0
    {
    	IE0=0;		   //中断标志清零
    	sys_nec_test();
    }
    
    
    /*------------------------------------------------
                     外部中断程序
    ------------------------------------------------*/
    void Exit1_isr(void) interrupt 2
    {
    	//在此处可以添加去抖动程序,防止按键抖动造成错误
    	//P1=~P1;
    }
    
    

    //c51_exit.h文件

    
    
    #ifndef __C51_EXIT_H__
    #define __C51_EXIT_H__
    
    extern void sys_exit_init(void);
    extern void Exit0_isr(void);
    extern void Exit1_isr(void);
    
    
    
    #endif
    

    3.5 串口打印程序

    实现printf打印不同的字符串。

    //c51_uart.c文件

    #include "includes.h"
    
    
    
    /*-----------------------------------------------
      名称:串口通信
      内容:连接好串口或者usb转串口至电脑,下载该程序,打开电源
            打开串口调试程序,将波特率设置为9600,无奇偶校验
            晶振11.0592MHz,发送和接收使用的格式相同,如都使用
            字符型格式,在发送框输入 hello,I Love MCU ,在接
            收框中同样可以看到相同字符,说明设置和通信正确
    ------------------------------------------------*/
                        
    
    
    /******************************************************************/
    void sys_uart_init(void)
    {
    
    
    	SCON  = 0x50;		        /* SCON: 模式 1, 8-bit UART, 使能接收         */
    	TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
    	TH1   = 0xFD;               /* TH1:  reload value for 9600 baud @ 11.0592MHz   */
    	TR1   = 1;                  /* TR1:  timer 1 run                          */
    	EA    = 1;                  /*打开总中断*/
    	//ES    = 1;                  /*打开串口中断*///当使用串口协议通讯时可以使用此型号中断
    
    }
    
    
    void Uart_SendChar(unsigned char  dat)
    {
        SBUF = dat; 
        while(!TI); 
        TI = 0; 
    }
     
    char putchar(char c)//重定向
    {
        Uart_SendChar(c);
        return c;
    
    }
    
    /******************************************************************/
    /*                  串口中断程序                                  */
    /******************************************************************/
    
    
    static unsigned char uart_temp = 0;          //定义临时变量 
    static unsigned char uart_cnt = 0;          //定义临时变量 
    
    
    void UART_isr(void) interrupt 4 //串行中断服务程序
    {
    	if(RI)                        //判断是接收中断产生
    	{
    		RI=0;                      //标志位清零
    		uart_temp=SBUF;                 //读入缓冲区的值
    		if(uart_cnt==0)
    		{
    			if(0x02 == uart_temp)
    			{
    				uart_cnt = 1;
    			}
    			else
    			{
    				uart_cnt = 0;
    			}
    		}
    		else if(uart_cnt==1)
    		{
    			if(0x05 == uart_temp)
    			{
    				uart_cnt = 2;
    			}
    			else
    			{
    				uart_cnt = 0;
    			}
    		}
    		else if(uart_cnt==2)
    		{
    			uart_cnt = 0;
    			//P1=uart_temp;                   //把值输出到P1口,用于观察
    			SBUF=uart_temp;                 //把接收到的值再发回电脑端
    		}
    		else
    		{
    			uart_cnt = 0;
    		}
    	}
    	if(TI)                        //如果是发送标志位,清零
    	{
    		TI=0;
    	}
    } 
    

    //c51_uart.h文件

    #ifndef __C51_UART_H__
    #define __C51_UART_H__
    
    
    extern void Uart_SendChar(unsigned char  dat);
    extern char putchar(char c);//重定向
    
    extern void sys_uart_init(void);
    extern void UART_isr(void);
    
    
    #endif
    

    3.6 演示效果

    (1)串口打印效果

    (2)数码管显示和LED显示
    数码管显示0x1C,LED显示D2D3D4灭,其他亮,所以也显示0x1C

    4 设计总结

    HX1838红外解码器结合数码管、串口和LED显示的应用场景有很多,下面是一些可能的应用场景:
    (1) 远程控制器:将HX1838红外解码器与数码管、串口和LED显示结合使用,可以实现一个简单的远程控制器。用户可以使用红外遥控器发送命令,通过解码器解码后,在数码管上显示命令信息,并使用LED显示命令的状态(例如开启/关闭)。这可以用于控制家电设备、灯光等。
    (2) 安防系统:将HX1838红外解码器与数码管、串口和LED显示结合使用,可以构建一个基本的安防系统。通过使用红外遥控器发送特定的指令,解码器将解码后的指令信息显示在数码管上,并相应地控制LED的状态,以指示安全状态或报警状态。
    (3) 学习工具:结合数码管和LED显示,可以将HX1838红外解码器用于学习工具。例如,可以使用红外遥控器发送特定的学习指令,解码器将解码后的指令信息显示在数码管上,而LED则可以用于指示学习进度或正确与否。
    (4) 玩具设计:利用HX1838红外解码器和数码管、串口和LED显示,可以设计各种互动玩具。例如,通过使用特定的红外遥控器发送不同的指令,解码器将识别并在数码管上显示相应的信息,而LED则可以用于增加互动效果或指示玩具状态。
    (5) DIY项目:HX1838红外解码器与数码管、串口和LED显示的组合可以应用于各种DIY项目,例如智能家居控制、自动化系统、电子游戏等。通过自定义红外指令和相应的解码、显示和控制逻辑,可以实现各种有趣的功能和交互体验。
    这些只是一些示例应用场景,实际上,HX1838红外解码器与数码管、串口和LED显示的组合可以应用于各种需要红外信号解码和相应显示控制的项目和系统中。具体的应用取决于你的创意和需求。

    作者:小白在路上~

    物联沃分享整理
    物联沃-IOTWORD物联网 » 51单片机嵌入式开发教程:使用STC89C52RC解码HX1838红外信号并进行数码管显示和LED显示

    发表回复