单片机红外线遥控

项目简介:
(TC9012)红外遥控器发送红外信号, 红外接收模块接收到信号后,通过外部中断0传送给(51)单片机; 单片机对接收到的每帧数据解码后将相应的按键值显示在LCD1602上; 并实现对相应外设的控制:0-开buzzer, 1-关buzzer; 2-开LED, 3-关LED。
TC9012遥控器相关参数如下:
1.发送的每帧数据格式如下:
在这里插入图片描述
每帧数据共33bit(1bit引导码 + 32bit数据),发送时低位在前,高位在后;
2.引导码波形格式如下:
在这里插入图片描述
3.逻辑0波形格式如下:
在这里插入图片描述
4.逻辑1波形格式如下:
在这里插入图片描述
C语言代码如下:

/*---------------------------
FileName: InfraredControl2.h
Funtion: 头文件
Author: Zhang Kaizhou
Date: 2019-6-14 19:09:23
---------------------------*/
#include 
#include 
#include 
#include 
#define uchar unsigned char
#define uint unsigned int
#define DATALEN 33 // 数据帧长度(1bit引导码 + 32bit数据)
	
/*红外接收模块端口定义*/
sbit infraredReceiver = P3^2;

/*LCD1602显示模块端口定义*/
sbit lcdrs = P1^0;
sbit lcdrw = P1^1;
sbit lcden = P2^5;

/*LED灯端口定义*/
sbit led = P1^7;

/*蜂鸣器端口定义*/
sbit buzzer = P2^3;

/*主模块函数声明*/
void timerInit();
void ecternINT0Init();
void dataProcess();
void keyValueProcess();

/*LCD1602显示模块函数声明*/
void delay(uint xms);
void writeCommand(uchar command);
void writeDataLCD(uchar dat);
void LCDInit();
void display(uchar dat);
/*---------------------------------------------------------------------
FileName: main.c
Function: (TC9012)红外遥控器发送红外信号, 红外接收模块接收到信号后,
通过外部中断0传送给(51)单片机; 单片机对接收到的每帧数据解码后将相应的
按键值显示在LCD1602上; 并实现对相应外设的控制:0-开buzzer, 1-关buzzer;
2-开LED, 3-关LED。
Author: Zhang Kaizhou
Date: 2019-6-14 19:08:23
----------------------------------------------------------------------*/
#include "InfraredControl2.h"

/*定义全局变量*/
uchar time = 0; // 用于记录接收的数据中两个下降沿之间的时间差
uchar disValue = 0; // 用于存放要显示数据
uchar dat[DATALEN] = 0; // 用于存放接收到的数据
uchar finalData[4] = 0; // 用于存放最终译码后的键值
bit receiveFlag = 0; // 接收结束标志位
bit processFlag = 0; // 一帧数据处理完成标志位
bit keyFlag = 0; // 键值处理完成标志位

/*主函数*/
void main(){
	LCDInit();
	ecternINT0Init();
	timerInit();
	while(1){
		if(receiveFlag){
			receiveFlag = 0;
			dataProcess();
		}
		if(processFlag){
			processFlag = 0;
			keyValueProcess();
		}
		if(keyFlag){
			keyFlag = 0;
			display(disValue);
		}
	}
}

/*定时器初始化函数*/
void timerInit(){
	TMOD = 0x02; // timer0 定时模式 工作方式2(自动重装初值的8位定时器)
	TH0 = 0x00; // 置初值
	TL0 = 0x00;
	ET0 = 1; // 开timer0溢出中断
	TR0 = 1; // 启动timer0
}

/*timer0中断服务程序*/
void timer0Service() interrupt 1{
	time++;
}

/*外部中断0(INT0)初始化*/
void ecternINT0Init(){
	IT0 = 1; //外部中断0为跳变沿触发
	EX0 = 1; // 允许外部中断0
	EA = 1; // 开全局中断
}

/*外部中断0(INT0)中断服务程序*/
void externINT0Service() interrupt 0{
	static uchar i; // 定义静态局部变量i, 每次调用函数时保存上次的变量值
	static bit startFlag;
	if(startFlag){ // 判定是否已启动红外通信
		if(time >= 30 && time < 50){ // 检测到引导码(4.5 + 4.5 = 9ms), 9 / 0.278 = 32; 检测冗余时间范围[30, 50]
			i = 0; // 引导码保存在数组的第0位
		}
		dat[i++] = time; // 存储每个数据位持续的时间用于后续0 1的判定
		time = 0;
		if(i == 33){ // 一帧数据(1bit引导码 + 32bit数据)接收结束
			receiveFlag = 1;
			i = 0;
		}
	}else{ // 启动红外通信
		time = 0;
		startFlag = 1;
	}
}

/*数据处理函数*/
void dataProcess(){
	uchar i, j, k = 1; // k标记当前处理的数据位(跳过第0位引导码)
	uchar value; // 存放处理后的键值
	for(i = 0; i < 4; i++){ // 一帧数据(4个字节)
		value = 0;
		for(j = 0; j < 8; j++){ // 每个字节8位
			if(dat[k++] > 7){ // 当前数据为1
				/*TC9012遥控器定义'0'的两个下降沿时间间隔为1.125ms; '1'的两个下降沿时间间隔为2.25ms;
					所以接收端检测到的时间间隔[time * T(系统)]的平均值 = (1.125 + 2.25) / 2 = 1.6875ms;
					假定系统晶振为11.0592MHz, 则T(系统) = 1.0850694us; 8位定时器每次定时长度 = 256 * T(系统) = 0.277ms;
					1.6875 / 0.277 = 6.0921(次); 所以, 若定时次数大于7次,即平均时间间隔大于1.6875ms, 可判定该数据为1;
					否则为0。
				*/
				value |= 0x80; // 最高位置1
			}
			if(j < 7){
				value >>= 1; // 因为TC9012遥控器发送的数据低位在前,高位在后,故需做右移位处理
			}
		}
		finalData[i] = value;
	}
	processFlag = 1; // 一帧数据处理完
}

/*键值处理函数*/
void keyValueProcess(){
	switch(finalData[2]){
		/*特殊功能键(11个)*/
		case 0x45: break;
		case 0x46: break;
		case 0x47: break;
		case 0x44: break;
		case 0x40: break;
		case 0x43: break;
		case 0x07: break;
		case 0x15: break;
		case 0x09: break;
		case 0x19: break;
		case 0x0d: break;
		
		/*数字键(0~9共10个)*/
		case 0x16: disValue = 0; buzzer = 0; break; // 显示按键值0, 开蜂鸣器
		case 0x0c: disValue = 1; buzzer = 1; break; // 显示按键值1, 关蜂鸣器
		case 0x18: disValue = 2; led = 0; break; // 显示按键值2, 开LED
		case 0x5e: disValue = 3; led = 1; break; // 显示按键值3, 关LED
		case 0x08: disValue = 4; break;
		case 0x1c: disValue = 5; break;
		case 0x5a: disValue = 6; break;
		case 0x42: disValue = 7; break;
		case 0x52: disValue = 8; break;
		case 0x4a: disValue = 9; break; // 9
		default: break;
	}
	keyFlag = 1;
}
/*-----------------------------
FileName:display.c
Function: LCD1602显示函数
Author: Zhang Kaizhou
Date: 2019-6-14 19:10:49
------------------------------*/
#include "InfraredControl2.h"

uchar code table0[] = {"Infrared value"};
uchar code table1[] = {"Received:"};
uchar code table2[] = {"0123456789"};
uchar num = 0;

/*初始化LCD1602的设置*/
void LCDInit(){
	uchar i;
	lcden = 0; // 拉低使能端,准备产生使能高脉冲信号
	writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)
	writeCommand(0x0c); // 开显示,不显示光标
	writeCommand(0x06); // 写一个字符后地址指针自动加1
	writeCommand(0x01); // 显示清零,数据指针清零
	
	/*LCD上电界面*/
	writeCommand(0x80); // 将数据指针定位到第一行首
	for(i = 0; i < strlen(table0); i++){
		writeDataLCD(table0[i]);
		delay(5);
	}
	
	writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首
	for(i = 0; i < strlen(table1); i++){
		writeDataLCD(table1[i]);
		delay(5);
	}
}

/*LCD显示函数*/
void display(uchar dat){
	writeCommand(0x80 + 0x40 + strlen(table1));
	writeDataLCD(table2[dat]);
	delay(5);
}

/*写指令函数*/
void writeCommand(uchar command){
	lcdrs = 0; // 命令选择
	lcdrw = 0;
	P0 = command;
	delay(5);
	
	lcden = 1; // 产生一个正脉冲使能信号
	delay(5);
	lcden = 0;
}

/*写数据函数*/
void writeDataLCD(uchar dat){
	lcdrs = 1; // 数据选择
	lcdrw = 0;
	P0 = dat;
	delay(5);
	
	lcden = 1;
	delay(5);
	lcden = 0;
}

/*延时xms函数*/
void delay(uint xms){
	uint i, j;
	for(i = xms; i > 0; i--)
		for(j = 110; j > 0; j--);
}

你可能感兴趣的:(C51)