45 超声波测距模块的linux platform驱动模型实现
来源:互联网 发布:易语言发送qq消息源码 编辑:程序博客网 时间:2024/06/05 07:43
//用一个头文件封装结构体表示超声波测距模块所用的io口
distancer.h
#ifndef __DISTANCER_H#define __DISTANCER_Htypedef struct { int trigger_io; //表示trigger的引脚 int echo_io; //捕捉数据的引脚 }mypdata_t;#endif /* __DISTANCER_H */
//////////////////
mypdev.c
#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>#include <mach/gpio.h>#include <linux/platform_device.h>#include "distancer.h"mypdata_t pdata = { .trigger_io = GPIOA(10), //PA10 .echo_io = GPIOA(9), //PA9};struct platform_device mydev = { .name = "distancer", .id = 0, .dev = { .platform_data = &pdata, }, .resource = NULL,};//生成初始化函数和卸载函数,并用module_init, module_exit指定相应的函数module_driver(mydev, platform_device_register, platform_device_unregister);MODULE_LICENSE("GPL");
平台设备驱动:
mypdrv.c
#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>#include <linux/gpio.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/ktime.h>#include <linux/slab.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/mutex.h>#include <linux/platform_device.h>#include "distancer.h"#define MYMAJOR 1234typedef struct { u64 prev; //记录超声波测距的上升沿中断时间 int started; //表示已接收到上升沿中断 int time; //测量的时间多少us int locked; struct mutex mutex; struct cdev cdev; mypdata_t *pdata;}mydata_t; //在设备驱动里每个超声波设备都用一个这类型的对象来记录时间ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off){ struct cdev *cdev = fl->f_path.dentry->d_inode->i_cdev; mydata_t *data = container_of(cdev, mydata_t , cdev); mypdata_t *pdata = data->pdata; int ret; //////// 发出开始信号/////// gpio_direction_output(pdata->trigger_io, 0); gpio_set_value(pdata->trigger_io, 1); msleep(1); gpio_set_value(pdata->trigger_io, 0); //上锁 data->locked = 1; ret = mutex_lock_interruptible(&data->mutex); if (ret < 0) return -ERESTART; data->locked = 0; //复制数据 sprintf(buf, "last time: %dus\n", data->time); return strlen(buf);}struct file_operations fops = { .read = myread,};irqreturn_t irq_func(int irqno, void *arg) //多个设备共用这个中断处理函数{ struct platform_device *pdev = (struct platform_device *)arg; mydata_t *data = platform_get_drvdata(pdev); mypdata_t *pdata = pdev->dev.platform_data; u64 now = ktime_to_us(ktime_get()); if (gpio_get_value(pdata->echo_io)) //高电平表示上升沿的中断 { data->started = 1; data->prev = now; } else if(data->started) //下降沿中断, 测量结束 { data->started = 0;// printk("%lldus\n", now - data->prev); data->time = (now - data->prev)>>1; if (data->locked) mutex_unlock(&data->mutex); } return IRQ_HANDLED;}static struct class *mycls;int myprobe(struct platform_device *pdev) //参数为则匹配上的设备对象的地址{ mypdata_t *pdata = pdev->dev.platform_data; int ret, irqno; mydata_t *data; dev_t devid; static int mi = 0; if (NULL == pdata) return -EINVAL; ret = gpio_request(pdata->trigger_io, pdev->name); if (ret < 0) goto err0; ret = gpio_request(pdata->echo_io, pdev->name); if (ret < 0) goto err1; irqno = gpio_to_irq(pdata->echo_io); ret = request_irq(irqno, irq_func, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, pdev->name, pdev); if (ret < 0) goto err2; data = kzalloc(sizeof(*data), GFP_KERNEL);//每个设备都分配一个记录时间的对象 platform_set_drvdata(pdev, data); // dev_set_drvdata(&pdev->dev, data) data->pdata = pdata; mutex_init(&data->mutex); mutex_lock(&data->mutex); devid = MKDEV(MYMAJOR, mi++); ret = register_chrdev_region(devid, 1, pdev->name); if (ret < 0) goto err3; cdev_init(&data->cdev, &fops); data->cdev.owner = THIS_MODULE; ret = cdev_add(&data->cdev, devid, 1); if (ret < 0) goto err4; device_create(mycls, NULL, data->cdev.dev, NULL, "%s.%d", pdev->name, pdev->id); printk("in myprobe ...%s.%d\n", pdev->name, pdev->id); return 0; //返回0表示设备驱动对刚匹配上的设备初始化成功,负数表示失败err4: unregister_chrdev_region(devid, 1);err3: kfree(data); free_irq(irqno, pdev);err2: gpio_free(pdata->echo_io);err1: gpio_free(pdata->trigger_io);err0: return ret;}int myremove(struct platform_device *pdev) //参数为需要结束驱动工作的设备对象的地址{ mypdata_t *pdata = pdev->dev.platform_data; int irqno = gpio_to_irq(pdata->echo_io); mydata_t *data = platform_get_drvdata(pdev); unregister_chrdev_region(data->cdev.dev, 1); cdev_del(&data->cdev); device_destroy(mycls, data->cdev.dev); free_irq(irqno, pdev); gpio_free(pdata->trigger_io); gpio_free(pdata->echo_io); kfree(data); printk("in myremove ...%s.%d\n", pdev->name); return 0;}struct platform_driver mydrv = { .probe = myprobe, .remove = myremove, .driver = { .owner = THIS_MODULE, .name = "distancer", //按名字匹配 },};static int __init test_init(void){ mycls = class_create(THIS_MODULE, "distancer"); return platform_driver_register(&mydrv);}static void __exit test_exit(void){ platform_driver_unregister(&mydrv); class_destroy(mycls);}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
//////////////////////
当多接入模块时,只需多增加一个platform_device对象来描述硬件接口即可.
当模块接的IO口需改变时,不需要修改设备驱动,只需修改设备部分的代码即可
阅读全文
0 0
- 45 超声波测距模块的linux platform驱动模型实现
- 11 H5上实现超声波测距模块的设备驱动
- 33 全志GPIO口的脚本配置及超声波测距模块的linux驱动
- STM32f407驱动hc-sr04超声波测距模块
- 超声波测距驱动
- Banana Pi的GPIO应用以及驱动HC-SR04超声波测距模块
- MC9S12XS128实现超声波测距
- S3C2440裸机实现超声波测距(US100模块)
- ARM-Linux定时器、中断驱动--超声波测距初试
- 51单片机超声波测距模块
- 树莓派蜂鸣器+超声波测距模块
- Linux platform 驱动模型
- [IMX6DL]超声波模块KS103 Linux驱动源代码
- 基于树莓派平台的超声波测距编程实现
- 超声波测距的最快算法
- STM32的超声波测距程序
- 基于stm32的超声波测距
- 基于Openmv的超声波测距
- 关于.NET编程中各种事务的实现
- URG和PSH
- spring Bean加载
- JavaScript之遍历
- 富文本方式超链接
- 45 超声波测距模块的linux platform驱动模型实现
- 统计学习笔记六----朴素贝叶斯
- 欢迎使用CSDN-markdown编辑器
- Spring的AOP原理
- javascript 中的index()属性与lastIndex()属性
- 正则相关常量
- WebGL画一个彩色矩形
- vue2.0脚手架的webpack 配置文件分析
- ARP脚本