前段时间做过一个通过gpio口来模拟红外loop out 的功能。整理记录一下.
GPIO:General Purpose Input Output (通用输入/输出)详情可查看Kernel 中的 GPIO 定义和控制
NEC:一种红外遥控器传输协议,由NEC开发.
从网上找到的概念图,很形象,借用一下:
红外遥控通常是由发送端和接收端两个部分组成。发送端将要发送的二进制信号编码成一系列的脉冲信号,然后通过红外发射管发射红外信号。
接收端完成对红外信号的接收,放大,整形,并解调出遥控编码脉冲。这个过程如下:
1.从上面图中可以看到 首先发送端是需要发送二进制信号编码,二进制信号编码由 Customer Code (客户码) 和 Data Code (数位码) 两部分构成。
2.一般都采用载波提高红外信频率,提高发射效率,载波频率为38KHZ:
用38KHZ的高频信号去调制然后通过红外二极管发射出去,那么就是在信号高电平期间加载波,
38K调制波形:
3.协议中一个bit的表示:
0:一个560us高电平+560us的低电平 合计 1.12ms
1:一个560us高电平+1690us的低电平 合计 2.25ms
如下图:代表一个1然后紧跟一个0
4.按键一次的NEC波形组成:
一个完整的NEC波形如下,它主要由5个部分组成:前导码(Head Code)+ 客户码(Customer Code)+ 客户反码 + 数位码(Data Code) + 数位反码
前导码也叫引导码 代表一次传输的起始标志:
9ms 高电平+4.5ms 低电平。
完整波形如图:
发的数据是:0x59 + 0xA6 + 0x16 +0xE9
都是从低位开始,后面会详细写发送过程。
5.重复按键NEC波形:
重复按键的引导码如下:
9ms 高电平+2.25ms 低电平。
它是以一个9ms的Head Code + 2.25ms的低电平 + 560us的高电平组成(必须拉高电平以区分2.25ms的低电平结束),
如下图正常发送一次nec之后一直重复:
6.软件解码模式图:
通过对IO口的拉高拉低,高低电平产生符合协议的波形,我的实现主函数如下:
void sendkeytodvb(U8 u8key) { printk("ir out put key for stb==%x\n",u8key); mdelay(100); U8 u8datOpposite = 0; u8datOpposite=~u8key; sendcarrier(9000,CARRIERNUM1); //delay 9ms mdelay(4); //delay 4.5 ms udelay(500); sendirbyte(GPIO_IR_HEADER_CODE0); sendirbyte(GPIO_IR_HEADER_CODE1); sendirbyte(u8key); sendirbyte(u8datOpposite); sendcarrier(560,CARRIERNUM2); }
以下是需要用到的GPIO口控制接口以及相关宏:
extern void MDrv_GPIO_Set_Low(U8 u8IndexGPIO); extern void MDrv_GPIO_Set_High(U8 u8IndexGPIO); #define GPIO_IR_HEADER_CODE0 0x08//0x10//0x00 /* Custom 0*/ #define GPIO_IR_HEADER_CODE1 0xF7//0xEF//0xFF /* Custom 1*/ #define CARRIERNUM1 90000/264 #define CARRIERNUM2 5600/264
高电平需要38KHZ载波调制:
void sendcarrier(U32 utime, U32 unum) { U32 icount = 0; while (1) { if (icount == unum) break; MDrv_GPIO_Set_High(gpioindex); udelay(13); MDrv_GPIO_Set_Low(gpioindex); udelay(13); ndelay(400); icount++; } MDrv_GPIO_Set_Low(gpioindex); }
因为考虑在liunx下对gpio口的操作耗时,想要做到完全和NEC协议一样的精确是很难实现的,细微的偏差是可以的,所以我在icount==unum时就break出来.
通过sendirbyte(...),来发送一个byte:
void sendirbyte(U8 u8keydata) { U8 u8Mask = 0x01; while (u8Mask) { sendbit(u8keydata & u8Mask); u8Mask <<= 1; } }
void sendbit(U8 byte) { sendcarrier(560, CARRIERNUM2); //delay 560us udelay(byte == 0x00 ? 560 : 1690); }
撰写不易,转载请注明出处 http://blog.csdn.net/jscese/article/details/21398961