HC-SR505人体感应模块(imx6ull)驱动与测试代码

HC-SR505在Linux下的驱动开发

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;
}

5.效果展示 

### STM32F103C8T6配合HC-SR505人体感应模块的使用方法 #### 1. 硬件连接 HC-SR505 是一款基于红外线技术的小型人体感应模块,适用于低功耗场景。将其 STM32F103C8T6 连接时,需注意以下几点: - **电源供应**:HC-SR505 的工作电压范围为 DC 3~5V,因此可以直接由 STM32 的 GPIO 输出供电[^1]。 - **信号输入/输出**:HC-SR505 提供了一个数字输出接口(OUT),当检测到人体移动时,该引脚会输出高电平;无人体活动时,则输出低电平。 以下是推荐的硬件连接表: | HC-SR505 引脚 | 功能 | 对应 STM32F103C8T6 引脚 | |----------------|--------------|----------------------------| | VCC | 工作电压 | PA8 (或其他可用 GPIO) | | OUT | 数字信号输出 | PB14 (外部中断引脚) | | GND | 地 | GND | #### 2. 初始化配置 为了使 STM32 正确读取 HC-SR505 的状态变化,需要对其进行初始化设置。具体代码如下: ```c #include "stm32f1xx_hal.h" void HC_SR505_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOB_CLK_ENABLE(); // 启用 GPIOB 时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 启用 GPIOA 时钟 // 配置 PB14 为输入模式(用于接收 HC-SR505 的 OUT 信号) GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; // 上升沿和下降沿触发中断 GPIO_InitStruct.Pull = GPIO_NOPULL; // 不启用上下拉电阻 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 配置 PA8 为输出模式(用于向 HC-SR505 提供电源) GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 设置速度为低速 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 开启外部中断并挂载回调函数 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } // 中断服务程序 void EXTI15_10_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_14)) { // 判断是否是 PB14 触发的中断 if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_SET) { Arrive_Flag = 1; // 检测到人体靠近 } else { Leave_Flag = 1; // 检测到人体离开 } __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_14); // 清除中断标志位 } } ``` 以上代码实现了对 HC-SR505 的初始化以及外部中断处理逻辑。通过 `Arrive_Flag` 和 `Leave_Flag` 变量可以分别捕获人体接近和远离事件[^4]。 #### 3. 应用实例 假设我们希望在检测到人体靠近时点亮 LED 并启动蜂鸣器报警,则可以在主循环中加入以下逻辑: ```c int main(void) { HAL_Init(); SystemClock_Config(); HC_SR505_Init(); // 初始化 HC-SR505 LED_Init(); // 初始化 LED 控制端口 Buzzer_Init(); // 初始化蜂鸣器控制端口 while (1) { if (Arrive_Flag) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); // 点亮 LED HAL_GPIO_WritePin(BUZZER_PORT, BUZZER_PIN, GPIO_PIN_SET); // 启动蜂鸣器 Arrive_Flag = 0; // 清零标志位 } if (Leave_Flag) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); // 关闭 LED HAL_GPIO_WritePin(BUZZER_PORT, BUZZER_PIN, GPIO_PIN_RESET); // 停止蜂鸣器 Leave_Flag = 0; // 清零标志位 } } } ``` 此示例展示了如何利用 HC-SR505 实现简单的安防功能[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值