- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
现在很多家电都使用了红外,而智能家居的诞生,连音响都带了红外遥控功能。为了解决家里遥控器比较多的情况,多数手机都支持了红外功能,这和以前的万能遥控器一样。这里主要记录红外接收的驱动,当然明白怎么接收的,对于遥控的发射就比较简单了.
外观 。
接收的工作原理 红外探头应该也是光敏电阻的一种,当接收到波长在750-1150NM的光时,OUT 引脚就会产生一个 38kHz 的 PWM 波。一般在电路中都会给 OUT 引脚进行一个上拉,所以没有检测到红外光时,OUT 引脚是稳定的高电平。通过这个现象我们就可以进行无线通信。 注意: 750-1150NM的光时是肉眼不可见的,不过可以通过手机摄像头进行查看 。
通信协议 了解完原理后,只需要配上相应的通信协议就可以使用红外进行无线通信了。常用的红外线信号传输协议有ITT协议、NEC协议、NokiaNRC协议、Sharp协议、SonySIRC协议、PhilipSRC-5协议、PhilipsRC-6协议,以及PhilipsRECS-80协议等.
需要了解不同协议区别的可以参考: 几种常用的红外线信号传输协议 ,红外的协议种类比较多,部分公司也会自己指定不同的协议,比如小米公司的遥控器,见 小米红外遥控器如何适配到其他应用设备之上 .
此笔记主要使用 NEC 协议完成驱动的编写,其他的协议驱动也可以参考完成.
数据帧格式 。
引导码 | 地址码0 | 地址码1 | 命令码 | 命令反码 | 引导码(重复) |
---|---|---|---|---|---|
LSB-MSB(0-7) | LSB-MSB(8-15) | LSB-MSB(16-23) | LSB-MSB(24-31) |
注意: 在标准的NEC协议中,地址码1为地址码0的反码,而在许多遥控器中,地址码0和地址码1共同作为红外遥控器的编码值.
PPM(脉冲位置调制) 。
接收波形 注意: 实际波形在低电平期间是一个 38kHz 的 PWM 波.
数据解析 在接收数据时需要过滤 38kHz 的波形,如下所示:
/**
* @brief 红外中断响应函数
*
* @param irq
* @param dev_id
* @return 0,成功;其他负值,失败
*/
static irqreturn_t infrared_interrupt(int irq, void *dev_id)
{
unsigned previous_offset; // 上一次的时间
unsigned start_offset; // 波型的起始时间差
long long now = ktime_to_us(ktime_get());
/* 由于红外接收传感器在接收到红外信号时产生一个38KHz的信号,所以接收时需要过滤,使信号变为一个低电平信号 */
/*-------------------------------- 滤波 --------------------------------*/
/* 从当前时刻开始接收一个下降沿开始的方波周期 */
if (0 == infrared_pwm.flag )
{
infrared_pwm.start_time = now;
infrared_pwm.flag = 1;
}
/* 计算两次下降沿的时差 */
previous_offset = now - infrared_pwm.previous;
infrared_pwm.previous = now;
/* 过滤红外接收器自生产生38KHz的信号,周期大约是 26us */
if (previous_offset < 60)
{
return IRQ_HANDLED;
}
/* 下降沿开始的时差,也就是一个周期的时间 */
start_offset = now - infrared_pwm.start_time;
/* 消除上次持续的信号 */
if (start_offset == 0)
{
return IRQ_HANDLED;
}
/* 完成一个周期的数据采集 */
infrared_pwm.flag = 0;
// infrared_pwm.low_time = start_offset - previous_offset + 52; // 低电平时间
// infrared_pwm.high_time = previous_offset - 52; // 高电平时间
/* NEC 解码 */
infrared_nec_decode(start_offset);
return IRQ_HANDLED;
}
在中断驱动中我使用了异步通知的方式,与应用程序进行通信 。
/**
* @brief 红外接收器初始化函数
*
* @return 0,成功;其他负值,失败
*/
static int infrared_init(void)
{
int res;
/* 申请 GPIO 资源 */
infrared_dev.gpio = INFRARED_GPIO;
res = gpio_request(infrared_dev.gpio, "infrared");
if (res)
{
pr_err("infrared dev: Failed to request gpio\n");
return res;
}
/* 将 GPIO 设置为输入模式 */
gpio_direction_input(infrared_dev.gpio);
/* 申请中断 */
infrared_dev.irq_num = gpio_to_irq(infrared_dev.gpio);
res = request_irq(infrared_dev.irq_num, infrared_interrupt, IRQF_TRIGGER_FALLING, "infrared", NULL);
if (res)
{
gpio_free(infrared_dev.gpio);
return res;
}
return 0;
}
/**
* @brief 打开设备
*
* @param inode 传递给驱动的 inode
* @param filp 设备文件,file 结构体有个叫做 private_data 的成员变量
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return 0 成功;其他 失败
*/
static int infrared_open(struct inode *inode, struct file *filp)
{
/* 将设备数据设置为私有数据 */
filp->private_data = &infrared_dev;
printk(PRINTK_GRADE "infrared_open\n");
return 0;
}
/**
* @brief 从设备读取数据
*
* @param filp 要打开的设备文件(文件描述符)
* @param buf 返回给用户空间的数据缓冲区
* @param count 要读取的数据长度
* @param offt 相对于文件首地址的偏移
* @return 0 成功;其他 失败
*/
static ssize_t infrared_read(struct file *filp, char __user *buf, size_t count, loff_t *offt)
{
int res = 0;
// struct infrared_dev_t *infrared_dev = filp->private_data;
res = copy_to_user(buf, infrared_receive_data, count);
if(res != 0) {
printk(PRINTK_GRADE "111111111111111\n");
return -1;
}
// printk(PRINTK_GRADE "infrared_read\n");
return 0;
}
/**
* @brief 向设备写数据
* @param filp 设备文件,表示打开的文件描述符
* @param buf 要写给设备写入的数据
* @param count 要写入的数据长度
* @param offt 相对于文件首地址的偏移
* @return 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t infrared_write(struct file *filp, const char __user *buf, size_t count, loff_t *offt)
{
int res = 0;
// struct infrared_dev_t *infrared_dev = filp->private_data;
char write_buf[1024] = {"0"};
res = copy_from_user(write_buf, buf, count);
if(res != 0) {
return -1;
}
printk("kernel recevdata:%s\r\n", write_buf);
return 0;
}
static int infrared_fasync(int fd, struct file *filp, int on)
{
struct infrared_dev_t *infrared_dev = filp->private_data;
printk(PRINTK_GRADE "infrared_fasync\n");
/* 异步通知初始化 */
return fasync_helper(fd, filp, on, &infrared_dev->fasync_queue);
}
/**
* @brief 关闭/释放设备
* @param filp 要关闭的设备文件(文件描述符)
* @return 0 成功;其他 失败
*/
static int infrared_release(struct inode *inode, struct file *filp)
{
int res = 0;
printk(PRINTK_GRADE "infrared_release\n");
/* 删除异步通知 */
infrared_fasync(-1, filp, 0);
return res;
}
/* 设备操作函数结构体 */
static struct file_operations infrared_ops = {
.owner = THIS_MODULE,
.open = infrared_open,
.read = infrared_read,
.write = infrared_write,
.release = infrared_release,
.fasync = infrared_fasync,
};
/**
* @brief 注册字符设备驱动
*
* @return 0,成功;其他负值,失败
*/
static int infrared_register(void)
{
int ret = -1; // 保存错误状态码
/* GPIO 中断初始化 */
ret = infrared_init();
/* 1、创建设备号 */
/* 采用动态分配的方式,获取设备编号,次设备号为0 */
/* 设备名称为 infrared_NAME,可通过命令 cat /proc/devices 查看 */
/* INFRARED_CNT 为1,只申请一个设备编号 */
ret = alloc_chrdev_region(&infrared_dev.devid, 0, INFRARED_CNT, INFRARED_NAME);
if (ret < 0)
{
pr_err("%s Couldn't alloc_chrdev_region, ret = %d \r\n", INFRARED_NAME, ret);
goto fail_region;
}
/* 2、初始化 cdev */
/* 关联字符设备结构体 cdev 与文件操作结构体 file_operations */
infrared_dev.cdev.owner = THIS_MODULE;
cdev_init(&infrared_dev.cdev, &infrared_ops);
/* 3、添加一个 cdev */
/* 添加设备至cdev_map散列表中 */
ret = cdev_add(&infrared_dev.cdev, infrared_dev.devid, INFRARED_CNT);
if (ret < 0)
{
pr_err("fail to add cdev \r\n");
goto del_unregister;
}
/* 4、创建类 */
infrared_dev.class = class_create(THIS_MODULE, INFRARED_NAME);
if (IS_ERR(infrared_dev.class))
{
pr_err("Failed to create device class \r\n");
goto del_cdev;
}
/* 5、创建设备,设备名是 INFRARED_NAME */
/*创建设备 INFRARED_NAME 指定设备名,*/
infrared_dev.device = device_create(infrared_dev.class, NULL, infrared_dev.devid, NULL, INFRARED_NAME);
if (IS_ERR(infrared_dev.device)) {
goto destroy_class;
}
return 0;
destroy_class:
device_destroy(infrared_dev.class, infrared_dev.devid);
del_cdev:
cdev_del(&infrared_dev.cdev);
del_unregister:
unregister_chrdev_region(infrared_dev.devid, INFRARED_CNT);
fail_region:
/* 释放个人初始化申请的资源,如del_init(); */
free_irq(infrared_dev.irq_num, NULL);
gpio_free(infrared_dev.gpio);
return -EIO;
}
/**
* @brief 注销字符设备驱动
*
* @return 0,成功;其他负值,失败
*/
static void infrared_unregister(void)
{
/* 1、删除 cdev */
cdev_del(&infrared_dev.cdev);
/* 2、注销设备号 */
unregister_chrdev_region(infrared_dev.devid, INFRARED_CNT);
/* 3、注销设备 */
device_destroy(infrared_dev.class, infrared_dev.devid);
/* 4、注销类 */
class_destroy(infrared_dev.class);
/* 释放中断 */
free_irq(infrared_dev.irq_num, NULL);
/* 释放 IO */
gpio_free(infrared_dev.gpio);
}
/**
* @brief 驱动入口函数
*
* @return 0,成功;其他负值,失败
*/
static int __init infrared_driver_init(void)
{
pr_info("infrared_driver_init\n");
return infrared_register();
}
/**
* @brief 驱动出口函数
*
* @return 0,成功;其他负值,失败
*/
static void __exit infrared_driver_exit(void)
{
pr_info("infrared_driver_exit\n");
infrared_unregister();
}
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(infrared_driver_init);
module_exit(infrared_driver_exit);
/* LICENSE 和作者信息 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("JIAOZHU");
MODULE_INFO(intree, "Y");
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
/***************************************************************
文件名 : infrared.c
作者 : jiaozhu
版本 : V1.0
描述 : 红外接收器驱动
其他 : 无
日志 : 初版 V1.0 2023/3/3
***************************************************************/
/* 红外接收器的数据引脚 59 */
#define INFRARED_GPIO 59
#define PRINTK_GRADE KERN_INFO
/*------------------ 字符设备内容 ----------------------*/
#define INFRARED_NAME "infrared"
#define INFRARED_CNT (1)
static unsigned char infrared_receive_data[4];
/*------------------ 设备数据结构体 ----------------------*/
struct infrared_dev_t
{
dev_t devid; // 设备号
struct cdev cdev; // cdev
struct class *class; // 类
struct device *device; // 设备
struct device_node *nd; // 设备节点
int irq_num; // 中断号
int gpio; // 数据接收引脚
struct fasync_struct *fasync_queue; // 异步相关结构体
};
struct infrared_dev_t infrared_dev; // 设备数据结构体
/*------------------ 红外波形过滤结构体 ----------------------*/
struct infrared_pwm_t
{
long long previous; // 记录上一次的时间,64bit
int flag; // 表示每个方波周期的开始
long long start_time; // 周期的起始时间
int low_time; // 低电平时间
int high_time; // 高电平时间
};
struct infrared_pwm_t infrared_pwm = // 红外波形采集
{
.flag = 0,
.previous = 0,
.start_time = 0,
.low_time = 0,
.high_time = 0,
};
/*------------------ 红外 NEC 数据解析结构体 ------------------*/
struct nec_decode_buf_t
{
int flag; // 表示 NEC 数据开始
unsigned times[128]; // 记录每帧的时间
int num; // 表示第几帧
};
struct nec_decode_buf_t nec_buf =
{
.flag = 0,
.num = 0,
};
/**
* @brief 红外 NEC 数据解析
*
* @param period 一个方波周期
*/
static void infrared_nec_decode(int period)
{
int i, j;
unsigned char temp;
if ((period > 13000) && (period < 14000))
{
nec_buf.flag = 1;
nec_buf.num = 0;
return;
}
if (nec_buf.num < 32)
{
nec_buf.times[nec_buf.num ++] = period;
}
if ((period > 10500) && (period < 13500))
{
if (nec_buf.flag)
{
for(i = 0; i < 4; i++) // 一共4个字节
{
temp = 0;
for(j = 0; j < 8; j++)
{
if ((nec_buf.times[i * 8 + j] > 2100) && (nec_buf.times[i * 8 + j] < 2400) )
{
temp |= 1 << j;
}
}
// printk("%02x ", temp);
infrared_receive_data[i] = temp;
}
// printk("\n");
nec_buf.flag = 0;
}
else
{
// printk(PRINTK_GRADE "Repetitive signal\n");
memset(infrared_receive_data, 0xFF, sizeof(infrared_receive_data));
}
/* 发送异步通知 */
kill_fasync(&infrared_dev.fasync_queue, SIGIO, POLL_IN);
}
}
/**
* @brief 红外中断响应函数
*
* @param irq
* @param dev_id
* @return 0,成功;其他负值,失败
*/
static irqreturn_t infrared_interrupt(int irq, void *dev_id)
{
unsigned previous_offset; // 上一次的时间
unsigned start_offset; // 波型的起始时间差
long long now = ktime_to_us(ktime_get());
/* 由于红外接收传感器在接收到红外信号时产生一个38KHz的信号,所以接收时需要过滤,使信号变为一个低电平信号 */
/*-------------------------------- 滤波 --------------------------------*/
/* 从当前时刻开始接收一个下降沿开始的方波周期 */
if (0 == infrared_pwm.flag )
{
infrared_pwm.start_time = now;
infrared_pwm.flag = 1;
}
/* 计算两次下降沿的时差 */
previous_offset = now - infrared_pwm.previous;
infrared_pwm.previous = now;
/* 过滤红外接收器自生产生38KHz的信号,周期大约是 26us */
if (previous_offset < 60)
{
return IRQ_HANDLED;
}
/* 下降沿开始的时差,也就是一个周期的时间 */
start_offset = now - infrared_pwm.start_time;
/* 消除上次持续的信号 */
if (start_offset == 0)
{
return IRQ_HANDLED;
}
/* 完成一个周期的数据采集 */
infrared_pwm.flag = 0;
// infrared_pwm.low_time = start_offset - previous_offset + 52; // 低电平时间
// infrared_pwm.high_time = previous_offset - 52; // 高电平时间
/* NEC 解码 */
infrared_nec_decode(start_offset);
return IRQ_HANDLED;
}
/**
* @brief 红外接收器初始化函数
*
* @return 0,成功;其他负值,失败
*/
static int infrared_init(void)
{
int res;
/* 申请 GPIO 资源 */
infrared_dev.gpio = INFRARED_GPIO;
res = gpio_request(infrared_dev.gpio, "infrared");
if (res)
{
pr_err("infrared dev: Failed to request gpio\n");
return res;
}
/* 将 GPIO 设置为输入模式 */
gpio_direction_input(infrared_dev.gpio);
/* 申请中断 */
infrared_dev.irq_num = gpio_to_irq(infrared_dev.gpio);
res = request_irq(infrared_dev.irq_num, infrared_interrupt, IRQF_TRIGGER_FALLING, "infrared", NULL);
if (res)
{
gpio_free(infrared_dev.gpio);
return res;
}
return 0;
}
/**
* @brief 打开设备
*
* @param inode 传递给驱动的 inode
* @param filp 设备文件,file 结构体有个叫做 private_data 的成员变量
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return 0 成功;其他 失败
*/
static int infrared_open(struct inode *inode, struct file *filp)
{
/* 将设备数据设置为私有数据 */
filp->private_data = &infrared_dev;
printk(PRINTK_GRADE "infrared_open\n");
return 0;
}
/**
* @brief 从设备读取数据
*
* @param filp 要打开的设备文件(文件描述符)
* @param buf 返回给用户空间的数据缓冲区
* @param count 要读取的数据长度
* @param offt 相对于文件首地址的偏移
* @return 0 成功;其他 失败
*/
static ssize_t infrared_read(struct file *filp, char __user *buf, size_t count, loff_t *offt)
{
int res = 0;
// struct infrared_dev_t *infrared_dev = filp->private_data;
res = copy_to_user(buf, infrared_receive_data, count);
if(res != 0) {
printk(PRINTK_GRADE "111111111111111\n");
return -1;
}
// printk(PRINTK_GRADE "infrared_read\n");
return 0;
}
/**
* @brief 向设备写数据
* @param filp 设备文件,表示打开的文件描述符
* @param buf 要写给设备写入的数据
* @param count 要写入的数据长度
* @param offt 相对于文件首地址的偏移
* @return 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t infrared_write(struct file *filp, const char __user *buf, size_t count, loff_t *offt)
{
int res = 0;
// struct infrared_dev_t *infrared_dev = filp->private_data;
char write_buf[1024] = {"0"};
res = copy_from_user(write_buf, buf, count);
if(res != 0) {
return -1;
}
printk("kernel recevdata:%s\r\n", write_buf);
return 0;
}
static int infrared_fasync(int fd, struct file *filp, int on)
{
struct infrared_dev_t *infrared_dev = filp->private_data;
printk(PRINTK_GRADE "infrared_fasync\n");
/* 异步通知初始化 */
return fasync_helper(fd, filp, on, &infrared_dev->fasync_queue);
}
/**
* @brief 关闭/释放设备
* @param filp 要关闭的设备文件(文件描述符)
* @return 0 成功;其他 失败
*/
static int infrared_release(struct inode *inode, struct file *filp)
{
int res = 0;
printk(PRINTK_GRADE "infrared_release\n");
/* 删除异步通知 */
infrared_fasync(-1, filp, 0);
return res;
}
/* 设备操作函数结构体 */
static struct file_operations infrared_ops = {
.owner = THIS_MODULE,
.open = infrared_open,
.read = infrared_read,
.write = infrared_write,
.release = infrared_release,
.fasync = infrared_fasync,
};
/**
* @brief 注册字符设备驱动
*
* @return 0,成功;其他负值,失败
*/
static int infrared_register(void)
{
int ret = -1; // 保存错误状态码
/* GPIO 中断初始化 */
ret = infrared_init();
/* 1、创建设备号 */
/* 采用动态分配的方式,获取设备编号,次设备号为0 */
/* 设备名称为 infrared_NAME,可通过命令 cat /proc/devices 查看 */
/* INFRARED_CNT 为1,只申请一个设备编号 */
ret = alloc_chrdev_region(&infrared_dev.devid, 0, INFRARED_CNT, INFRARED_NAME);
if (ret < 0)
{
pr_err("%s Couldn't alloc_chrdev_region, ret = %d \r\n", INFRARED_NAME, ret);
goto fail_region;
}
/* 2、初始化 cdev */
/* 关联字符设备结构体 cdev 与文件操作结构体 file_operations */
infrared_dev.cdev.owner = THIS_MODULE;
cdev_init(&infrared_dev.cdev, &infrared_ops);
/* 3、添加一个 cdev */
/* 添加设备至cdev_map散列表中 */
ret = cdev_add(&infrared_dev.cdev, infrared_dev.devid, INFRARED_CNT);
if (ret < 0)
{
pr_err("fail to add cdev \r\n");
goto del_unregister;
}
/* 4、创建类 */
infrared_dev.class = class_create(THIS_MODULE, INFRARED_NAME);
if (IS_ERR(infrared_dev.class))
{
pr_err("Failed to create device class \r\n");
goto del_cdev;
}
/* 5、创建设备,设备名是 INFRARED_NAME */
/*创建设备 INFRARED_NAME 指定设备名,*/
infrared_dev.device = device_create(infrared_dev.class, NULL, infrared_dev.devid, NULL, INFRARED_NAME);
if (IS_ERR(infrared_dev.device)) {
goto destroy_class;
}
return 0;
destroy_class:
device_destroy(infrared_dev.class, infrared_dev.devid);
del_cdev:
cdev_del(&infrared_dev.cdev);
del_unregister:
unregister_chrdev_region(infrared_dev.devid, INFRARED_CNT);
fail_region:
/* 释放个人初始化申请的资源,如del_init(); */
free_irq(infrared_dev.irq_num, NULL);
gpio_free(infrared_dev.gpio);
return -EIO;
}
/**
* @brief 注销字符设备驱动
*
* @return 0,成功;其他负值,失败
*/
static void infrared_unregister(void)
{
/* 1、删除 cdev */
cdev_del(&infrared_dev.cdev);
/* 2、注销设备号 */
unregister_chrdev_region(infrared_dev.devid, INFRARED_CNT);
/* 3、注销设备 */
device_destroy(infrared_dev.class, infrared_dev.devid);
/* 4、注销类 */
class_destroy(infrared_dev.class);
/* 释放中断 */
free_irq(infrared_dev.irq_num, NULL);
/* 释放 IO */
gpio_free(infrared_dev.gpio);
}
/**
* @brief 驱动入口函数
*
* @return 0,成功;其他负值,失败
*/
static int __init infrared_driver_init(void)
{
pr_info("infrared_driver_init\n");
return infrared_register();
}
/**
* @brief 驱动出口函数
*
* @return 0,成功;其他负值,失败
*/
static void __exit infrared_driver_exit(void)
{
pr_info("infrared_driver_exit\n");
infrared_unregister();
}
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(infrared_driver_init);
module_exit(infrared_driver_exit);
/* LICENSE 和作者信息 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("JIAOZHU");
MODULE_INFO(intree, "Y");
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <signal.h>
/***************************************************************
文件名 : drive_read_app.c
作者 : jiaozhu
版本 : V1.0
描述 : 驱动读取测试
其他 : 使用方法:./drive_read_app [/dev/xxx]
argv[1] 需要读取的驱动
日志 : 初版 V1.0 2023/3/3
***************************************************************/
int fd;
char *filename;
/**
* @brief 信号响应函数,用于读取红外接收的数据
*
* @param num 信号量
*/
void infrared_handler(int num)
{
int res;
unsigned char data_buf[4];
/* 从驱动文件读取数据 */
res = read(fd, data_buf, sizeof(data_buf));
if (res == 0)
{
printf("infrared data: %02x %02x %02x %02x\n", data_buf[0], data_buf[1], data_buf[2], data_buf[3]);
}
else
{
printf("read file %s failed!\r\n", filename);
}
}
/**
* @brief main 主程序
* @param argc argv 数组元素个数
* @param argv 具体参数
* @return 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int flags = 0;
if(argc != 2){
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
/* 打开驱动文件 */
fd = open(filename, O_RDWR);
if(!fd){
printf("Can't open file %s\r\n", filename);
return -1;
}
signal(SIGIO, infrared_handler);
/* 设置当前进程接收信号 */
fcntl(fd, F_SETOWN, getpid());
flags =fcntl(fd, F_GETFL);
/* 开启异步通知 */
fcntl(fd, F_SETFL, flags | FASYNC);
while (1);
close(fd);
return 0;
}
几种常用的红外线信号传输协议: https://tech.hqew.com/news_1050217 小米红外遥控器如何适配到其他应用设备之上:< https://blog.csdn.net/qq_40001346/article/details/108639243 。
最后此篇关于【Linux中断】红外接收器设备驱动的文章就讲到这里了,如果你想了解更多关于【Linux中断】红外接收器设备驱动的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!