先上张电路图。pcspkr就是PC机上小喇叭的线,当设定为某个频率时,会发出该频率的[0,+5v]方波信号。当在相应寄存器中写入0时,该引脚无信号。这样只要控制该寄存器值就能控制红外遥控信号的发出了。红外遥控器有一个基准频率,一般为36KHz或者38KHz,视具体的电视机而定,当频率偏离该值时,遥控距离迅速减小(猜测是因为无法达到足够的共振频率)。
上次软件篇中提到不能驱动pcspkr发出大于32khz的信号,事实证明这是pcspkr kernel module的一个限制。
http://lxr.free-electrons.com/source/drivers/input/misc/pcspkr.c
50 if (value > 20 && value < 32767) 51 count = PIT_TICK_RATE / value; |
这样pcspkr不能发出低于20HZ或者超过32767HZ的声音。严格的说这不算是一个bug,因为这已经属于人耳无法听到的范畴了,但是对想要发出高频红外信号的我来说,却是不小的困惑。
继续研究后,发现Linux下可以通过直接对端口读写来绕过这个限制。这样只需要在应用程序中使用pcspkr.c驱动中的这一小段code就行了。大概曾经在DOS下写过pc小喇叭程序的朋友应该都很熟悉这段code.
55 if (count) { 56 /* set command for counter 2, 2 byte write */ 57 outb_p(0xB6, 0x43); 58 /* select desired HZ */ 59 outb_p(count & 0xff, 0x42); 60 outb((count >> 8) & 0xff, 0x42); 61 /* enable counter 2 */ 62 outb_p(inb_p(0x61) | 3, 0x61); 63 } else { 64 /* disable counter 2 */ 65 outb(inb_p(0x61) & 0xFC, 0x61); 66 } |
在调试中发现红外发射管的发射强度比较弱(用摄像头和电视遥控器比较结果),于是把电阻换成47欧姆的了!这样最大电流是80毫安,但是因为方波信号的duty cycle是1/2,所以平均电流是40毫安,小于手册的最大持续电流,应该是安全的。PCSPKR只能发出方波信号,这种情况下反而成为一种优点了。
关于遥控器的代码,可以到lirc的网站上去下一个各种remote的网站的大集http://www.lirc.org/remotes.tar.bz2,只要你的遥控器不是太冷门,一般总能找到遥控器的代码。关于遥控器的编码格式可以从这篇博客入门http://jimlu.spaces.live.com/blog/cns!9B1C2AEA8D078F9A!609.entry?sa=211980024,lirc的文档中也能找到不少资料。
参考了下lirc的网站,各种home brew的红外接收发射方案都有,有用串口或者并口的,比较夸张的是通过声卡的line in接口做红外接收的信号分析的。不过貌似用pcspkr的没有,算是pc控制红外发射的一种新方法,呵呵。
最后放上程序,虽然不是通用的,不过稍加修改应该可以适用各种情况。
#include <fcntl.h> int console_fd; struct remote_space_enc panasonic_tv = inline void vsleep (usec) inline void _0 () } inline void _1 () inline void pulse(int usec) inline void space(int usec) inline void send_bits (int one[2], int zero[2], int code, int width) mask = 1<<(width-1); for (i=0;i<width;i++) { inline void send_code (struct remote_space_enc * remote, int code, int width) int main(int argc, char** argv) |
很赞!