做兼职推荐网站,网站广告位有哪些,制作一个网站的需要多少钱,wordpress主题php目录
一、 模块介绍
1.1 简介
1.2 协议
二、 驱动代码
三、 应用代码
四、 实验
五、 程序优化 一、 模块介绍
1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中#xff0c;像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和…目录
一、 模块介绍
1.1 简介
1.2 协议
二、 驱动代码
三、 应用代码
四、 实验
五、 程序优化 一、 模块介绍
1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和接收端如图下图所示。 发送端就是红外遥控器上面有许多按键当我们按下遥控器按键时遥控器内部电路会进行编码和调制再通过红外发射头将信号以肉眼不可见的红外线发射出去。红外线线虽然肉眼不可见但可以通过手机摄像头看到常用该方法检查遥控器是否正常工作。接收端是一个红外接收头收到红外信号后内部电路会进行信号放大和解调再将数据传给板子上的 GPIO板子收到数据后再解码才能确定是哪个按键被按下。 1.2 协议 我们按下遥控器按键的时候遥控器自动发送某个红外信号接收头接收到红外信号然后把红外信号转换成电平信号通过 IRD 这根线传给 SOC。整个传输只涉及单向传输由 HS0038 向主芯片传送。因此我们只需要编写程序从 IRD 上获取数据即可在这之前我们需要先了解下数据是怎么表示的也就是传输的红外数据的格式。 红外协议有 NEC、 SONY、 RC5、 RC6 等常用的就是 NEC 格式因此我们主要对 NEC 进行讲解。在分析文章中的波形之前我们先想象一下怎么在一条数据线上传输信号。开始传输数据之前一般都会发出一个 start 起始信号通知对方我开始传输数据了后面就是每一位每一位的数据。NEC 协议的开始是一段引导码 这个引导码由一个 9ms 的低脉冲加上一个 4.5ms 的高脉冲组成它用来通知接收方我要开始传输数据了。 然后接着的是数据数据由 4 字节组成地址、地址(取反)、数据、数据(取反)取反是用来校验用的。地址是指遥控器的 ID每一类遥控器的 ID 都不一样这样就可以防止操控电视的遥控器影响空调。数据就是遥控器上的不同按键值。从前面的图可以知道 NEC 每次要发 32 位地址、地址取反、数据、数据取反每个 8 位的数据。数据的 1 和 0开始都是 0.56ms 的低脉冲对于数据 1后面的高脉冲比较长对于数据 0后面的高脉冲比较短。 第一次按下按键时它会发出引导码地址地址取反数据数据取反。 如果这时还没松开按键这就是“长按”怎么表示“长按”遥控器会发送一个不一样的引导码这个引导码由 9ms 的低脉冲 2.25ms 的高脉冲组成表示现在按的还是上次一样的按键也叫连发码它会一直发送直到松开 二、 驱动代码
#include asm-generic/errno-base.h
#include linux/jiffies.h
#include linux/module.h
#include linux/poll.h#include linux/fs.h
#include linux/errno.h
#include linux/miscdevice.h
#include linux/kernel.h
#include linux/major.h
#include linux/mutex.h
#include linux/proc_fs.h
#include linux/seq_file.h
#include linux/stat.h
#include linux/init.h
#include linux/device.h
#include linux/tty.h
#include linux/kmod.h
#include linux/gfp.h
#include linux/gpio/consumer.h
#include linux/platform_device.h
#include linux/of_gpio.h
#include linux/of_irq.h
#include linux/interrupt.h
#include linux/irq.h
#include linux/slab.h
#include linux/fcntl.h
#include linux/timer.hstruct gpio_desc{int gpio;int irq;char *name;int key;struct timer_list key_timer;
} ;static struct gpio_desc gpios[] {{115, 0, irda, },
};/* 主设备号 */
static int major 0;
static struct class *gpio_class;/* 环形缓冲区 */
#define BUF_LEN 128
static unsigned char g_keys[BUF_LEN];
static int r, w;struct fasync_struct *button_fasync;static u64 g_irda_irq_times[68];
static int g_irda_irq_cnt 0;#define NEXT_POS(x) ((x1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r w);
}static int is_key_buf_full(void)
{return (r NEXT_POS(w));
}static void put_key(unsigned char key)
{if (!is_key_buf_full()){g_keys[w] key;w NEXT_POS(w);}
}static unsigned char get_key(void)
{unsigned char key 0;if (!is_key_buf_empty()){key g_keys[r];r NEXT_POS(r);}return key;
}static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);// static void key_timer_expire(struct timer_list *t)
static void key_timer_expire(unsigned long data)
{/* 超时 */g_irda_irq_cnt 0;put_key(-1);put_key(-1);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);
}/* 实现对应的open/read/write等函数填入file_operations结构体 */
static ssize_t irda_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned char kern_buf[2] ;int err;if (size ! 2)return -EINVAL;if (is_key_buf_empty() (file-f_flags O_NONBLOCK))return -EAGAIN;wait_event_interruptible(gpio_wait, !is_key_buf_empty());kern_buf[0] get_key(); /* device */kern_buf[1] get_key(); /* data */if (kern_buf[0] (unsigned char)-1 kern_buf[1] (unsigned char)-1)return -EIO;err copy_to_user(buf, kern_buf, 2);return 2;
}static unsigned int irda_poll(struct file *fp, poll_table * wait)
{//printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, gpio_wait, wait);return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}static int irda_fasync(int fd, struct file *file, int on)
{if (fasync_helper(fd, file, on, button_fasync) 0)return 0;elsereturn -EIO;
}/* 定义自己的file_operations结构体 */
static struct file_operations gpio_key_drv {.owner THIS_MODULE,.read irda_read,.poll irda_poll,.fasync irda_fasync,
};static void parse_irda_datas(void)
{u64 time;int i;int m, n;unsigned char datas[4];unsigned char data 0;int bits 0;int byte 0;/* 1. 判断前导码 : 9ms的低脉冲, 4.5ms高脉冲 */time g_irda_irq_times[1] - g_irda_irq_times[0];if (time 8000000 || time 10000000){goto err;}time g_irda_irq_times[2] - g_irda_irq_times[1];if (time 3500000 || time 55000000){goto err;}/* 2. 解析数据 */for (i 0; i 32; i){m 3 i*2;n m1;time g_irda_irq_times[n] - g_irda_irq_times[m];data 1;bits;if (time 1000000){/* 得到了数据1 */data | 1;}if (bits 8){datas[byte] data;byte;data 0;bits 0;}}/* 判断数据正误 */datas[1] ~datas[1];datas[3] ~datas[3];if ((datas[0] ! datas[1]) || (datas[2] ! datas[3])){printk(data verify err: %02x %02x %02x %02x\n, datas[0], datas[1], datas[2], datas[3]);goto err;}put_key(datas[0]);put_key(datas[2]);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);return;err:g_irda_irq_cnt 0;put_key(-1);put_key(-1);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);
}static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{struct gpio_desc *gpio_desc dev_id;u64 time;/* 1. 记录中断发生的时刻 */ time ktime_get_ns();g_irda_irq_times[g_irda_irq_cnt] time;/* 2. 累计中断次数 */g_irda_irq_cnt;/* 3. 次数达标后, 删除定时器, 解析数据, 放入buffer, 唤醒APP */if (g_irda_irq_cnt 68){parse_irda_datas();del_timer(gpio_desc-key_timer);g_irda_irq_cnt 0;}/* 4. 启动定时器 */mod_timer(gpio_desc-key_timer, jiffies msecs_to_jiffies(100));return IRQ_HANDLED;
}/* 在入口函数 */
static int __init irda_init(void)
{int err;int i;int count sizeof(gpios)/sizeof(gpios[0]);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);for (i 0; i count; i){ gpios[i].irq gpio_to_irq(gpios[i].gpio);setup_timer(gpios[i].key_timer, key_timer_expire, (unsigned long)gpios[i]);//timer_setup(gpios[i].key_timer, key_timer_expire, 0);err request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[i].name, gpios[i]);}/* 注册file_operations */major register_chrdev(0, 100ask_irda, gpio_key_drv); /* /dev/gpio_desc */gpio_class class_create(THIS_MODULE, 100ask_irda_class);if (IS_ERR(gpio_class)) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, 100ask_gpio_key);return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, irda); /* /dev/irda */return err;
}/* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数*/
static void __exit irda_exit(void)
{int i;int count sizeof(gpios)/sizeof(gpios[0]);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, 100ask_irda);for (i 0; i count; i){free_irq(gpios[i].irq, gpios[i]);del_timer(gpios[i].key_timer);}
}/* 7. 其他完善提供设备信息自动创建设备节点 */module_init(irda_init);
module_exit(irda_exit);MODULE_LICENSE(GPL);
三、 应用代码 #include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include stdio.h
#include string.h
#include poll.h
#include signal.hstatic int fd;/** ./button_test /dev/irda**/
int main(int argc, char **argv)
{unsigned char buf[2];/* 1. 判断参数 */if (argc ! 2) {printf(Usage: %s dev\n, argv[0]);return -1;}/* 2. 打开文件 */fd open(argv[1], O_RDWR);if (fd -1){printf(can not open file %s\n, argv[1]);return -1;}while (1){if (read(fd, buf, 2) 2)printf(get irda: deivce 0x%02x, data 0x%02x\n, buf[0], buf[1]);elseprintf(get irda: -1\n);}close(fd);return 0;
}
四、 实验 因为ip默认是dhcp分配的所以我ifconfig后dhcp会给我覆盖掉烦死啦所以配置一下永久生效的好了 auto lo
iface lo inet loopbackauto eth0
iface eth0 inet static
address 192.168.5.110
netmask 255.255.255.0
gareway 192.168.5.1 不是所有的按键都好使不知道为什么 五、 程序优化 #include asm-generic/errno-base.h
#include linux/jiffies.h
#include linux/module.h
#include linux/poll.h#include linux/fs.h
#include linux/errno.h
#include linux/miscdevice.h
#include linux/kernel.h
#include linux/major.h
#include linux/mutex.h
#include linux/proc_fs.h
#include linux/seq_file.h
#include linux/stat.h
#include linux/init.h
#include linux/device.h
#include linux/tty.h
#include linux/kmod.h
#include linux/gfp.h
#include linux/gpio/consumer.h
#include linux/platform_device.h
#include linux/of_gpio.h
#include linux/of_irq.h
#include linux/interrupt.h
#include linux/irq.h
#include linux/slab.h
#include linux/fcntl.h
#include linux/timer.hstruct gpio_desc{int gpio;int irq;char *name;int key;struct timer_list key_timer;
} ;static struct gpio_desc gpios[] {{115, 0, irda, },
};/* 主设备号 */
static int major 0;
static struct class *gpio_class;/* 环形缓冲区 */
#define BUF_LEN 128
static unsigned char g_keys[BUF_LEN];
static int r, w;struct fasync_struct *button_fasync;static u64 g_irda_irq_times[68];
static int g_irda_irq_cnt 0;#define NEXT_POS(x) ((x1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r w);
}static int is_key_buf_full(void)
{return (r NEXT_POS(w));
}static void put_key(unsigned char key)
{if (!is_key_buf_full()){g_keys[w] key;w NEXT_POS(w);}
}static unsigned char get_key(void)
{unsigned char key 0;if (!is_key_buf_empty()){key g_keys[r];r NEXT_POS(r);}return key;
}static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);// static void key_timer_expire(struct timer_list *t)
static void key_timer_expire(unsigned long data)
{/* 超时 */g_irda_irq_cnt 0;put_key(-1);put_key(-1);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);
}/* 实现对应的open/read/write等函数填入file_operations结构体 */
static ssize_t irda_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned char kern_buf[2] ;int err;if (size ! 2)return -EINVAL;if (is_key_buf_empty() (file-f_flags O_NONBLOCK))return -EAGAIN;wait_event_interruptible(gpio_wait, !is_key_buf_empty());kern_buf[0] get_key(); /* device */kern_buf[1] get_key(); /* data */if (kern_buf[0] (unsigned char)-1 kern_buf[1] (unsigned char)-1)return -EIO;err copy_to_user(buf, kern_buf, 2);return 2;
}static unsigned int irda_poll(struct file *fp, poll_table * wait)
{//printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, gpio_wait, wait);return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}static int irda_fasync(int fd, struct file *file, int on)
{if (fasync_helper(fd, file, on, button_fasync) 0)return 0;elsereturn -EIO;
}/* 定义自己的file_operations结构体 */
static struct file_operations gpio_key_drv {.owner THIS_MODULE,.read irda_read,.poll irda_poll,.fasync irda_fasync,
};static void parse_irda_datas(void)
{u64 time;int i;int m, n;unsigned char datas[4];unsigned char data 0;int bits 0;int byte 0;/* 1. 判断前导码 : 9ms的低脉冲, 4.5ms高脉冲 */time g_irda_irq_times[1] - g_irda_irq_times[0];if (time 8000000 || time 10000000){goto err;}time g_irda_irq_times[2] - g_irda_irq_times[1];if (time 3500000 || time 55000000){goto err;}/* 2. 解析数据 */for (i 0; i 32; i){m 3 i*2;n m1;time g_irda_irq_times[n] - g_irda_irq_times[m];data 1;bits;if (time 1000000){/* 得到了数据1 */data | 1;}if (bits 8){datas[byte] data;byte;data 0;bits 0;}}/* 判断数据正误 */datas[1] ~datas[1];datas[3] ~datas[3];if ((datas[0] ! datas[1]) || (datas[2] ! datas[3])){printk(data verify err: %02x %02x %02x %02x\n, datas[0], datas[1], datas[2], datas[3]);goto err;}put_key(datas[0]);put_key(datas[2]);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);return;err:g_irda_irq_cnt 0;put_key(-1);put_key(-1);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);
}static int get_irda_repeat_datas(void)
{u64 time;/* 1. 判断重复码 : 9ms的低脉冲, 2.25ms高脉冲 */time g_irda_irq_times[1] - g_irda_irq_times[0];if (time 8000000 || time 10000000){return -1;}time g_irda_irq_times[2] - g_irda_irq_times[1];if (time 2000000 || time 2500000){return -1;} return 0;
}static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{struct gpio_desc *gpio_desc dev_id;u64 time;/* 1. 记录中断发生的时刻 */ time ktime_get_ns();g_irda_irq_times[g_irda_irq_cnt] time;/* 2. 累计中断次数 */g_irda_irq_cnt;/* 3. 次数达标后, 删除定时器, 解析数据, 放入buffer, 唤醒APP */if (g_irda_irq_cnt 4){/* 是否重复码 */if (0 get_irda_repeat_datas()){/* device: 0, val: 0, 表示重复码 */put_key(0);put_key(0);wake_up_interruptible(gpio_wait);kill_fasync(button_fasync, SIGIO, POLL_IN);del_timer(gpio_desc-key_timer);g_irda_irq_cnt 0;return IRQ_HANDLED;}}if (g_irda_irq_cnt 68){parse_irda_datas();del_timer(gpio_desc-key_timer);g_irda_irq_cnt 0;return IRQ_HANDLED;}/* 4. 启动定时器 */mod_timer(gpio_desc-key_timer, jiffies msecs_to_jiffies(100));return IRQ_HANDLED;
}/* 在入口函数 */
static int __init irda_init(void)
{int err;int i;int count sizeof(gpios)/sizeof(gpios[0]);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);for (i 0; i count; i){ gpios[i].irq gpio_to_irq(gpios[i].gpio);setup_timer(gpios[i].key_timer, key_timer_expire, (unsigned long)gpios[i]);//timer_setup(gpios[i].key_timer, key_timer_expire, 0);err request_irq(gpios[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[i].name, gpios[i]);}/* 注册file_operations */major register_chrdev(0, 100ask_irda, gpio_key_drv); /* /dev/gpio_desc */gpio_class class_create(THIS_MODULE, 100ask_irda_class);if (IS_ERR(gpio_class)) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, 100ask_gpio_key);return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, irda); /* /dev/irda */return err;
}/* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数*/
static void __exit irda_exit(void)
{int i;int count sizeof(gpios)/sizeof(gpios[0]);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, 100ask_irda);for (i 0; i count; i){free_irq(gpios[i].irq, gpios[i]);del_timer(gpios[i].key_timer);}
}/* 7. 其他完善提供设备信息自动创建设备节点 */module_init(irda_init);
module_exit(irda_exit);MODULE_LICENSE(GPL); 这次没有那个-1了按下和弹起时都会有数据被拿到