资讯详情

红外遥控——驱动直流电机

这是我对联动的一些理解。请纠正错误。 1、功能显示:按下开关键,控制直流电机启动或停止,即奇数次启动,偶数次关闭,同时LCD1602上显示“ON”或“OFF”. 二、模块构成:需要红外遥控,LCD1602、直流电机三个模块联动。 接下来,让我们详细了解这三个模块。 三、模块讲解。 1、红外模块: (1)原理:红外遥控 使用波长为 0.76~1.5μm 控制信号在近红外线之间传输(红外线是无光的,肉眼无法区分)。由红外发射装置发送,红外接收装置接收、调制和放大。 红外遥控器常用载波频率为38kHz载波传输二进制编码(这里kHz它是由发射端使用的晶体振动决定的。晶体振动应在发射端进行整数分频,分频系数一般取 12,所以 455kHz÷12≈37.9kHz≈38kHz)。通常的红外遥控器是将遥控信 调制号(二进制脉冲码) 38KHz 缓冲放大后,载波送至红外发光二极 管,转化为红外信号发射出去的。二进制脉冲码的形式有很多种,其中最常用的是 NEC Protocol 的 PWM 码 (脉冲宽度调制)和 Philips RC-5 Protocol 的 PPM 代码(脉冲位置调制码,脉冲 实现信号调制的时间间隔)。要开发红外接收设备,必须了解红外接收设备 我们可以选择外遥控器的编码方法和载波频率**一体化红外接收头和制定解码 方案。* 配套红外遥控器使用 NEC 协议的特点如下: a、8 位地址和 8 位指令长度; b、地址和命令 2 次传输 c、PWM 脉冲位置调制代表0和1,发射红外载波占空比; d、载波频率为 38Khz e、位时间为 1.125ms 或 2.25ms(NEC 代码的位置定义:脉冲对应 560us 连续载波,逻辑 1 传输需要 2.25ms(560us 脉冲 1680us 低电平),逻辑 0 的传输需要 1.125ms(560us 脉冲 560us )。 当没有脉冲时,红外接收头是低电平的 这样,我们在接收头端收到的信号是:逻辑 1 :560us 低 1680us 高;逻辑 0 :560us 低 560us 高。可以通过计算高电平时间来判断接收到的数据是逻辑0还是逻辑1。红外接收头在接收脉冲时电平较低, (2)发射装置:红外遥控器由键盘电路和红外编码电路组成 红外发光二极管由道路、电源电路和红外发射电路组成。 在这里插入图片描述

在没有脉冲 当它是高电平时,可以通过外部中断的下降沿触发中断来判断。 接收到的数据是 0 还是 1。NEC 码位定义时序图如下图所示: 另外,NEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码 代码。一个引导码 9ms 低电平和一个 4.5ms 由高电平组成,地址代码地址反向 代码、控制码和控制反码 8 位数据格式。按低位在前,高位在后 发送。反码用于增加传输的可靠性(可用于验证)。数据格式如下 NEC 代码还规定了连发码(由 9ms 低电平 2.5m 高电平 0.56ms 低电平 97.94ms 高电平组成),如果红外遥控按钮在一帧数据发送后仍然没有 如果放开,则发射连发码,按钮按下的长度或次数可以通过统计连发码的次数来标记。 (3)接收装置 红外接收设备由红外接收电路、红外解码、电源和应用电路组成。 控制接收器的主要功能是将遥控发射器发送的红外光信转换为电信号,然后放大, 限幅、检波、整形,形成遥控指令脉冲,输出到遥控微处理器 这是红外模块的原理:左蓝色部分调制在38KHz载波上的数据通过缓冲放大发送到红外发光二极管(右侧),并通过接收端接收、解码和发送到处理器执行相应的功能。需要注意的是: 当发送为1时,三极管导通, 红外发光二极管发光,发射高电平1,解码为低电平0: 发送0时,二极管不打开,不传输数据,接收装置与单片机连接,为高电平1。 (4)原理图 电路集成,可直接连接使用。 2、LCD1602模块 (1)简介:1602 液晶也叫 1602 它可以显示字符液晶 2 每行可以显示字符信息 16 个字符。它是一种点阵液晶模块,用于显示字母、数字和符号。它是由若 干个 5x7 或者 5x10 的点阵字符位组成,每个点阵字符位都可以用显示一个字符。每个人之间有一个点距,每行之间也有一个间距,起到字符间距和行间距的作用 因此,它不能很好地显示图片。LCD1602实物如下所示 (2)管脚功能 上图可见LCD1602有 16 个管脚孔从左到右编号 顺序是 其功能定义如下:1-16: 3 脚:VL,液晶显示偏压信号用于调整 LCD1602 显示对比度. 4 脚:RS,当这只脚是高电平时,数据/命令选择端可以对 1602 进行数据字 节传输操作,而低电平时则是命令字节传输操作。LCD1602 的数据是 8 位的。 5 脚:R/W,读写选择端。这只脚是高电平的 LCD1602 读数据操作, 反之进行写数据操作。 6 脚:E,使能信号,其实是 LCD1602 使用该信号的数据控制时钟信号 实现正确的上升边缘 LCD1602 数据传输。 7~14 脚:8 并行数据口,而 51 单片机一组 IO 也是 8 位,使得对 LCD1602 数据读写非常方便。 在 LCD1602 内部含有 80 个字节的 ,用于存储显示字符。它的地址 与屏幕的对应关系如下表所示: 并非所有地址都可以直接用来显示字符数据,只有在第一行 的 00-0F,第二行中的 40-4F 其他地址只能用于存储。显示字符时 首先输入显示字符地址,即告诉模块在哪里显示字符。需要注意的是,在写入显示地址时,需要最高位置 D7 恒定为高电平 1 所以实际写入的数据应该是 指定显示地址数据 10000000B(80H) (3)常用指令 <1> 即将清除液晶显示器 DDRAM 填写所有内容"空白"的 ASCII 码 20H; <2> 将光标返回液晶显示屏左上方; <3> 地址计数器(AC)的值设为 0 只有DB1和DB0需要手动输入,其他值为固定。 设定每次写入 1 位数据后光标的移位方向,并且设定每次写入的一个字符是 否移动。 I/D:0=写入新数据后光标左移 1=写入新数据后光标右移 S:0=写入新数据后显示屏不移动 1=写入新数据后显示屏整体右移 1 个 字符。 控制显示器开/关、光标显示/关闭以及光标是否闪烁。 D:0=显示功能关 1=显示功能开 C:0=无光标 1=有光标 B:0=光标闪烁 1=光标不闪烁 设定数据总线位数、显示的行数及字型。 DL:0=数据总线为 4 位 1=数据总线为 8 位 N:0=显示 1 行 1=显示 2 行 F:0=5×7 点阵/每字符 1=5×10 点阵/每字符 总结来说,操作步骤如下 作步骤如下所示: (1)初始化 (2)写命令(RS=L), 设置显示坐标 (3)写数据(RS=H) 在此,不需要读出它的数据的状态或者数据本身。所以只需要看两个写时序: ① 当要写指令字,设置 LCD1602 的工作方式时:需要把 RS 置为低电平,RW 置为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。 ② 当要写入数据字,在 1602 上实现显示时:需要把 RS 置为高电平,RW 置 为低电平,然后将数据送到数据口 D0~D7,最后 E 引脚一个高脉冲将数据写入。 写指令和写数据,差别仅仅在于 RS 的电平不一样而已。以下是 LCD1602 的 时序图: 当要写命令字节的时候,时间由左往右,RS 变为低电平,R/W 变为低电平, 注意看是 RS 的状态先变化完成。然后这时,DB0~DB7 上数据进入有效阶段,接 着 E 引脚有一个整脉冲的跳变,接着要维持时间最小值为 tpw=400ns 的 E 脉冲宽 度。然后E引脚负跳变,RS电平变化,R/W 电平变化。这样便是一个完整的LCD1602 写命令的时序。如需要更加详细数据请移步数据手册。 3、直流电机 ULN2003控制的直流电机只能同一方向转动,定义引脚sbit moto=P1^0后,令moto=1即可转动不再赘述。 四、代码设置 我的机子lcd1602没有转接使用的是8位。如果有转接板的话使用的是4位,下列代码只适用于八位

#include<reg51.h>
#include<lcd.h>
//#define __LCD_H_
#define uchar unsigned char
#define uint unsigned int
typedef unsigned char uint8;
typedef unsigned int uint16;
#define LCD1602_DATAPINS P0 //D0~D7在P0端口 指令和程序都在p0口
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat)	;
/*LCD1602初始化子程序*/		
void LcdInit();						  
sbit moto=P1^0;
uint8 d1[8]=" RED IR ";
uint8 d2[12]="MOTO STATE: ";
uint8 num[16]="0123456789ABCDEF";在这里插入代码片
void lcdwrc(uint8 c)
{ 
        
	LcdWriteCom(c);		//写入命令
}
void lcdwrd(uint8 dat)
{ 
        
	LcdWriteData(dat);	 	//写入数据
}
void lcd_init()
{ 
        
	LcdInit();		     //LCD初始化子程序
}

void Lcd1602_Delay1ms(uint c);是12MHZ时钟下的延时函数 sbit LCD1602_E=P2^7; 使能 sbit LCD1602_RW=P2^5; 数据命令选择端管脚 sbit LCD1602_RS=P2^6;读写控制选择管脚 void LcdInit(); //LCD初始化子程序

void LcdWriteCom(uchar com)	  //写入命令
{ 
        
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
void LcdWriteData(uchar dat)			//写入数据
{ 
        
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}在这里插入代码片

简单介绍一下lcd写如指令和数据函数 LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); //保持时间 LCD1602_E = 0; 三条代码是为了产生下降沿,将数据写入1602内部,与上文的时序图对应 写命令和数据的唯一区别是LCD1602_RS = 1还是0; //选择输入数据

void LcdInit()						  //LCD初始化子程序
{ 
        
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}插入代码片

根据上文介绍的显示开关控制指令设置一个 你所想要的显示状态

void int0init()					 //中断配置 使用INT0
{ 
        
	EA=1;
	EX0=1;
	IT0=1;
}
void time0init()		  //计数
{ 
        
	TMOD=0X02;	//设置定时器0模式2.该模式为自动装载模式
	TH0=0X00;
	TL0=0X00;//设定计数初值,每当TL0计数到255时,TH0将把自己的数据给TL0,又重新计数
	TR0=1;
	ET0=1;
	EA=1;	
}

中断和计数器,中断服务函数在下面,由于红外接收管脚和外部中断0定义在一个管脚,所以使用INT0。定时计数其用于计算每一位二进制数的发送时间。

void irpros() //红外接收数据处理 ,区分是数据0还是1
{ 
        
	uint8 i,j,value;
	uint8 k=1;	//引导码去掉,所以令k=1;
	for(j=0;j<4;j++)  //取出了一帧数据中的四个字节数据
	{ 
        
		for(i=0;i<8;i++)	//取出了一个字节的数据 
		{ 
        
			value>>=1;
			if(irdata[k]>6)
			{ 
        
				value=value|0x80;
			}
			k++;
		}
		ircode[j]=value;
	}
	irprosok=1;				   //接收数据处理标志位
}

红外接收数据解码,区分是数据0还是1。irdata[k]是存储每一位二进制位数发送的时间,如果高电位的时间大于0.6毫秒,就是逻辑‘1’,反之就是逻辑‘0’。如果高电位的时间大于0.6毫秒,value=value|0x80。将接收数据存储到ircode[]数组中。接收数据处理标志位irprosok=1;表示数据处理完成。

void irwork()  //将四个字节的数据转换成10进制数显示
{ 
        
	irdisp[0]=ircode[0]/16;//显示高位
	irdisp[1]=ircode[0]%16;//显示低位 
	irdisp[2]=ircode[1]/16;
	irdisp[3]=ircode[1]%16;	 //同一个遥控器此2个字节的引导码数据是不会改变的,改变的只是数据码及反码
	irdisp[4]=ircode[2]/16;
	irdisp[5]=ircode[2]%16;
	irdisp[6]=ircode[3]/16;
	irdisp[7]=ircode[3]%16;
	dat1=irdisp[4];	  //数据高位
	dat2=irdisp[5];	  //数据低位
	keynum++;
}

ircode[]中存储四个字节:用户码、用户反码、数据码、数据反码,将各字节转换为十进制的数字。 dat1=irdisp[4]; 数据高位 dat2=irdisp[5]; 数据低位 表示的是数据码的高地位。 keynum指按键按下次数

void display()				//显示屏显示 电击开关
{ 
        
	uint8 i;
	lcdwrc(0x00+0x80);	// 第一行显示
	for(i=0;i<8;i++)		 //uint8 d1[8]=" RED IR "
	{ 
        
		lcdwrd(d1[i]);		   //显示 " RED IR "
	}	
	for(i=4;i<6;i++)
	{ 
        
		lcdwrd(num[irdisp[i]]);		  //显示数据码
	}									//uint8 num[16]="0123456789ABCDEF";
	lcdwrc(0x40+0x80);
	for(i=0;i<12;i++)
	{ 
        
		lcdwrd(d2[i]);
	}
	if(motoflag==1)			//马达状态显示
	{ 
        
		lcdwrd('O');
		lcdwrd('N');
		lcdwrd(' ');
	}
	else
	{ 
        
		lcdwrd('O');
		lcdwrd('F');
		lcdwrd('F');	
	}
}

lcdwrc(0x00+0x80)显示第一行,0x00(第一行第一位)+0x80(因为写入显示地址时要求最高位 D7 恒定为高电平 1 所以实际写入的数据应该加0x80)

void motopros()					   //控制电机
{ 
        
	if((dat1==4)&&(dat2==5)&&(keynum==1))  //按下第一次按键开马达
	{ 
        			
		dat1=0;
		dat2=0;
		motoflag=1;
		moto=1;						
	}
			
	if((dat1==4)&&(dat2==5)&&(keynum>=2))	//按下第二次此按键时关闭马达
	{ 
        
		dat1=0;		  //置零
		dat2=0;
		keynum=0;
		motoflag=0;
		moto=0;			
	}				
}

控制直流电机

void main()
{ 
        
	moto=0;	
	lcd_init();	 //初始化lcd程序
	int0init();	 //开外部中断0
	time0init();  //定时计数
	while(1)
	{ 
        
		if(irreceok)
		{ 
        
			irreceok=0;
			irpros(); //红外数据处理
			if(irprosok)//接收数据处理标志位
			{ 
        
				irwork();  //将四个字节的数据转换成10进制数显示
			}
		}
		motopros();		  //控制电机
		display();	 //显示屏显示 电击开关
	}		
}

主函数 while循环中,当数据接收完成后,将接收完成标志irreceok置零,进入解码程序,解码完成后,将四个字节的数据转换成10进制数显示,控制电机,lcd602显示。

void time0() interrupt 1
{ 
        
	irtime++;//每进来一次就说明定时时间为256us; 
}
void init0() interrupt 0
{ 
        
	if(t)
	{ 
        
		if(irtime>32)//检测引导码,求法是用引导码时间除以一次计数时间,看看要多少次 
		{ 
        
			bitnum=0;	
		}
		irdata[bitnum]=irtime;
		irtime=0;
		bitnum++;
		if(bitnum==33)// 一帧数据发送完成需要32秒
		{ 
        
			bitnum=0;
			irreceok=1;//一帧红外数据接收完成标志
		}
	}
	else
	{ 
        
		t=1;//将开始标志位置1,等到下次进入中断即可进入if语句
		irtime=0;//将开始之前的计数器时间清零。等到下次进入中断的时候才是引导码真正的时间
	}
}

1 为定时计数器触发的中断,每进来一次就说明定时时间为256us, 5 为外部中断触发 的中断服务函数irdata[bitnum]=irtime 将每位二进制数存储到irdata[]数组中,就是上文提到的void irpros() 中所应用于判断逻辑‘1’和逻辑‘0’的语句。

标签: 红外遥控接收器模块传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台