1.HC-SR505原理
HC-SR505工作原理是根据人体发出的红外信号,发出高电平信号,持续时间在8s。工作电压4.5v-20v。详细原理参考HC-SR505 人体红外感应模块-优快云博客
2.设备树
smarthome-sr505 {
compatible = “smarthome -sr505”;
pinctrl-names = “default”;
pinctrl-0 = <&pinctrl_sr505>;
sr505-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
status = “okay”;
};
pinctrl_sr505:sr505grp {
fsl,pins = <
MX6UL_PAD_UART2_CTS_B__GPIO1_IO22 0x10B0
>;
};
采用的板子是正点原子的mini开发板,sr505信号输出线连接板子20号引脚
3.驱动代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/gpio/consumer.h>
/*设备结构体*/
struct sr505_dev{
int major; //主设备号
struct class *class; //类
struct device *device; //设备
struct device_node *nd; //设备节点
int gpio; //GPIO编号
int irq; //中断号
};
struct sr505_dev sr505_dev;
static struct gpio_desc *sr505_desc;
struct fasync_struct *sr_fasync; // fasync_struct结构体指针
static irqreturn_t sr505_handler(int irq, void *dev_id)
{
kill_fasync(&sr_fasync,SIGIO,POLL_IN); //向应用程序发送通知,可以访问设备
return IRQ_HANDLED;
}
static int sr505_open (struct inode *node, struct file *filp)
{
return 0;
}
static ssize_t sr505_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
char val;
int ret;
val = gpiod_get_value(sr505_desc);
ret = copy_to_user(buf, &val, 1);
if(ret != 0){
printk("sr505 read failed\n");
}
return 1;
}
static int sr505_fasync (int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &sr_fasync); //初始化sr_fasync结构体
if (retval < 0)
return retval;
return 0;
}
static int sr505_release (struct inode *node, struct file *filp)
{
sr505_fasync(-1,filp,0); //删除异步通知
free_irq(sr505_dev.irq,NULL);
return 0;
}
static struct file_operations sr505_ops = {
.owner = THIS_MODULE,
.open = sr505_open,
.release = sr505_release,
.fasync = sr505_fasync,
.read = sr505_read,
};
static int sr505_init(void)
{
int err;
int ret;
sr505_dev.nd = of_find_node_by_path("/smarthome-sr505");
sr505_dev.gpio = of_get_named_gpio(sr505_dev.nd,"sr505-gpio",0); //获取GPIO标号
printk("sr505-gpio number: %d\n",sr505_dev.gpio);
err = gpio_request(sr505_dev.gpio,"sr505_gpio");
if(err != 0){
printk("gpio request failed\n");
return 0;
}
sr505_desc = gpio_to_desc(sr505_dev.gpio);
ret = gpiod_direction_input(sr505_desc);
if(ret < 0){
printk("can not set direction\n");
}
/*申请中断号 申请中断*/
sr505_dev.irq = gpio_to_irq(sr505_dev.gpio);
ret = request_irq(sr505_dev.irq,sr505_handler,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,"sr505_irq",NULL);
if(ret){
printk("request_irq failed\n");
return -1;
}
sr505_dev.major = register_chrdev(0 , "sr505", &sr505_ops);
sr505_dev.class = class_create(THIS_MODULE, "sr505_class");
sr505_dev.device = device_create(sr505_dev.class, NULL, MKDEV(sr505_dev.major, 0), NULL, "sr505");
return 0;
}
static void sr505_exit(void)
{
device_destroy(sr505_dev.class, MKDEV(sr505_dev.major, 0));
class_destroy(sr505_dev.class);
unregister_chrdev(sr505_dev.major, "sr505");
gpio_free(sr505_dev.gpio);
}
module_init(sr505_init);
module_exit(sr505_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("keane");
MODULE_VERSION("v1.0");
4.测试代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <poll.h>
int fd;
void handler(int signum)
{
close(fd);
exit(0);
return 0;
}
void sr505_sigio(int signum)
{
char val;
read(fd, &val, 1);
printf("val is %d, %s\n", val, val==1?"have people":"no people");
}
int main(int argc, char *argv[])
{
char buf[10];
int val;
char status = 1;
int flags;
int tim;
signal(SIGINT, handler); /* ctrl+c */
signal(SIGIO, sr505_sigio);
fd = open("/dev/sr505", O_RDWR);
if(fd < 0){
printf("/dev/sr505 open failed\n");
return 1;
}
fcntl(fd, F_SETOWN, getpid()); //当前进程号告诉内核
flags = fcntl(fd, F_GETFL); //获取当前进程状态
fcntl(fd, F_SETFL, flags | O_ASYNC); //设置进程启用异步通知功能
while(1){
sleep(1);
}
return 0;
}