即插即用的PC红外遥控接收器

文章原标题《基于V-USB制作的电脑红外遥控接收器》 已刊登在《无线电》杂志2014年12期      点此购买淘宝套件

基于V-USB制作的电脑红外遥控接收器

文 任鹏


当我们使用电脑观看电影、听歌,或是将播放视频的画面投射到电视机上时,总是希望可以像遥控电视机那样遥控电脑,方便地实现上一曲、下一曲、音量增减等必要功能。网上已有一些常见的方案为电脑增加红外遥控功能,硬件上不外乎使用到了串口,而且需要安装一款软件用于记忆红外编码,并赋予该编码确定的功能。笔者制作的这款,无需安装驱动程序,也不需要上位机软件,真正做到了即插即用。同时,硬件结构简单,成本极低,很适合自制(如图1)。

 

红外遥控接收器

生活中,可能大多数朋友使用的键盘是标准键盘,不过,市场上还有一种带多媒体按键的键盘,有音量控制、曲目控制、睡眠,甚至一键打开主页、计算器等功能。这一特点给了笔者启发,我们完全可以制作一款红外遥控接收器,对于使用者而言,它接收红外编码指令,而对于电脑而言,电脑会认为它是一款只拥有多媒体按键的特殊键盘,通过它完成了红外解码并转换为键码的过程。如此一来,我们就摆脱了对上位机软件的依赖,更方便广大电脑用户的使用。

有了思路,接下来就是划定方案。首先,制作一款键盘,USB接口是必不可少的。实现下位机和上位机通过USB交换数据的方案很多,但是考虑到成本、体积、下位机编程的难易,甚至是相关芯片的购买是否方便,笔者认为多年前出现的V-USB方案比较符合要求。V-USB是一套用于在AVR单片机上实现低速USB设备的软件包,AVR家族的绝大多数型号均可使用而无需内置硬件USB控制器,USB通讯完全靠软件模拟时序完成,受此制约,CPU占用率较高。在V-USB的官网,提供了一款使用8引脚单片机ATtiny 45制作的范例,其小巧的封装很符合本次制作的要求,但是ATtiny 45并不容易购得,且零售价较高。

深圳绿智微电子2012年推出了兼容AVR指令的LGT8F0XA系列单片机,随后进一步优化了内核,并扩充了产品线。其中,LGT8F08ASOP8L封装非常符合本设计要求,体积小,且售价低廉(零售价约为1.35元),由于其兼容AVR指令,使得移植V-USB成为可能。根据芯片手册的描述,基于MVR8X内核的LGT单片机有若干指令的执行速度比AVR快,则V-USB的底层汇编部分代码需要进行调整,以满足时序。令人欣喜的是,在绿智微电子的官方网站上,已经提供了移植好的模板代码包。该模板仅提供对12MHz和16MHz系统时钟的支持。

硬件确定后,紧接着就是单片机程序的编写。打开从绿智微电子官网下载的模板压缩包,将其中的VUSB-Sample文件夹解压到某一位置,然后打开该文件夹,将除source文件夹和Makefile文件之外的全部删掉,后面的工作我们都在这个基础上展开。source文件夹中,usbdrv文件夹内是移植好的V-USB程序包,Smpl_USBLED.c是官方提供的示例文件。V-USB为适应不同型号AVR单片机的寄存器差别,大量使用了宏定义,我们需要根据硬件的具体情况对V-USB进行配置。打开usbdrv文件夹里的usbconfig.h文件,根据注释可以很快清楚每项宏定义的用途,这其中,我们修改的重点是外部中断的入口。按照V-USB的要求,USB+USB-两根信号线需要和同一组的不同IO相连,同时,占用一个外部中断,默认情况下,V-USB使用的是外部中断0,但是,本着节约IO的原则,以及根据LGT8F08A-SOP8L封装的特点,我们选择使用外部中断2,同时USB+USB-分别连接到PA6PA3,满足前述要求(如图2)。在usbconfig.h文件的末端,就是用来修改中断入口的。我们将其修改为如下代码:


#define USB_INTR_CFG            EICRA //EICRA –外部引脚中断控制寄存器
#define USB_INTR_CFG_SET        ((1 << ISC20) | (1 << ISC21))
#define USB_INTR_CFG_CLR        0
#define USB_INTR_ENABLE         EIMSK //EIMSK –外部引脚中断屏蔽寄存器
#define USB_INTR_ENABLE_BIT     INT2
#define USB_INTR_PENDING        EIFR  //EIFR –外部引脚中断标志寄存器
#define USB_INTR_PENDING_BIT    INTF2 //外部引脚 2 中断标志位
#define USB_INTR_VECTOR         INT2_vect


 

原理图

其它配置块,如“Hardware Config”和“Optional Hardware Config”等,只需根据电路实际进行修改即可。“Optional Hardware Config”下的“USB_CFG_PULLUP_IOPORTNAME”和“USB_CFG_PULLUP_BIT”是用来配置USB- 线上的上拉电阻连接的IO的,用以将USB设备配置为低速设备。原本这是个可选项,1.5k 的上拉电阻完全可以直接接到3.3V电平上,但是这里有个特殊情况,LGT8F08A-SOP8L封装的IO高电平比供电电平低了约0.6V,这是因为,这款芯片的VCC实际上是RESET,在芯片内部,RESET通过一个二极管连接到真正的VCC(如图3)。为了匹配USB电平标准,我们使用一个稳压二极管来产生3.9V的供电电压,同时占用一个IO完成上拉操作。“Device Description”下的“USB_CFG_VENDOR_ID”和“USB_CFG_DEVICE_ID”分别为VIDPID的配置宏,原则上,这里的值需要向USB组织付费申请,作为实验,笔者均使用0x8888进行代替。至于“USB_CFG_VENDOR_NAME”和“USB_CFG_DEVICE_NAME”则可根据自己的需要修改。

 

图3 SOP8L封装内部结构

配置完毕后,我们来建立主程序。打开source文件夹下的Smpl_USBLED.c,将原来的main函数替换为如下代码:


int main(void)
{
	uchar i;

	hardwareInit();

	wdt_enable(WDTO_1S);    // enable 1s watchdog timer

	usbInit();

	usbDeviceDisconnect(); 	// enforce re-enumeration

	i = 0;
	while (--i)             // fake USB disconnect for > 250 ms
	{
		wdt_reset();
		_delay_ms(1);
	}

	usbDeviceConnect();

	sei(); 					// Enable interrupts after re-enumeration

	while (1)
	{
		wdt_reset(); 		// keep the watchdog happy
		usbPoll();
		if (IR_Press && usbInterruptIsReady())
		{ /* we can send another report */
			IR_Press = 0;
			buildReport();
			usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
			IR_PressRelease = 1;
		}
		if (IR_PressRelease && usbInterruptIsReady())
		{ /* we can send another report */
			IR_PressRelease = 0;
			buildReport();
			usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
		}
	}
	return 0;
}


其中,hardwareInit() 函数用于初始化相关寄存器,首先是禁能SWD功能。SWDLGT单片机的仿真调试接口,上电默认开启,并占用PC6PA6引脚,根据数据手册描述,软件必须在 个时钟周期内将期望的数值两次写入SWDD 位,所以程序中需要连续两次执行MCUCR = 1 << SWDD; 语句。紧接着是将系统的时钟源切换到外部晶振,虽然芯片自带16MHz 的内部RC振荡器,但其精度不满足USB通讯要求,故外接精度较高的无源晶振。最后是初始化定时器0中断,这将用于红外解码。在主函数的while死循环中,usbPoll(); 用于USB事务轮询,下面的两个if语句用于判断按键是否按下或释放,并建立相应的数据包上传给电脑。事实上,这里不像机械按键那样存在一直按下的行为,所以在发送按键按下的数据包后,立即发送按键释放的数据包。

前面说到,定时器0中断将用于红外解码,整个红外解码的方式采用了状态机的编程思想。笔者使用的是市面上常见的采用NEC协议的遥控器,NEC协议(如图4)根据脉冲时间长短编码,每个脉冲为560us长的38KHz载波(21个载波周期),逻辑“1”脉冲时间为2.25ms,逻辑“0”脉冲时间为1.12ms(如图5)。定时器0100us 中断一次,每次中断都检测红外接收器的DAT脚是否发生了电平翻转,并记录该时长,以此判断相应的逻辑位或是超时。由于V-USB已经占用了较高的CPU使用率,所以红外解码必须采用占CPU时间少的方式,状态机解码比其它方式更满足这个要求。同时,由于定时器0的中断优先级比外部中断2的优先级低,不必担心USB响应错误或超时。读者在购买红外遥控器的时候,应当向卖家索要该遥控器的键码表和用户码(如图7),特别指出的是,笔者将“EQ”按键定义为了“静音”键,“CH-”和“CH+”分别定义为了“睡眠”和“关机”,数字键和“CH”键没有用到。对于无法获知键码编码的情况,需要自行测试获取。在附件当中,笔者提供了一份用于获取键码的测试代码,结果通过串口输出到电脑。如想利用其他协议的遥控器,则需对解码部分进行修改。电路中的R4C4不可省去,以免干扰过大而无法工作。

 

图4 NEC帧格式

 

图5 逻辑1和逻辑0

 

逻辑分析仪捕获的红外一体化接收头输出波形(与发射波形反相)

 

遥控器外形及键码,第一个用户码为00,第二个为FF

为了让电脑认为这是一款USB键盘,必须将其描述为HID(人体工程学设备),usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH]数组中,正是相应的HID报告描述符,在该描述符中,按顺序规定了8个按键,这8个按键共占用一个字节,其中的每一bit用于描述按键的按下(1)和释放(0)。关于HID报告描述符的具体含义,笔者在源码中进行了详细注释,更为全面的介绍,可以参考网上的一篇技术博文(http://blog.csdn.net/cazicaquw/article/details/6724951)。如果读者朋友希望自定义其它功能,只需按规则改动这里即可,相关的描述符可以通过HID报告描述符生成工具(http://www.usb.org/developers/hidpage/dt2_4.zip)查阅,同时注意修改usbconfig.h文件当中USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH这个宏的值。

源代码整理好后,就可以进行编译了。V-USB推荐使用GCC进行编译,本文也不例外。打开VUSB-Sample文件夹下的Makefile文件,可以看到,“## General Flags”下的“MCU”被配置为“atmega164p”,也就是说,在开发LGT8F08A时,只需将其看作ATmega164p即可。“## Include Directories”下,“INCLUDES”需要根据你的实际的安装目录进行配置。修改完毕后,进入命令行操作界面,键入“make”并回车,便会完成编译并生成HEX文件。为了方便,笔者将一些常用操作整理成了一个批处理文件,每次编译仅需双击这个批处理文件即可。此外,对于习惯使用类似Keil 这种IDE软件的人来说,上面的这些操作,无论是编辑还是编译,都显得十分不便,笔者推荐大家可以试试TKStudio这款国产的IDE软件,无论是51AVR,还是ARM,都可轻松应对。更多详情,请参考TKStudio的官方网站

最后一步,就是把HEX文件烧录到单片机里。笔者使用的是LGT单片机专用ISP下载器(如图8),这款下载器可以自制,相关的原理图以及固件均可在绿智微电子官网下载,也可直接购买成品。如果读者手里有现成的用于AVR单片机的USBASP下载器,也可将其改制,用于LGT单片机的下载,甚至,普通的51单片机开发板也可以改制为下载器,具体的说明详见附件,这里不再赘述。

 

8 LGT_ISP下载器

 

图9 确保HID服务处于运行态

到这里,我们预期的目标算是基本达成了,有条件的朋友还可以找一个合适的外壳或是使用热缩管进行防尘防静电保护。有些使用精简版或是GHOST版系统的用户需要注意,如无法自动安装驱动,可能是缺少系统组件,按照电脑的提示从网上下载即可,另外,需要确保Human Interface Device Access服务处于“正在运行”状态(如图9),可以通过手动输入命令来设置,点击“开始”→“运行”,输入“sc start hidserv”并回车,需要设置为开机自启动的,在“运行”中输入“sc config hidserv start= auto”并回车(注意“auto”前有一空格)。对于有兴趣继续研究的朋友来说,这个小制作还可以变成USB接口的温度计,只需将红外接收头替换成DS18B20即可,又或是变成USB接口的显示器、I2C读写器、一键输入密码登录器等等,可扩展性很强,同时又能熟悉USB通信的各个环节,对于开发其它USB设备很有帮助。


资料包下载地址:http://www.hobbypress.cn/bencandy.php?fid-194-id-8220-page-1.htm


猜你喜欢

转载自blog.csdn.net/renpeng009672/article/details/43865593