前言:最近基于dragonboard410c上做一个demo,其中就要用到超声波模块来测距以达到当人靠近超声波一定距离的时候,驱动会上报single,激活应用层。这个驱动写的有点简单,如果大家有什么见解可以提出。
一、硬件搭建
1.Dragonboard410c开发板:
低速接口中pin1,pin23,pin25,ping35对应的GPIO接口,见《Low speed Expansion connector》分布图
2.US-100电平触发测距工作原理:
在模块上电前,首先去掉模式选择跳线上的跳线帽,使模块处于电平触发模式。
电平触发测距的时序如图:
只需要在 Trig/TX 管脚输入一个 10US 以上的高电平,系统便可发出 8 个 40KHZ 的超声波脉冲,然后检测回
波信号。当检测到回波信号后,模块还要进行温度值的测量,然后根据当前温度对测距结果进行校正,将校正后的结果通过Echo/RX 管脚输出。
在此模式下,模块将距离值转化为 340m/s 时的时间值的 2倍,通过 Echo 端输出一高电平,可根据此高电平的持续时间来计算距离值。即距离值为:(高电平时间*340m/s)/2。
3.按照下表的方式将US-100与开发板电气连接
二、软件环境搭建
根据blog教程在装有Ubuntu的主机上下载相应源码以及编译工具。
注意:在dts中要修改apq8016-***c.dtsi文件,增加超声波驱动的节点信息:
sonar{
compatible = "thundersoft,sonar";
thunder,poll_time =<50>;
thunder,gpio_cmd = <&msm_gpio 13 0>;
thunder,gpio_irq = <&msm_gpio 36 0>;
};
三、驱动编写
1.//匹配设备树定义接口
static int parse_dt(struct platform_device* pdev,struct us100_data* data){
int rc;
struct device_node* node = pdev->dev.of_node;
//将node 50 写入到poll_time中
rc = of_property_read_u32(node,"thunder,poll_time",&data->poll_time);
if(rc){
pr_warning("%s you should point time",__FUNCTION__);
data->poll_time = 20;
}
/* --TrigPin3---PIN25---- gpio13---- gpio_cmd ---cmd_gpio----------- */
data->cmd_gpio = of_get_named_gpio(node,"thunder,gpio_cmd",0);
/* --EchoPin2---PIN23---- gpio36---- gpio_irp ---echo_gpio----------- */
data->echo_gpio = of_get_named_gpio(node,"thunder,gpio_irq",0);
if(data->cmd_gpio<0 || data->echo_gpio<0){
pr_err("%s,error gpion",__FUNCTION__);
return -EINVAL;
}
return 0;
}
2.//启动、关闭方波产生
static ssize_t hs100_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size){
struct us100_data* data = dev_get_drvdata(dev);
int enable = simple_strtoul(buf,NULL,10);
if(enable){
//调用cmd_work_func
schedule_delayed_work(&data->cmd_work,0);
data->enable =1;
}
else{
//取消调用cmd_work_func
cancel_delayed_work_sync(&data->cmd_work);
data->enable=0;
}
return size;
}
3.//实现12us的方波功能
static void cmd_work_func(struct work_struct* work){
struct us100_data* data = container_of(work,struct us100_data,cmd_work.work);
gpio_set_value(data->cmd_gpio,1);
延迟12us产生方波
udelay(12);
gpio_set_value(data->cmd_gpio,0);//genarate a 12 us pluse
// printk("%s send cmdn",__FUNCTION__);
//激活工作队列中的cmd_work_func
schedule_delayed_work(&data->cmd_work,msecs_to_jiffies(data->poll_time));
}
//实现获得实际距离的功能
static void report_work_func(struct work_struct* work){
struct timespec now,last;
s64 diff_time;
/*---通过结构体中成员的首地址获结构体变量首地址---*/
struct us100_data* data = container_of(work,struct us100_data,report_work);
//时间格式转换
now = ktime_to_timespec(data->now_ktime);
last= ktime_to_timespec(data->last_ktime);
//时间差
diff_time = now.tv_sec*1000000000UL+now.tv_nsec-last.tv_sec*1000000000UL-last.tv_nsec;
// printk("ns=%lldn",diff_time);
mutex_lock(&data->data_lock);
//实际距离
data->distance = diff_time*170*100*10/1000000000UL;
mutex_unlock(&data->data_lock);
data-> data_ready = true;
// 唤醒data_queue 指定的注册在等待队列上的进程
wake_up_interruptible(&data->data_queue);
// printk("dis=%dn",data->distance);
}
|