学习型遥控器C语言编程
`/*************************************************************** 名称:红外线遥控发射(NEC编码)
单片机:STC89C52RC
晶振:12M
编译环境:Keil uVision4 V9.00
主程序如下所示,附录中为两个头文件,里面包含参数设定和LCD屏显示。***************************************************************/
// 发射引脚(接PNP三极管b极与1K欧电阻)
// PNP三极管e极接电源,c极接红外发射管与51欧电阻
#include
#include "INC\MY_SET.h"
#include "INC\LCD1602_6IO.h"
sbit IR = P3^6; //发射引脚(接PNP三极管基极)
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;
sbit KEY1=P1^0;
sbit KEY2=P1^1;
sbit KEY3=P1^2;
sbit KEY4=P1^3;
sbit KEY5=P1^4;
#define USER_H P2 //用户码高8位
#define USER_L P0 //用户码低8位
uint8 tab[16] = { //操作码
0x12,0x05,0x1e,0x55,
0x01,0x1b,0x03,0x6b,
0x07,0x08,0x09,0x68,
0x22,0xE6,0x33,0xe2};
uint16 M = 0;
#define m9 (65536-9000) //9mS
#define m4_5 (65536-4500) //4.5mS
#define m1_6 (65536-1650) //1.65mS
#define m_56 (65536-560) //0.56mS
#define m40 (65536-40000) //40mS
#define m56 (65536-56000) //56mS
#define m2_25 (65536-2250) //2.25mS
void SanZhuan();
uint8 KEY(void);
void ZZ(uint8 x); //NEC编码发送程序
void Z0(uint8 temp); //单帧(8位数据)发送程序
void TT0(bit BT,uint16 x); //38KHz载波发射+ 延时程序
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈函数:主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void main(void)
{
uchar m;
TMOD = 0x01;
IE = 0x81; //允许总中断中断,使能INT0 外部中断TCON = 0x01; //触发方式为脉冲负边沿触发
IRIN=1; //I/O口初始化
BEEP=1;
IR = 1;
delay1(10); //延时
lcd_init(); //初始化LCD
lcd_pos(0); //设置显示位置为第一行的第1个字符m = 0;
while(cdis1[m] != '\0')
{ //显示字符
lcd_wdat(cdis1[m]);
m++;
}
lcd_pos(0x40); //设置显示位置为第二行第1个字符m = 0;
while(cdis2[m] != '\0')
{
lcd_wdat(cdis2[m]); //显示字符
m++;
}
while(1) {
if(LED4 == 0){IE = 0x00;}
else{IE = 0x81;}
SanZhuan();
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈函数:4*2独立键盘
入口:void
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ uint8 KEY(void)
{
uint8 Key = 0xff;
if(KEY1 == 0)
{Key = 0; LED1 =~ LED1;}
if(KEY2 == 0)
{Key = 1; LED2 =~ LED2;}
if(KEY3 == 0)
{Key = 2; LED3 =~ LED3;}
if(KEY4 == 0)
{Key = 3; LED3 =~ LED3;}
if(KEY5 == 0)
{ LED4 =~ LED4;}
return Key; //返回键值
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈函数:散转程序
入口:void
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ voidSanZhuan()
{
uint8 v;
//TMOD = 0x01;
v = KEY(); //键盘检测
switch(v)
{
case 0:ZZ(tab[0]);break;
case 1:ZZ(tab[1]);break;
case 2:ZZ(tab[2]);break;
case 3:ZZ(tab[3]);break;
/* case 0x7d:ZZ(tab[4]);break;
case 0xbd:ZZ(tab[5]);break;
case 0xdd:ZZ(tab[6]);break;
case 0xed:ZZ(tab[7]);break;
case 0x7b:ZZ(tab[8]);break;
case 0xbb:ZZ(tab[9]);break;
case 0xdb:ZZ(tab[10]);break;
case 0xeb:ZZ(tab[11]);break;
case 0x77:ZZ(tab[12]);break;
case 0xb7:ZZ(tab[13]);break;
case 0xd7:ZZ(tab[14]);break;
case 0xe7:ZZ(tab[15]);break; */
default:break;
}
v=0;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈函数:NEC编码发送程序
入口:八位操作码
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void ZZ(uint8 Value)
{
TT0(1,m9); //高电平9mS
TT0(0,m4_5); //低电平4.5mS
/*┈发送4帧数据┈*/
Z0(USER_H); //用户码高8位
Z0(USER_L); //用户码低8位
Z0(Value); //操作码
Z0(~Value); //操作码反码
/*┈┈结束码┈┈*/
TT0(1,m_56);
TT0(0,m40);
/*┈┈重复码┈┈*/
while(KEY() != 0xFF)
{
TT0(1,m9);
TT0(0,m2_25);
TT0(1,m_56);
TT0(0,m40);
TT0(0,m56);
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:单帧(8位数据)发送程序
入口:temp
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void Z0(uint8 temp)
{
uint8 v;
for (v=0;v<8;v++) //循环8次移位
{
TT0(1,m_56); //高电平0.65mS
if(temp&0x01) TT0(0,m1_6); //发送最低位
else TT0(0,m_56);
temp >>= 1; //右移一位
}
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:38KHz载波发射+ 延时程序
入口:(是否发射载波,延时约x (uS))
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void TT0(bit BT,uint16 x)
{
TH0 = x>>8; //输入T0初始值
TL0 = x;
TF0=0; //清0
TR0=1; //启动定时器0
if(BT == 0) while(!TF0); //BT=0时,不发射38KHz载波只延时;BT=1发射38KHz脉冲且延时;else while(1) //38KHz载波,(低电平)占空比5:26
{
IR = 0;
if(TF0)break;if(TF0)break;
IR = 1;
if(TF0)break;if(TF0)break;
if(TF0)break;if(TF0)break;
if(TF0)break;if(TF0)break;
if(TF0)break;if(TF0)break;
if(TF0)break;if(TF0)break;
}
TR0=0; //关闭定时器0
TF0=0; //标志位溢出则清0
IR =1; //载波停止后,发射端口常态为高
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:外部中断函数
入口:void
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void IR_IN(void) interrupt 0 //外部中断服务程序
{
unsigned char j,k,N=0;
EX0 = 0;
delay(15);
if (IRIN==1)
{ EX0 =1;
return;
}
//确认IR信号出现
while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
{delay(1);}
for (j=0;j<4;j++) //收集四组数据
{
for (k=0;k<8;k++) //每组数据有8位
{
while (IRIN) //等IR 变为低电平,跳过4.5ms的前导高电平信号。
{delay(1);}
while (!IRIN) //等IR 变为高电平
{delay(1);}
while (IRIN) //计算IR高电平时长
{
delay(1);
N++;
if (N>=30)
{ EX0=1;
return;} //0.14ms计数过长自动离开。
} //高电平计数完毕
IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”
if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;} //数据最高位补“1”
N=0;
}//end for k
}//end for j
if (IRCOM[2]!=~IRCOM[3]) //按位取反
{ EX0=1;
return; }
IRCOM[5]=IRCOM[2] & 0x0F; //取键码的低四位
IRCOM[6]=IRCOM[2] >> 4; //右移4次,高四位变为低四位
if(IRCOM[5]>9)
{ IRCOM[5]=IRCOM[5]+0x37;}
else
IRCOM[5]=IRCOM[5]+0x30;
if(IRCOM[6]>9)
{ IRCOM[6]=IRCOM[6]+0x37;}
else
IRCOM[6]=IRCOM[6]+0x30;
lcd_pos(0x4b);
lcd_wdat(IRCOM[6]); //第一位数显示
lcd_pos(0x4c);
lcd_wdat(IRCOM[5]); //第二位数显示
Y0=0;
switch(IRCOM[2])
{
case 0x09: Y0=0x01; break;
case 0x1D: Y0=0x02; break;
case 0x1F: Y0=0x03; break;
case 0x0D: Y0=0x04; break;
case 0x19: Y0=0x05; break;
case 0x1B: Y0=0x06; break;
case 0x11: Y0=0x07; break;
case 0x15: Y0=0x08; break;
case 0x17: Y0=0x09; break;
default:break;
//case 0x13: RELAY=1; break;
// case 0x14: RELAY=1; break;
// case 0x51: RELAY=0; break;
}
tab[M] = IRCOM[2];
M = (M+1)%4;
beep();
EX0 = 1;
}
附录1
//头文件,包含各类定义
#ifndef __MY_SET_H__
#define __MY_SET_H__
// data 固定指片内RAM:0x00~0x7F
// bdata固定指片内RAM:0x20~0x2F
// idata固定指片内RAM:0x00~0xFF
// xdata一般指内部扩展RAM:0x0000~0xFFFF,也指内部扩展RAM:0x0000~0xFFFF // code 指程序存储区ROM:0x0000~0xFFFF
//无符号类型
#define uint8 unsigned char
#define uint8b unsigned char bdata
#define uint8i unsigned char idata
#define uint8x unsigned char xdata
#define uint8c unsigned char code
#define uint16 unsigned int
#define uint16i unsigned intidata
#define uint16x unsigned intxdata
#define uint16c unsigned int code
#define uint32 unsigned long
#define uint32i unsigned long idata
#define uint32x unsgined long xdata
#define uint32c unsgined long code
//有符号类型
#define int8 char
#define int8x char xdata
#define int8c char code
#define int16 int
#define int16x intxdata
#define int16c int code
#define int32 long
#define int32x long xdata
#define int32c long code
/////////////
#include
#define NOP _nop_()
#define NOP_12 _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_no p_()
#define NOP() _nop_() /* 定义空指令*/
#define uchar unsigned char
#define uint unsignedint
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
#endif
//头文件2,LCD的全部函数
#ifndef __LCD1602_6IO_H__
#define __LCD1602_6IO_H__
sbit IRIN = P3^2; //红外接收器数据线
uchar IRCOM[7];
uchar cdis1[] = {" REMOTE CONTROL "};
uchar cdis2[] = {" IR-CODE: ----H"};
//LCD IO
sbit LCD_RW = P2^5;
sbit LCD_RS = P2^6;
sbit LCD_EN = P2^7;
sbit BEEP = P1^5;
void delay(uchar x); //x*0.14MS
void delay1(intms);
void beep(void);
unsigned char Y0;
/*******************************************************************/
/* */
/*检查LCD忙状态*/
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。*/ /* */ /*******************************************************************/
bitlcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/*******************************************************************/ /* */ /*写指令数据到LCD */ /*RS=L,RW=L,E=高脉冲,D0-D7=指令码。*/ /* */ /*******************************************************************/
voidlcd_wcmd(ucharcmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/ /* */ /*写显示数据到LCD */ /*RS=H,RW=L,E=高脉冲,D0-D7=数据。*/ /* */
/*******************************************************************/
voidlcd_wdat(uchardat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/*******************************************************************/ /* */ /* LCD初始化设定*/ /* */ /*******************************************************************/
voidlcd_init()
{
delay1(15);
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x38);
delay1(5);
lcd_wcmd(0x0c); //显示开,关光标
delay1(5);
lcd_wcmd(0x06); //移动光标
delay1(5);
lcd_wcmd(0x01); //清除LCD的显示内容
delay1(5);
}
/*******************************************************************/ /* */ /* 设定显示位置*/ /* */ /*******************************************************************/
voidlcd_pos(ucharpos)
{
lcd_wcmd(pos | 0x80); //数据指针=80+地址变量
}
/**********************************************************/ void delay(unsigned char x) //x*0.14MS
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++) {}
}
}
/**********************************************************/ void delay1(intms)
{
unsigned char y;
while(ms--)
{
for(y = 0; y<250; y++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void beep(void)
{
unsigned char i;
for (i=0;i<100;i++)
{
delay(4);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //关闭蜂鸣器
}
#endif