青绿色为遥控器发射端波形,
黄颜色为一体化接收端波形,
静态时:
发送一个电平,接收一个电平
发送一个编码,接收一个按键的编码
波形参考
DIY硬件平台:
STC89C54RD+
LCD1602
红外1838接收
红外发送管
矩阵键盘
功能:
学习遥控器的编码
显示遥控器的NEC编码
发送学习到的编码
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
本文出自 “魂斗罗” 博客,谢绝转载!