红外


青绿色为遥控器发射端波形,

黄颜色为一体化接收端波形,



静态时:

红外_第1张图片




发送一个电平,接收一个电平


红外_第2张图片


发送一个编码,接收一个按键的编码

红外_第3张图片




波形参考

红外_第4张图片



DIY硬件平台:

STC89C54RD+

LCD1602

红外1838接收

红外发送管

矩阵键盘

功能:

学习遥控器的编码

显示遥控器的NEC编码

发送学习到的编码






红外_第5张图片



STARTUP.A51

STARTUP.A51


$NOMOD51
;------------------------------------------------------------------------------
;  This file is part of the C51 Compiler package
;  Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
;  Version 8.01
;
;  *** <<< Use Configuration Wizard in Context Menu >>> ***
;------------------------------------------------------------------------------
;  STARTUP.A51:  This code is executed after processor reset.
;
;  To translate this file use A51 with the following invocation:
;
;     A51 STARTUP.A51
;
;  To link the modified STARTUP.OBJ file to your application use the following
;  Lx51 invocation:
;
;     Lx51 your object file list, STARTUP.OBJ  controls
;
;------------------------------------------------------------------------------
;
;  User-defined <h> Power-On Initialization of Memory
;
;  With the following EQU statements the initialization of memory
;  at processor reset can be defined:
;
; <o> IDATALEN: IDATA memory size <0x0-0x100>
;     <i> Note: The absolute start-address of IDATA memory is always 0
;     <i>       The IDATA space overlaps physically the DATA and BIT areas.
IDATALEN        EQU     80H
;
; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF> 
;     <i> The absolute start address of XDATA memory
XDATASTART      EQU     0     
;
; <o> XDATALEN: XDATA memory size <0x0-0xFFFF> 
;     <i> The length of XDATA memory in bytes.
XDATALEN        EQU     0      
;
; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF> 
;     <i> The absolute start address of PDATA memory
PDATASTART      EQU     0H
;
; <o> PDATALEN: PDATA memory size <0x0-0xFF> 
;     <i> The length of PDATA memory in bytes.
PDATALEN        EQU     0H
;
;</h>
;------------------------------------------------------------------------------
;
;<h> Reentrant Stack Initialization
;
;  The following EQU statements define the stack pointer for reentrant
;  functions and initialized it:
;
; <h> Stack Space for reentrant functions in the SMALL model.
;  <q> IBPSTACK: Enable SMALL model reentrant stack
;     <i> Stack space for reentrant functions in the SMALL model.
IBPSTACK        EQU     0       ; set to 1 if small reentrant is used.
;  <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
;     <i> Set the top of the stack to the highest location.
IBPSTACKTOP     EQU     0xFF +1     ; default 0FFH+1  
; </h>
;
; <h> Stack Space for reentrant functions in the LARGE model.      
;  <q> XBPSTACK: Enable LARGE model reentrant stack
;     <i> Stack space for reentrant functions in the LARGE model.
XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
;  <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
;     <i> Set the top of the stack to the highest location.
XBPSTACKTOP     EQU     0xFFFF +1   ; default 0FFFFH+1 
; </h>
;
; <h> Stack Space for reentrant functions in the COMPACT model.    
;  <q> PBPSTACK: Enable COMPACT model reentrant stack
;     <i> Stack space for reentrant functions in the COMPACT model.
PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
;
;   <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
;     <i> Set the top of the stack to the highest location.
PBPSTACKTOP     EQU     0xFF +1     ; default 0FFH+1  
; </h>
;</h>
;------------------------------------------------------------------------------
;
;  Memory Page for Using the Compact Model with 64 KByte xdata RAM
;  <e>Compact Model Page Definition
;
;  <i>Define the XDATA page used for PDATA variables. 
;  <i>PPAGE must conform with the PPAGE set in the linker invocation.
;
; Enable pdata memory page initalization
PPAGEENABLE     EQU     0       ; set to 1 if pdata object are used.
;
; <o> PPAGE number <0x0-0xFF> 
; <i> uppermost 256-byte address of the page used for PDATA variables.
PPAGE           EQU     0
;
; <o> SFR address which supplies uppermost address byte <0x0-0xFF> 
; <i> most 8051 variants use P2 as uppermost address byte
PPAGE_SFR       DATA    0A0H
;
; </e>
;------------------------------------------------------------------------------

; Standard SFR Symbols 
ACC     DATA    0E0H
B       DATA    0F0H
SP      DATA    81H
DPL     DATA    82H
DPH     DATA    83H

                NAME    ?C_STARTUP


?C_C51STARTUP   SEGMENT   CODE
?STACK          SEGMENT   IDATA

                RSEG    ?STACK
                DS      1

                EXTRN CODE (?C_START)
                PUBLIC  ?C_STARTUP

                CSEG    AT      0
?C_STARTUP:     LJMP    STARTUP1

                RSEG    ?C_C51STARTUP

STARTUP1:

IF IDATALEN <> 0
                MOV     R0,#IDATALEN - 1
                CLR     A
IDATALOOP:      MOV     @R0,A
                DJNZ    R0,IDATALOOP
ENDIF

IF XDATALEN <> 0
                MOV     DPTR,#XDATASTART
                MOV     R7,#LOW (XDATALEN)
  IF (LOW (XDATALEN)) <> 0
                MOV     R6,#(HIGH (XDATALEN)) +1
  ELSE
                MOV     R6,#HIGH (XDATALEN)
  ENDIF
                CLR     A
XDATALOOP:      MOVX    @DPTR,A
                INC     DPTR
                DJNZ    R7,XDATALOOP
                DJNZ    R6,XDATALOOP
ENDIF

IF PPAGEENABLE <> 0
                MOV     PPAGE_SFR,#PPAGE
ENDIF

IF PDATALEN <> 0
                MOV     R0,#LOW (PDATASTART)
                MOV     R7,#LOW (PDATALEN)
                CLR     A
PDATALOOP:      MOVX    @R0,A
                INC     R0
                DJNZ    R7,PDATALOOP
ENDIF

IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)

                MOV     ?C_IBP,#LOW IBPSTACKTOP
ENDIF

IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)

                MOV     ?C_XBP,#HIGH XBPSTACKTOP
                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
                MOV     ?C_PBP,#LOW PBPSTACKTOP
ENDIF

                MOV     SP,#?STACK-1

; This code is required if you use L51_BANK.A51 with Banking Mode 4
;<h> Code Banking
; <q> Select Bank 0 for L51_BANK.A51 Mode 4
#if 0   
;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
EXTRN CODE (?B_SWITCH0)
                CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0
#endif
;</h>
                LJMP    ?C_START

                END




IR-stc89C54.c

IR-stc89C54.c


/*************************************************************************
*工程名称:红外发射-解码-遥控学习一体模块                                *
*单片机型号:STC89C54RD+                                                 *
*晶振频率:12MHz	        												 *
*内部EEPROM有90个扇区,每个扇区512个字节,本程序只用12个扇区,           *
*解码格式为:NEC红外编码  红外解码最好有个1S的解码间隔                   *
*其他未能解码的红外编码脉冲均被完整复制,可以直接学习并控制相应设备		 *
*最大存储红外编码位数:120位(含一位起始脉冲)							 *
*作者:新兴光电                                                          *
*日期:2015-1-6                                                          *
*************************************************************************/

//#include <reg52.h>      //下面已经有一个STC的头文件了,51的就不用加上了 
#include "STC89C5xRC.H"
#include <intrins.h> 
#include "LCD1602.h"
#include "EEPROM.h"	 

#define uchar unsigned char
#define uint unsigned int

//sfr T2CON  = 0xC8;          //定时器2控制寄存器 
//sfr RCAP2L = 0xCA;			//定时器/计数器2重装/捕获低位
//sfr RCAP2H = 0xCB;			//定时器/计数器2重装/捕获高位
//sfr TL2    = 0xCC;
//sfr TH2    = 0xCD;
//单片机端口定义 
#define KEY_OUT P1      //4*3键盘信号输出端 
sbit KEY_send=P2^0;     //遥控功能按键 
sbit KEY_code=P2^1;    //遥控解码功能按键 
sbit KEY_study=P2^2;    //遥控学习功能按键 
sbit BEEP = P2^3;         //蜂鸣器驱动接口 
sbit IR_T=P2^4;         //红外线数据发送口 
sbit IR_R=P3^3;         //红外线数据接收口 
//以下为键盘扫描用到的寄存器 
uchar KEY_H_scan,KEY_V_check,KEY_value;  //KEY_H_scan为行扫描信号,KEY_V_check为列检测,KEY_value为最终键值
uchar KEY_temp;                          //键值缓存(存按键扫描子程序返回的键值)
uchar KEY;                               //键值处理子程序用到的定义键值的寄存器 
bit KEY_flag;                          //3-4键盘按键标志寄存器 
bit KEY_send_f;           //遥控功能按键的标志位
bit KEY_code_f;           //红外解码功能按键的标志位
bit KEY_study_f;          //遥控按键编码学习功能的标志位

static uchar LCD1602key[2];    //按键码显示动态缓存  
static uchar LCD1602temp[8];   //红外遥控码显示动态缓存 8个位的用户码 8个位的用户码 8个位的键码 8个位的键码反码  

uint EPROM_add_H,EPROM_add_L;         //EEPROM地址寄存器   

//以下为红外发射/接收/解码用到的寄存器 
uint n,i;
static uchar IR_data[4];             //红外编码数据 
bit IR_receive_OK;        //红外数据接收完毕标志 
bit IR_receive_end;       //红外解码结束标志位
static uint xdata FH[120];   //存脉冲宽度高电平数据用 	 含一位起始位
static uint xdata FL[120];   //存脉冲宽度低电平数据用 	  含一位起始位
	 
/*******1ms基准延时程序*******************/
void Delay1ms(uint t)    //1ms延时程序 
{
	uchar j;
	while(t--)
	{
		for(j=0;j<125;j++)
		{ ; }
	}
}
/****************************************/
/*****************峰鸣器子程序***************************/
void beep()
{
	uchar m;
	for (m=0;m<100;m++)
	{
		Delay1ms(1);
		BEEP=!BEEP;           //BEEP取反 
	} 
	BEEP=1;               //关闭蜂鸣器 
}
/********************************************************/
/*****************EEPROM读一个组按键编码子程序******************/
void EEPROM_read(uint R_add,uint *R_dat,uchar R_bit_count)     //读EEPROM中相应地址的数据 
{
    uchar k,R_dat_H,R_dat_L;
	for(k=0;k<R_bit_count;k++)
	{
		R_dat_H=Byte_Read(R_add);         //Byte_Read(add),读一EEPROM地址内数据的子程序  高位数据 
		R_add++;						  //地址加1 
		R_dat_L=Byte_Read(R_add);         //Byte_Read(add),读一EEPROM地址内数据的子程序  低位数据 
		R_add++;						  //地址加1
		*R_dat=(R_dat_H*0x100)+R_dat_L;   //数据整合 
		//*R_dat=(R_dat_H<<8)+R_dat_L;      //或者这样数据整合 
		R_dat++;
	}
}
/*******************************************************/
/******************EEPROM写一组按键编码子程序***********/
void EEPROM_write(uint W_add,uint *W_dat,uchar W_bit_count)    //向EEPROM相应地址写入数据 
{
	uchar w1,W_dat_H,W_dat_L;
	Sector_Erase(W_add);     //先擦除扇区 
	for(w1=0;w1<W_bit_count;w1++)
	{  
        W_dat_H=(uchar)(*W_dat>>8);	  //高位字节 
		Byte_Program(W_add,W_dat_H);    //给相应扇区写入数据  高位字节 
		W_add++;					  //存储地址加1 
		W_dat_L=(uchar)(*W_dat&0xff);	  //低位字节 
		Byte_Program(W_add,W_dat_L);    //给相应扇区写入数据  低位字节 
		W_add++;					  //存储地址加1
		W_dat++;
	}
}
/*******************************************************************/
/************定时器中断T1的服务程序***************/
void time_intt1(void) interrupt 3//定时器中断T1
{
	IR_T=~IR_T;	             //当IR_T为低电平时,红外发射处于工作状态,
                             //会发出红外信号;当送入的为高电平时,红外发射不工作。 
}
/*************************************************/
/****************红外发射初始化程序*************************/
void IR_send_init(void)
{
	IR_T=1;//关红外输出 
	TMOD=0x21;//设置定时器1为8位自动重装模式和定时器0为16位模式  
	TR0=0;
	TH1=0xf3;//红外载波40khz初值  	12MHz
	TL1=0xf3;
	TR1=0;
	EA=1;
}
/***********************************************************/
/*****************红外发射程序******************************/
void IR_send_dat(void)
{
    if(FH[0]==0x0000||FH[0]==0xFFFF)	//无红外数据 
	{
	    goto end2;
	}
	n=0;	
	TH0=~FL[n]/256;
	TL0=~FL[n]%256; 			
	ET1=1;TR1=1;//	   产生脉冲 
	TF0=0;
	TR0=1;
	IR_T=0;   //开红外输出口 
	while(TF0==0);		  //起始脉冲 
	TR0=0;
	TF0=0;
	ET1=0;TR1=0;//	   不产生脉冲 
	IR_T=1;   //关闭红外输出 
	
	TH0=~FH[n]/256;
	TL0=~FH[n]%256;		  
	TR0=1;
	while(TF0==0); 
	TR0=0;
	TF0=0;
	n++;
	while(1)			   //发红外数据 
	{	  			  
		TH0=~FL[n]/256;
		TL0=~FL[n]%256;
		ET1=1;TR1=1;//	   产生脉冲 
		TR0=1;
	    IR_T=0;   //开红外输出口 
		while(TF0==0);
		TR0=0;
		TF0=0;
		ET1=0;TR1=0;//	   不产生脉冲 
		IR_T=1;   //关闭红外输出 
		TH0=~FH[n]/256;
		TL0=~FH[n]%256;
		TR0=1;
		while(TF0==0); 
		TR0=0;
		TF0=0;
		if(FH[n]==0x0000)
		{  
			goto end2;						
		}
		n++;
	}
	end2:  n=0; 
		   IR_T=1;   //关闭红外输出 
		   TR0=0;
		   TF0=0;
		   TH0=0x00;
	       TL0=0x00;
		   TR1=0;
		   ET1=0;  //定时器1中断 关 
	       EA=1;
}
/*************************************************************/
/********************红外解码初始化设置程序***********************/
void IR_receive_init(void)     
{
	for(i=0;i<120;i++)//清内存 
	{
		FH[i]=0x0000;
		FL[i]=0x0000;
	}	  
	IR_R=1;	 //红外数据接收口  置高电平 		  			
	TMOD=0x10;//设置定时器1为16位模式 
	TH1=0x00;
	TL1=0x00;
	TF1=0;
	TR1=0;    //关闭定时器1 
	ET1=0;
	IT1=1;   //外部中断1,脉冲触发方式,负跳变有效 
	EX1=1;   //外中断允许 	  
	EA=1;    //开总中断 

}
/*************************************************************/
/***********************红外数据接收程序************************/
void int1() interrupt 2         //外部中断1处理程序 
{
	EX1=0;		//关外部中断1
    IT1=0;      //外部中断1低电平触发 
	n=0;
	//EA=0;	  	//关总中断 	
	TF1=0;
	TR1=1;   //启动定时器 
	while(IR_R==0);	 //低电平 
	TR1=0;
	FL[n]=TH1*256+TL1;  //起始位低电平脉宽宽度测量 
	TH1=0x00;
	TL1=0x00;
	TF1=0;
	TR1=1;
	while(IR_R==1);	  //高电平 
	TR1=0;
	FH[n]=TH1*256+TL1;  //起始位高电平脉宽宽度测量	
	n++;	    
	 while(1)
	 {
		TH1=0x00;
		TL1=0x00;
		TF1=0;
		TR1=1;
		while(IR_R==0);	 //低电平 
		TR1=0;
		FL[n]=TH1*256+TL1;	//数据位低电平脉宽宽度测量 
		while(IR_R==0);   //确定接收完 
		TH1=0x00;
		TL1=0x00;
		TF1=0;
		TR1=1;		
        while(IR_R==1)	 //高电平 
		{
			if(TH1>0x80)	 //32ms
			{
			  IR_receive_OK=1;		 //接收完毕标志位
			  goto end; 
			} 	   	
		} 

		TR1=0;
		FH[n]=TH1*256+TL1;	//数据位高电平脉宽宽度测量 
		while(IR_R==1);	 //确定接收完 
		n++;		//FH和FL共用一个 n
    } 	
   end:		TR1=0;			  //关定时器1        	
		    FH[n]=0x0000;
			n=0;
			TF1=0;
			TH1=0x00;
			TL1=0x00;
			//EX1=1;			  //开外部中断1 
			//EA=1;  	   
}
/*********************************************************************/
/*****************************红外数据解码程序************************/
void IR_code(void)
{
    uchar a,b,c,value;
	a=0;
    if(FL[0]>8500&&FL[0]<9500&&FH[0]>4000&&FH[0]<5000)  //NEC格式编码  8.5-9.5ms高电平和4-5ms低电平   12MHz晶振 
	{
		a++;			 //定位值  定位至脉冲数据 
		for(b=0;b<4;b++)		//4字节NEC数据 
		{
			for(c=0;c<8;c++)
			{
				value=value>>1;			  //数据右移一位
				if(FH[a]<1750&&FH[a]>700)   //判断高低电平  0.7-1.75  11.0592MHz晶振时间不一样 	  1.3-1.8ms
				{
					value=value|0x80; 	//该位为高电平 	记'1'
				}
				a++;
			}
			IR_data[b]=value;
		}
		    IR_receive_end=1;  //解码结束标志	  
	}		  
	else if(FL[a]>689&&FL[a]<1089&&FH[a]>689&&FH[a]<1089)  //其他格式格式编码  0.689-1.089ms  高电平和  低电平 
	{
		a++;			 //定位值  定位至脉冲数据 
		for(b=0;b<4;b++)		//4字节NEC数据 
		{
			for(c=0;c<8;c++)
			{
				value=value>>1;			  //数据右移一位
				if(FH[a]<1612&&FH[a]>645)   //判断高低电平  0.7-1.75ms     11.0592MHz晶振时间不一样 
				{
					value=value|0x80; 	//该位为高电平 	记'1'
				}
				a++;
			}
			IR_data[b]=value;
		}
		IR_receive_end=1;  //解码结束标志 
	} 	
	else			  //都没有 
	{
	    a=0;
		a++;			 //定位值  定位至脉冲数据 
		for(b=0;b<4;b++)		//4字节NEC数据 
		{
			for(c=0;c<8;c++)
			{
				value=value>>1;			  //数据右移一位
				if(FH[a]>1750)   //判断高低电平  1.75ms     11.0592MHz晶振时间不一样 
				{
					value=value|0x80; 	//该位为高电平 	记'1'
				}
				a++;
			}
			IR_data[b]=value;
		}
		IR_receive_end=1;  //解码结束标志 
	} 	  
}
/*********************************************************************/
/*******************功能按键扫描程序**********************************/
void SET_KEY_choose(void)
{
	if(KEY_send==0)        //红外遥控器功能 
	{
    	Delay1ms(100);
		if(KEY_send==0)
		{
			KEY_code_f=0;
			KEY_study_f=0;
			KEY_send_f=1;
			TR1=0;	//关闭定时器1
			EX1=0;	//关闭外部中断1中断 
			IT1=0;	//触发方式 清0
         GotoXY(0,0);    //lcd1602第一行,第一个位置   x,y  x列   y行
         Print("  IR KEY Send   ");  
         GotoXY(0,1); 
         Print("KEY--:-------- H"); 
		}
	}
	if(KEY_code==0)       //红外解码功能	  
	{
	   Delay1ms(100);
		if(KEY_code==0)
		{
			KEY_send_f=0; 
			KEY_study_f=0;
			KEY_code_f=1;
			EX1=0;  //关闭外部中断1中断 
			TR1 =0;	//关闭定时器0
			TR0 =0;	//关闭定时器0
			ET1=0;	//关闭定时器0中断 
			GotoXY(0,0); 
			Print("  IR KEY code   ");  
			GotoXY(0,1); 
			Print("   -------- H   ");
			IR_receive_init();   //红外解码设置程序	 
		}
   }
	if(KEY_study==0)      //红外遥控按键学习功能	   
	{
	   Delay1ms(100);
		if(KEY_study==0)
		{
			KEY_code_f=0;
			KEY_send_f=0; 
			KEY_study_f=1;
			TR0=0;	//关闭定时器0
		//	ET0=0;	//关闭定时器0中断 
            TR1=0;  //关闭定时器1
			ET1=0;  //关闭定时器1中断	    
			EX1=0;  //关闭外部中断1
         GotoXY(0,0); 
         Print("  IR KEY Study  ");  
         GotoXY(0,1); 
         Print("KEY--:-------- H");
		}
   }
}
/*************************************************************************/

/*******4*3键盘扫描及键值确定程序********/
uchar keyscan(void)                        //每个按键编码是从矩阵键盘左上角开始编码的,是我们事先定好的:0x11(0键) 0x21(1键) 。。。。0x88(F键即第16键)
{
	KEY_OUT=0xf0;        //设置键盘行线(低四位)为低电平,列线(高四位)为高电平
	KEY_V_check=KEY_OUT&0xf0;        //第一次读按键检测状态(若有按键按下,列线(高四位)其中有一位定为低电平
	if(KEY_V_check!=0xf0){
		Delay1ms(100);               //若有按键按下,延时10ms(防按键抖动)
		KEY_V_check=KEY_OUT&0xf0;   //第二次当有按键按下时,列信号就已经定了!读列检测(按键)状态:0xe0(第一列),0xd0(第二列),0xb0(第三列),0x70(第四列,本程序无第4列)      
			if(KEY_V_check!=0xf0){     //若有闭合键,则逐行扫描
				KEY_H_scan=0xfe;       //扫第一行  行扫描码分别为0xfe(第一行),0xfd(第二行),0xfb(第三行),0xf7(第四行)
				while((KEY_H_scan&0x10)!=0){    //若扫描码为0xef(此值为第五行值,当测到第五行,扫描停止),则结束扫描
					KEY_OUT=KEY_H_scan;          //输出行扫描码  相当于  "当前按键按下时的键值|行扫描值=新的值"相当于作或运算
					KEY_V_check=KEY_OUT&0xf0;    //读列检测数据:0xe0,0xd0,0xb0,0x70  将上一步的值送给列检测
					if(KEY_V_check!=0xf0){       //本行有闭合键  若等于0xf0说明按下的键不在本行,跳到下一命令,行值左移,扫描下一行
						KEY_value=(~KEY_H_scan)+(~(KEY_V_check|0x0f));   //计算键值  由于前面已经确定好了列值,可以计算键值
						KEY_flag=1;    //按键标志位
						return(KEY_value);
						}
					else KEY_H_scan=(KEY_H_scan<<1)|0x01;   //行扫描左移一位,准备扫描下一行
				}
			}
	}
	return(0x00);
}		  
/*****************************************/
/***********************键值处理程序*************************/  
void KEY_choose(uchar tmp)              //3-4键盘处理子程序	 
{
	switch(tmp){
		case 0x11:  KEY=1;      //按键1
	                EPROM_add_H=flash_1;           //EEPROM第一扇区初始地址 
					EPROM_add_L=flash_2;		   //EEPROM第二扇区初始地址 
						break;    
		case 0x21:  KEY=2;      //按键2	 
	                EPROM_add_H=flash_3;           //EEPROM第三扇区初始地址 
					EPROM_add_L=flash_4;		   //EEPROM第四扇区初始地址  
						break;    
		case 0x41:  KEY=3;      //按键3  
	                EPROM_add_H=flash_5;           //EEPROM第五扇区初始地址 
					EPROM_add_L=flash_6;		   //EEPROM第六扇区初始地址  
						break;		
		case 0x12:  KEY=4;      //按键4 	   
	                EPROM_add_H=flash_7;           //EEPROM第七扇区初始地址 
					EPROM_add_L=flash_8;		   //EEPROM第八扇区初始地址 
						break;    
		case 0x22:  KEY=5;      //按键5 
	                EPROM_add_H=flash_9;           //EEPROM第九扇区初始地址 
					EPROM_add_L=flash_10;		   //EEPROM第十扇区初始地址
						break;    
		case 0x42:  KEY=6;      //按键6 
	                EPROM_add_H=flash_11;           //EEPROM第十一扇区初始地址 
					EPROM_add_L=flash_12;		   //EEPROM第十二扇区初始地址  
						break;  		
		case 0x14:  KEY=7;      //按键7
	                EPROM_add_H=flash_13;           //EEPROM第十三扇区初始地址 
					EPROM_add_L=flash_14;		   //EEPROM第十四扇区初始地址 
						break;    
		case 0x24:  KEY=8;      //按键8
	                EPROM_add_H=flash_15;           //EEPROM第十五扇区初始地址 
					EPROM_add_L=flash_16;		   //EEPROM第十六扇区初始地址
						break;    
		case 0x44:  KEY=9;      //按键9 
	                EPROM_add_H=flash_17;           //EEPROM第十七扇区初始地址 
					EPROM_add_L=flash_18;		   //EEPROM第十八扇区初始地址 
						break; 		
		case 0x18:  KEY=10;      //按键10
	                EPROM_add_H=flash_19;           //EEPROM第十九扇区初始地址 
					EPROM_add_L=flash_20;		   //EEPROM第二十扇区初始地址 
						break;    
		case 0x28:  KEY=11;     //按键11
	                EPROM_add_H=flash_21;           //EEPROM第二十一扇区初始地址 
					EPROM_add_L=flash_22;		   //EEPROM第二十二扇区初始地址	 
						break;   
		case 0x48:  KEY=12;     //按键12
	                EPROM_add_H=flash_23;           //EEPROM第二十三扇区初始地址 
					EPROM_add_L=flash_24;		   //EEPROM第二十四扇区初始地址	 
						break;     
		default: break;
	} 
}
/********************************************************/
/*****************字符数值转换以适于显示*********************/
void IntToStr(uchar k,uchar *buf)    //字符数值的10进制显示
{
	uchar h,j, a[2];
	
	a[0]=(k/10)%10;                                       	
	a[1]=(k/1)%10;
	for(h=0; h<2; h++)         //转成ASCII码              	
	a[h]=a[h]+'0';                                    	
	for(h=0; a[h]=='0' && h<=1; h++);                     	
	for(j=0; j<h; j++)       //填充指定字符                 	
	{ *buf='-';  buf++; }                             	
	for(; h<2; h++)                                       	
	{ *buf=a[h]; buf++; }    //加入有效的数字           	
	*buf='\0'; 

 
} 
/************************************************************/
/***********************字符数值转换以适于lcd1602显示***********/
void HtoStr(uchar *buf,uchar *dis)      //字符的16进制显示
{
   uchar to,DH,DL;

//   IRCOM[5]=IRCOM[2] & 0x0F;     //取键码的低四位
//   IRCOM[6]=IRCOM[2] >> 4;       //右移4次,高四位变为低四位
   
   for(to=0;to<4;to++)
	{
  
		DL=*buf&0x0F;     //取低四位用户码  
      DH=*buf>>4;      //右移4次,高四位变为低四位
	   if(DH>9)
	    { *dis=DH+0x37;}    //选0x37是调整以显示  根据1602内部ASCII码得出的
	   else
		 { *dis=DH+0x30;}    //选0x30是调整以显示  根据1602内部ASCII码得出的
      dis++;
   	  if(DL>9)
	    { *dis=DL+0x37;}    //选0x37是调整以显示  根据1602内部ASCII码得出的
	   else
		 { *dis=DL+0x30;}    //选0x30是调整以显示  根据1602内部ASCII码得出的
      dis++;
      buf++;
	}
}
/***************************************************************/
/*****************字符数值转换以适于显示*********************
void IntToStr(uchar k,uchar *buf) 
{
  *buf[0]=KEY/10+'0';
  *buf[1]=KEY%10+'0';
} 
************************************************************/
void main(void)
{	
    LcdRs=0;
	LcdRw=0;
	LcdEn=0;
	P0=0x00;
	IR_T=1;    //关闭红外发射管 
	KEY_send=1;
	KEY_code=1;
	KEY_study=1;
	KEY_flag=0;
	KEY_send_f=1;
	KEY_code_f=0;
	KEY_study_f=0;
	LCD1602_init();
	GotoXY(0,0);    //lcd1602第一行,第一个位置   x,y  x列   y行
	Print("  IR KEY Send   ");  
	GotoXY(0,1); 
	Print("KEY--:-------- H");
	for(i=0;i<120;i++)//清红外编码数据内存 
	{
		FH[i]=0x0000;
		FL[i]=0x0000;
	}
	while(1)
	{
		SET_KEY_choose();     //功能键按键扫描子程序 
		if(KEY_send_f)	 //遥控器功能 
		{
//      	    TR1=0;  //关闭定时器1
//			ET1=0;  //关闭定时器1中断 
//			EX1=0;  //关闭外部中断1
//			EA=0;   //关闭总中断 
				KEY_temp=keyscan();     //3-4键盘扫描程序  
				KEY_choose(KEY_temp);   //3-4键值处理程序 
				if(KEY_flag)       //3-4键盘标志位  为1表示有按键按下 
				{
		            KEY_flag=0;
					//TR0=0;
					//ET0=0;
					//EA=0;
					beep();   //峰鸣器  
					EEPROM_read(EPROM_add_H,&FH[0],120);	 //从EPROM扇区读取红外数据 
					EEPROM_read(EPROM_add_L,&FL[0],120);
					IR_code();  //数据解码 	
					IR_receive_end=0;  //解码结束标志 清0			 
					IntToStr(KEY,&LCD1602key[0]); //按键值转换用于显示 
					HtoStr(&IR_data[0],&LCD1602temp[0]);   //红外数据转换用于显示 
					LCD1602_Print(3,1,&LCD1602key[0]);   //第二行,第4个字符显示,动态数据(按键值)
					LCD1602_Print(6,1,&LCD1602temp[0]);   //第二行,第7个字符显示,动态数据(遥控编码)
					IR_send_init();  //红外发射初始化程序 
					IR_send_dat();   //红外发射程序 
					ET1=0;
					TR1=0;
					TR0=0;
					TH0=0x00;
					TL0=0x00;
					EA=1;
				}
		}			 

		if(KEY_code_f)	 //遥控解码功能 
		{		
			if(IR_receive_OK)
			{
				IR_receive_OK=0;
				IR_code();    //红外数据解码 
			}
			if(IR_receive_end)
			{
				IR_receive_end=0;
				TR1=0;
				ET1=0;
				EX1=0;
				//EA=0;
				HtoStr(&IR_data[0],&LCD1602temp[0]);   //数据转换以适于显示   数据寄存器,显示寄存器
				LCD1602_Print(3,1,&LCD1602temp[0]);   //第二行,第4个字符显示,动态数据(遥控编码)
                beep();   //峰鸣器 
                IR_receive_init();   //再次启动红外解码设置程序,等待下一次解码 
			}
        }

		if(KEY_study_f)		//遥控学习功能 
		{
			KEY_temp=keyscan();  //按键扫描 
			KEY_choose(KEY_temp);  //按键处理  
			if(KEY_flag)     //3-4键盘按键标志位
			{
		        KEY_flag=0;
				IntToStr(KEY,&LCD1602key[0]); //按键值转换以显示
				LCD1602_Print(3,1,&LCD1602key[0]);   //第二行,第4个字符显示,动态数据(按键值)	
				GotoXY(6,1);                  //当重新有按键按下后,重新显示
				Print("--------");		
				IR_receive_init();   //红外解码设置程序	 
			}
			if(IR_receive_OK)
			{
				IR_receive_OK=0;
				IR_code();    //红外数据解码  
			}
			if(IR_receive_end)
			{
				IR_receive_end=0;
				TR1=0;
				EX1=0;
				EA=0;
				EEPROM_write(EPROM_add_H,&FH[0],120);     //保存红外数据至扇区 
				EEPROM_write(EPROM_add_L,&FL[0],120);     //保存红外数据至扇区 
		        HtoStr(&IR_data[0],&LCD1602temp[0]);       //数据转换以显示  红外数据寄存器,显示寄存器 
				LCD1602_Print(6,1,&LCD1602temp[0]);   //第二行,第7个字符显示,动态数据(遥控编码)
                beep();   //峰鸣器 
			}
		}
	}
}  
/*********************************************************/

/****************************************
T2CON (C8H)
7      6        5       4       3       2       1         0
TF2	  EXF2	  RCLK	   TCLK	   EXEN2	TR2   	C/T2	 CP/RL2
EXF2:定时器2外部标志。为1将使CPU从中断向量处执行定时器2中断程序 
RCLK:接收时钟标志。为1时,定时器2的溢出作为串行模式1和模式3的接收时钟。
	 为0时,定时器1的溢出作为串行模式1和模式3的接收时钟 
TCLK:发送时钟标志。为1时,定时器2的溢出作为串行模式1和模式3的发送时钟。
	 为0时,定时器1的溢出作为串行模式1和模式3的发送时钟 
EXEN2:定时器2外部使能标志。
C/T2:定时器/计数器选择。0为内部定时器 1外部事件计数器(下降沿触发) 
CP/RL2:捕获/重装标志。当RCLK=1或TCLK=1时,该位无效,定时器强制为溢出时自动重装 
*******************************************/




STC89C5xRC.H

STC89C5xRC.H






#ifndef __STC89C5xRC_RDP_H_
#define __STC89C5xRC_RDP_H_

/////////////////////////////////////////////////

/* The following is STC additional SFR */

/* sfr  AUXR  = 0x8e; */
/* sfr  AUXR1 = 0xa2; */
/* sfr  IPH   = 0xb7; */

sfr  P4  = 0xe8;
sbit P43 = P4^3;
sbit P42 = P4^2;
sbit P41 = P4^1;
sbit P40 = P4^0;

sfr  XICON = 0xc0;

sfr  WDT_CONTR = 0xe1;

sfr ISP_DATA  = 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr ISP_CMD   = 0xe5;
sfr ISP_TRIG  = 0xe6;
sfr ISP_CONTR = 0xe7;

/* Above is STC additional SFR */

/*--------------------------------------------------------------------------
REG51F.H

Header file for 8xC31/51, 80C51Fx, 80C51Rx+
Copyright (c) 1988-1999 Keil Elektronik GmbH and Keil Software, Inc.
All rights reserved.

Modification according to DataSheet from April 1999
 - SFR's AUXR and AUXR1 added for 80C51Rx+ derivatives
--------------------------------------------------------------------------*/

/*  BYTE Registers  */
sfr P0   = 0x80;
sbit P00 = P0^0;
sbit P01 = P0^1;
sbit P02 = P0^2;
sbit P03 = P0^3;
sbit P04 = P0^4;
sbit P05 = P0^5;
sbit P06 = P0^6;
sbit P07 = P0^7;
sfr P1   = 0x90;
sbit P10 = P1^0;
sbit P11 = P1^1;
sbit P12 = P1^2;
sbit P13 = P1^3;
sbit P14 = P1^4;
sbit P15 = P1^5;
sbit P16 = P1^6;
sbit P17 = P1^7;
sfr P2   = 0xA0;
sbit P20 = P2^0;
sbit P21 = P2^1;
sbit P22 = P2^2;
sbit P23 = P2^3;
sbit P24 = P2^4;
sbit P25 = P2^5;
sbit P26 = P2^6;
sbit P27 = P2^7;
sfr P3   = 0xB0;
sbit P30 = P3^0;
sbit P31 = P3^1;
sbit P32 = P3^2;
sbit P33 = P3^3;
sbit P34 = P3^4;
sbit P35 = P3^5;
sbit P36 = P3^6;
sbit P37 = P3^7;
sfr PSW  = 0xD0;
sfr ACC  = 0xE0;
sfr B    = 0xF0;
sfr SP   = 0x81;
sfr DPL  = 0x82;
sfr DPH  = 0x83;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0  = 0x8A;
sfr TL1  = 0x8B;
sfr TH0  = 0x8C;
sfr TH1  = 0x8D;
sfr IE   = 0xA8;
sfr IP   = 0xB8;
sfr SCON = 0x98;
sfr SBUF = 0x99;

/*  80C51Fx/Rx Extensions  */
sfr AUXR   = 0x8E;
sfr AUXR1  = 0xA2;
sfr SADDR  = 0xA9;
sfr IPH    = 0xB7;
sfr SADEN  = 0xB9;
sfr T2CON  = 0xC8;
sfr T2MOD  = 0xC9;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2    = 0xCC;
sfr TH2    = 0xCD;

/* PCA SFR
sfr CCON   = 0xD8;
sfr CMOD   = 0xD9;
sfr CCAPM0 = 0xDA;
sfr CCAPM1 = 0xDB;
sfr CCAPM2 = 0xDC;
sfr CCAPM3 = 0xDD;
sfr CCAPM4 = 0xDE;
sfr CL     = 0xE9;
sfr CCAP0L = 0xEA;
sfr CCAP1L = 0xEB;
sfr CCAP2L = 0xEC;
sfr CCAP3L = 0xED;
sfr CCAP4L = 0xEE;
sfr CH     = 0xF9;
sfr CCAP0H = 0xFA;
sfr CCAP1H = 0xFB;
sfr CCAP2H = 0xFC;
sfr CCAP3H = 0xFD;
sfr CCAP4H = 0xFE;
*/

/*  BIT Registers  */
/*  PSW   */
sbit CY   = PSW^7;
sbit AC   = PSW^6;
sbit F0   = PSW^5;
sbit RS1  = PSW^4;
sbit RS0  = PSW^3;
sbit OV   = PSW^2;
sbit P    = PSW^0;

/*  TCON  */
sbit TF1  = TCON^7;
sbit TR1  = TCON^6;
sbit TF0  = TCON^5;
sbit TR0  = TCON^4;
sbit IE1  = TCON^3;
sbit IT1  = TCON^2;
sbit IE0  = TCON^1;
sbit IT0  = TCON^0;

/*  IE   */
sbit EA   = IE^7;
sbit EC   = IE^6;
sbit ET2  = IE^5;
sbit ES   = IE^4;
sbit ET1  = IE^3;
sbit EX1  = IE^2;
sbit ET0  = IE^1;
sbit EX0  = IE^0;

/*  IP   */ 
/*  sbit PPC  = IP^6;*/
sbit PT2  = IP^5;
sbit PS   = IP^4;
sbit PT1  = IP^3;
sbit PX1  = IP^2;
sbit PT0  = IP^1;
sbit PX0  = IP^0;

/*  P3  */
sbit RD   = P3^7;
sbit WR   = P3^6;
sbit T1   = P3^5;
sbit T0   = P3^4;
sbit INT1 = P3^3;
sbit INT0 = P3^2;
sbit TXD  = P3^1;
sbit RXD  = P3^0;

/*  SCON  */
sbit SM0  = SCON^7; // alternatively "FE"
sbit FE   = SCON^7;
sbit SM1  = SCON^6;
sbit SM2  = SCON^5;
sbit REN  = SCON^4;
sbit TB8  = SCON^3;
sbit RB8  = SCON^2;
sbit TI   = SCON^1;
sbit RI   = SCON^0;
             
/*  P1  */
/* PCA
sbit CEX4 = P1^7;
sbit CEX3 = P1^6;
sbit CEX2 = P1^5;
sbit CEX1 = P1^4;
sbit CEX0 = P1^3;
sbit ECI  = P1^2;
*/

sbit T2EX = P1^1;
sbit T2   = P1^0;

/*  T2CON  */
sbit TF2   = T2CON^7;
sbit EXF2  = T2CON^6;
sbit RCLK  = T2CON^5;
sbit TCLK  = T2CON^4;
sbit EXEN2 = T2CON^3;
sbit TR2   = T2CON^2;
sbit C_T2  = T2CON^1;
sbit CP_RL2= T2CON^0;

/*  CCON  */
/*  PCA
sbit CF    = CCON^7;
sbit CR    = CCON^6;

sbit CCF4  = CCON^4;
sbit CCF3  = CCON^3;
sbit CCF2  = CCON^2;
sbit CCF1  = CCON^1;
sbit CCF0  = CCON^0;
*/

/////////////////////////////////////////////////

#endif




intrins.h

intrins.h





/*--------------------------------------------------------------------------
INTRINS.H

Intrinsic functions for C51.
Copyright (c) 1988-2010 Keil Elektronik GmbH and ARM Germany GmbH
All rights reserved.
--------------------------------------------------------------------------*/

#ifndef __INTRINS_H__
#define __INTRINS_H__

#pragma SAVE

#if defined (__CX2__)
#pragma FUNCTIONS(STATIC)
/* intrinsic functions are reentrant, but need static attribute */
#endif

extern void          _nop_     (void);
extern bit           _testbit_ (bit);
extern unsigned char _cror_    (unsigned char, unsigned char);
extern unsigned int  _iror_    (unsigned int,  unsigned char);
extern unsigned long _lror_    (unsigned long, unsigned char);
extern unsigned char _crol_    (unsigned char, unsigned char);
extern unsigned int  _irol_    (unsigned int,  unsigned char);
extern unsigned long _lrol_    (unsigned long, unsigned char);
extern unsigned char _chkfloat_(float);
#if defined (__CX2__)
extern int           abs       (int);
#endif
#if !defined (__CX2__)
extern void          _push_    (unsigned char _sfr);
extern void          _pop_     (unsigned char _sfr);
#endif

#pragma RESTORE

#endif




LCD1602.h

LCD1602.h





/***************************************************************************
   File Name:       LCD1602.h
   Author:          xin xing guang dian
   Created:         2014/5/16
   Modified:		NO
   Revision: 		1.0  
***************************************************************************/

#ifndef _LCD1602_h
#define _LCD1602_h

#include <intrins.h>

//Port Definitions**********************************************************
sbit LcdRs		= P2^7;  //LCD寄存器选择  1 选数据寄存器  0 选指令寄存器
sbit LcdRw		= P2^6;  //LCD读/写操作  1 把LCM数据读到单片机  0 把单片机数据写入LCM
sbit LcdEn  	= P2^5;          //LCD使能端
sfr  DBPort 	= 0x80;		//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口  sfr程序状态字寄存器

//内部等待函数(判断忙碌标志位BF)BF由数据口D7表示**************************************************************************
unsigned char LCD1602_Wait(void)
{
	LcdRs=0;
	LcdRw=1;	_nop_();
	LcdEn=1;	_nop_();
while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,
						 //可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80
						 //实际硬件时打开此语句
	LcdEn=0;
	return DBPort;		
}
//向LCD1602写入命令或数据************************************************************
#define LCD1602_command	 0      // Command指令
#define LCD1602_data	 1      // Data数据
#define LCD1602_clear	0x01      // 清屏指令
#define LCD1602_return  0x02      // 光标返回原点
void LCD1602_Write(bit style, unsigned char input)
{
	LcdEn=0;
	LcdRs=style;
	LcdRw=0;		_nop_();
	DBPort=input;	_nop_();//注意顺序
	LcdEn=1;		_nop_();//注意顺序
	LcdEn=0;		_nop_();
	LCD1602_Wait();	
}

//设置显示模式************************************************************
#define LCD1602_open			0x04    //显示器开
#define LCD1602_close			0x00    //显示器关	  

#define LCD1602_cursor			0x02 	//显示光标
#define LCD1602_NO_cursor		0x00    //无光标		     

#define LCD1602_flash			0x01    //光标闪动
#define LCD1602_NO_flash		0x00    //光标不闪动

void LCD1602_SetDisplay(unsigned char DisplayMode)
{
	LCD1602_Write(LCD1602_command, 0x08|DisplayMode);	
}

//设置输入模式************************************************************
#define LCD1602_AC_UP			0x02      //地址计数器AC加1
#define LCD1602_AC_DOWN			0x00      // default

#define LCD1602_MOVE			0x01      // 画面可平移
#define LCD1602_NO_MOVE			0x00      //default默认画面不移动

void LCD1602_SetInput(unsigned char InputMode)
{
	LCD1602_Write(LCD1602_command, 0x04|InputMode);
}

//移动光标或屏幕************************************************************

#define LCD1602_cursor		0x02      
#define LCD1602_screen		0x08
#define LCD1602_left		0x00
#define LCD1602_right		0x04
void LCD1602_Move(unsigned char object, unsigned char direction)
{
	if(object==LCD1602_cursor)
		LCD1602_Write(LCD1602_command,0x10|direction);
	if(object==LCD1602_screen)
		LCD1602_Write(LCD1602_command,0x18|direction);
}

//初始化LCD1602************************************************************
void LCD1602_init()
{        
	LcdEn=0;
        _nop_();_nop_();_nop_();
	LCD1602_Write(LCD1602_command,0x38);           //8位数据端口,2行显示,5*7点阵
        _nop_();_nop_();_nop_();
	LCD1602_Write(LCD1602_command,0x38);
        _nop_();_nop_();_nop_();
	LCD1602_SetDisplay(LCD1602_open|LCD1602_NO_cursor);    //设置显示模式  开启显示, 无光标
        LCD1602_Write(LCD1602_command,LCD1602_clear);   //清屏	
	LCD1602_SetInput(LCD1602_AC_UP|LCD1602_NO_MOVE);       //设置输入模式  AC递增, 画面不动
        //LCD1602_Move(LCD1602_cursor,LCD1602_left);
}

//************************************************************************
void GotoXY(unsigned char x, unsigned char y)    //设置显示数据地址
{
	if(y==0)
		LCD1602_Write(LCD1602_command,0x80|x);          //第一行地址0x80+x
	if(y==1)
		LCD1602_Write(LCD1602_command,0x80|(x-0x40));   // 第二行地址0x80+(0x40+x)==0xc0+x
}
void Print(unsigned char *str)
{
	while(*str!='\0')        // \0  结束标志
	{
		LCD1602_Write(LCD1602_data,*str);
		str++;
	}
}

void LCD1602_Print(unsigned char x, unsigned char y, unsigned char *str)
{
  GotoXY(x,y);
  Print(str);
}


/*
void LCD1602_LoadChar(unsigned char user[8], unsigned char place)
{
	unsigned char i;
	LCD1602_Write(LCD1602_command,0x40|(place*8));
	for(i=0; i<8; i++)
		LCD1602_Write(LCD1602_data,user[i]);
}
*/
//************************************************************************
#endif


EEPROM.h

EEPROM.h





/****************************************************************************
    File Name: STC89C54RD+ EEPROM
    Author:    Xin Xing Guang Dian
    Created:   2015/1/7
    Modified:     NO
    Revision:     1.0
说明   :
    STC89C54RD+的第一扇区起始地址为0x4000
    需修改本程序
    其他芯片请参考手册
    本程序参考 宏晶公司提供的STC5Axx 系列 EEPROM 例子程序
****************************************************************************/

#ifndef _EEPROM_h
#define _EEPROM_h

#include <intrins.h>

typedef unsigned char INT8U;     //typedef 类型定义关键字
typedef unsigned int   INT16U;

//以下语句如果在主程序添加有STC相应型号的头文件则不用定义sfc(特殊功能寄存器)了,没有则要加
/******************EEPROM用到的sfr中的寄存器地址stc型号不同地址不同*****************************************/
sfr IAP_DATA    = 0xE2;   //IAP操作时的数据寄存器(从flash读数据和写数据都在此处)
sfr IAP_ADDRH   = 0xE3;   //IAP操作时的地址寄存器高8位
sfr IAP_ADDRL   = 0xE4;   // IAP操作时的地址寄存器低8位
sfr IAP_CMD     = 0xE5; //IAP命令模式寄存器(需命令触发寄存器触发方生效)3种模式
sfr IAP_TRIG    = 0xE6; //IAP命令触发寄存器,在IAP_CONTR.7=1时;对IAP_TRIG先写//入46h,再写入B9h,IAP命令生效
sfr IAP_CONTR   = 0xE7; //IAP控制寄存器

/***********定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数(属于IAP_CONTR寄存器)***********/
//#define ENABLE_ISP 0x80   //系统工作时钟<5MHz 时,对IAP_CONTR 寄存器设置此值
//#define ENABLE_ISP 0x81   //系统工作时钟<10MHz 时,对IAP_CONTR 寄存器设置此值
#define ENABLE_ISP 0x82     //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值
//#define ENABLE_ISP 0x83   //系统工作时钟<40MHz 时,对IAP_CONTR 寄存器设置此值

/***********STC系列EEPROM起始地址**************************************************************/
//#define DATA_FLASH_START_ADDRESS 0x2000 //STC89C51RC,STC89C52RC的EEPROM的第一扇区起始地址为0x2000
                                        //STC89C54RD+的EEPROM的第一扇区起始地址为0x8000,需修改本程序
                                        //其他芯片请参考手册

#define flash_1 0x4000               //STC89C54RD+的第一扇区起始地址为0x4000
#define flash_2 0x4200                //STC89C54RD+的第二扇区起始地址为0x4200
#define flash_3 0x4400                //STC89C54RD+的第三扇区起始地址为0x4400
#define flash_4 0x4600                //STC89C54RD+的第四扇区起始地址为0x4600
#define flash_5 0x4800                //STC89C54RD+的第五扇区起始地址为0x4800
#define flash_6 0x4A00                //STC89C54RD+的第六扇区起始地址为0x4A00
#define flash_7 0x4C00                //STC89C54RD+的第七扇区起始地址为0x4C00
#define flash_8 0x4E00                //STC89C54RD+的第八扇区起始地址为0x4E00
#define flash_9 0x5000               //STC89C54RD+的第九扇区起始地址为0x5000
#define flash_10 0x5200               //STC89C54RD+的第十扇区起始地址为0x5200
#define flash_11 0x5400               //STC89C54RD+的第十一扇区起始地址为0x5400
#define flash_12 0x5600               //STC89C54RD+的第十二扇区起始地址为0x5600  
#define flash_13 0x5800               //STC89C54RD+的第十三扇区起始地址为0x5800
#define flash_14 0x5A00               //STC89C54RD+的第十四扇区起始地址为0x5A00
#define flash_15 0x5C00               //STC89C54RD+的第十五扇区起始地址为0x5C00
#define flash_16 0x5E00               //STC89C54RD+的第十六扇区起始地址为0x5E00
#define flash_17 0x6000               //STC89C54RD+的第十七扇区起始地址为0x6000
#define flash_18 0x6200               //STC89C54RD+的第十八扇区起始地址为0x6200
#define flash_19 0x6400               //STC89C54RD+的第十九扇区起始地址为0x6400
#define flash_20 0x6600               //STC89C54RD+的第二十扇区起始地址为0x6600
#define flash_21 0x6800               //STC89C54RD+的第二十一扇区起始地址为0x6800
#define flash_22 0x6A00               //STC89C54RD+的第二十二扇区起始地址为0x6A00
#define flash_23 0x6C00               //STC89C54RD+的第二十三扇区起始地址为0x6C00
#define flash_24 0x6E00               //STC89C54RD+的第二十四扇区起始地址为0x6E00
/****************************************************
struct EEP_dat     //struct 结构体  
{
INT16U add;    //16位地址
INT8U dat;     //8位数据
}temp;
****************************************************/
/*****************************************************
void main()
{
EEPROM_Init();   //EEPROM初始化函数
while(1)
{
   P0=~count.dat;
   P1=~temp.dat;
   delayms(1000);
   count.dat++;
   temp.dat++;
   Sector_Erase(DATA_FLASH_START_ADDRESS);  //擦除扇区
   Byte_Program(count.add,count.dat); //字节编程
   Byte_Program(temp.add,temp.dat); //字节编程
}
}
*******************************************************/

/******************************************************
void EEPROM_Init()      
{

//count.add=0x2000;                //把EEPROM变量的地址现在这里定义好
//count.dat=Byte_Read(count.add);  //读一字节
//temp.add=0x2001;                 //把EEPROM变量的地址现在这里定义好
//temp.dat=Byte_Read(temp.add);    //读一字节
}
******************************************************/
/*************关闭IAP功能子程序*****************************/
void IAP_Disable()      //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
{                       //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关    
    IAP_CONTR = 0;      //关闭IAP 功能
    IAP_CMD   = 0;      //清命令寄存器,使命令寄存器无命令,此句可不用
    IAP_TRIG = 0;       //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
    IAP_ADDRH = 0;      //高八位地址清0
    IAP_ADDRL = 0;      //低八位地址清0
}

/**********EEPROM读一字节子程序***********************/
INT8U Byte_Read(INT16U add)      //读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
{
    IAP_DATA = 0x00;             //IAP数据寄存器清0
    IAP_CONTR = ENABLE_ISP;      //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x01;              //IAP/ISP/EEPROM 字节读命令

    IAP_ADDRH = (INT8U)(add>>8);    //设置目标单元地址的高8 位地址
    IAP_ADDRL = (INT8U)(add&0xff);    //设置目标单元地址的低8 位地址

    EA = 0;
    IAP_TRIG = 0x46;   //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xB9;   //送完 B9h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    EA = 1;
    IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                    //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
    return (IAP_DATA);
}


/************EEPROM字节编程子程序**************************/
void Byte_Program(INT16U add,INT8U ch)  //字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
{
    IAP_CONTR = ENABLE_ISP;         //打开 IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x02;                 //IAP/ISP/EEPROM 字节编程命令


    IAP_ADDRH = (INT8U)(add>>8);    //设置目标单元地址的高8 位地址
    IAP_ADDRL = (INT8U)(add&0xff);    //设置目标单元地址的低8 位地址

    IAP_DATA = ch;                  //要编程的数据先送进IAP_DATA 寄存器
    EA = 0;
    IAP_TRIG = 0x46;   //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xB9;   //送完 B9h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    EA = 1;
    IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                    //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}

/*************EEPROM擦除扇区子程序**************************/
void Sector_Erase(INT16U add)       //擦除扇区, 入口:DPTR = 扇区地址
{
    IAP_CONTR = ENABLE_ISP;         //打开IAP 功能, 设置Flash 操作等待时间
    IAP_CMD = 0x03;                 //IAP/ISP/EEPROM 扇区擦除命令

    IAP_ADDRH = (INT8U)(add>>8);    //设置目标单元地址的高8 位地址
    IAP_ADDRL = (INT8U)(add&0xff);    //设置目标单元地址的低8 位地址

    EA = 0;
    IAP_TRIG = 0x46;   //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
    IAP_TRIG = 0xB9;   //送完 B9h 后,ISP/IAP 命令立即被触发起动
    _nop_();
    EA = 1;
    IAP_Disable();     //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
                       //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}



/********************************
void delayms(INT16U z)
{
INT16U x,y;
for(x=z;x>0;x--)
   for(y=125;y>0;y--);
}
********************************/
//************************************************************************
#endif













本文出自 “魂斗罗” 博客,谢绝转载!

你可能感兴趣的:(红外)