1.通过查询原理图可知:

传输协议:
1.起始信号:

平时是高电平,芯片拉低电平480us,然后变高电平,对方设备收到信号后回应低电平,设备准备好后拉高电平。
2.传输数据
主控芯片发出八位数据选中DS18B20,再发出八位数据命令,让设备转换采集温度。延时等待转换完成
3.复位

发出起始信号,主控芯片发出八位数据选中DS18B20, 再发出八位数据命令,读取设备上的数据。
4.设备模块发送8位数据+8位数据

写一位数据
写0:

主控拉低电平,提醒设备,主控芯片要发送数据了。30us后,设备读取引脚电平。
写1:

主控拉低电平,提醒设备,主控芯片要发送数据了。30us内主控芯片拉高电平,30us后,设备读取引脚电平。

读一位数据
读数据:

0

1
主控芯片至少拉低1us,通知设备,设备会马上设置引脚,发送0则会拉低电平,发送1则拉高电平,主控芯片在15us后读取电平。

驱动程序步骤:

#include <linux/module.h>
#include <linux/poll.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>
#include <linux/delay.h>
#include <linux/version.h>static int major;
static struct class *ds18b20_class;
static struct gpio_desc *ds18b20_data_pin;
static int irq;
static int ds18b20_data = 0;
static wait_queue_head_t ds18b20_wq;void ds18b20_delay_us(int us)
{u64 pre,last;pre = ktime_get_boot_ns();while(1){last = ktime_get_boot_ns();if(last-pre>=us*1000){break;}}
}int ds18b20_wait_for_ack(void)
{int timeout_count = 500;/*如果是高电平,等待*/while(gpiod_get_value(ds18b20_data_pin) && --timeout_count){udelay(1);}if(!timeout_count){return -1;}/*此时为低电平,是ds18b20发出的回应信号,等待变为高电平*/timeout_count = 500;while(!gpiod_get_value(ds18b20_data_pin) && --timeout_count){udelay(1);}if(!timeout_count){return -1;}return 0;/*此时成功*/}
static int ds18b20_reset(void)
{int ret;/*1.发出低电平脉冲*/gpiod_direction_output(ds18b20_data_pin,0);/*2.维持480us*/ds18b20_delay_us(480);/*因为udelay不准,需要用到ktime*//*设置为输入模式*/ret = gpiod_direction_input(ds18b20_data_pin);if(ds18b20_wait_for_ack())/*设置超时时间,当没有设备时,返回非零值*/{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -1;}elsereturn 0;
}
static void ds18b20_write_byte(unsigned char data)
{/*优先传输最低位*/int i;for(i = 0;i<8;i++){if(data & (1<<i)){/*输出1*/  gpiod_direction_output(ds18b20_data_pin,0);ds18b20_delay_us(2);/*设置为输入引脚,由于有上拉电阻,引脚默认为高电平*/gpiod_direction_input(ds18b20_data_pin);ds18b20_delay_us(60);}else{/*输出0*/gpiod_direction_output(ds18b20_data_pin,0);ds18b20_delay_us(60);/*设置为输入引脚,由于有上拉电阻,引脚默认为高电平*/gpiod_direction_input(ds18b20_data_pin);ds18b20_delay_us(2);}}
}unsigned char ds18b20_read_byte(void)
{unsigned char data =0;int i;for(i = 0;i<8;i++){/*设置输入引脚*/gpiod_direction_output(ds18b20_data_pin,0);    ds18b20_delay_us(2);/* 设置为输入 */gpiod_direction_input(ds18b20_data_pin);/* 7us之后读引脚 */ds18b20_delay_us(7);if(gpiod_get_value(ds18b20_data_pin)){data|=(1<<i);}/*读取到数据后等待60us*/    ds18b20_delay_us(60);}return data;
}/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t ds18b20_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned long flags;unsigned char tempL=0,tempH=0;unsigned int integer;unsigned char decimal1,decimal2,decimal;if (size != 5)return -EINVAL;local_irq_save(flags);    // 关中断if (ds18b20_reset()){gpiod_direction_output(ds18b20_data_pin, 1);local_irq_restore(flags);/*回复中断*/printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -ENODEV;}ds18b20_write_byte(0xcc);//忽略rom指令,直接使用功能指令ds18b20_write_byte(0x44);//温度转换指令gpiod_direction_output(ds18b20_data_pin, 1);/*设置回输出引脚,保持高电平*/local_irq_restore(flags);//让出cpu资源/*使用schedule_timeout函数时要先设置当前线程的状态,否则不起效果*/set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(HZ);//等待转换,延时1s()local_irq_save(flags);      // 关中断if (ds18b20_reset()){gpiod_direction_output(ds18b20_data_pin, 1);local_irq_restore(flags);/*回复中断*/printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return -ENODEV;}ds18b20_write_byte(0xcc);//忽略rom指令,直接使用功能指令ds18b20_write_byte(0xbe);//读暂存器中的数据tempL=ds18b20_read_byte();//读低八位温度tempH=ds18b20_read_byte();//读高八位温度if(tempH>0x7f)                                //最高位为1时温度是负{tempL    = ~tempL;                            //补码转换,取反加一tempH    = ~tempH+1;      integer  = tempL/16+tempH*16;               //整数部分decimal1 = (tempL&0x0f)*10/16;           //小数第一位decimal2 = (tempL&0x0f)*100/16%10;          //小数第二位decimal  = decimal1*10+decimal2;           //小数两位}else{integer  = tempL/16+tempH*16;                     //整数部分decimal1 = (tempL&0x0f)*10/16;                   //小数第一位decimal2 = (tempL&0x0f)*100/16%10;              //小数第二位decimal  = decimal1*10+decimal2;               //小数两位if(tempH>0x7f)                                 }local_irq_restore(flags);gpiod_direction_output(ds18b20_data_pin, 1);/*拷贝整数部分*/copy_to_user(buf,&integer,4);/*拷贝小数部分*/copy_to_user(buf+4,&decimal,1);return 5;
}static unsigned int ds18b20_drv_poll(struct file *fp, poll_table * wait)
{
//  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
//  poll_wait(fp, &ds18b20_wait, wait);return 0;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations ds18b20_fops = {.owner    = THIS_MODULE,.read    = ds18b20_drv_read,.poll    = ds18b20_drv_poll,
};/* 1. 从platform_device获得GPIO* 2. gpio=>irq* 3. request_irq*/
static int ds18b20_probe(struct platform_device *pdev)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 1. 获得硬件信息 */ds18b20_data_pin = gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH );//irq = gpiod_to_irq(ds18b20_echo);//request_irq(irq, ds18b20_isr, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "ds18b20", NULL);/* 2. device_create */device_create(ds18b20_class, NULL, MKDEV(major, 0), NULL, "myds18b20");return 0;
}static int ds18b20_remove(struct platform_device *pdev)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(ds18b20_class, MKDEV(major, 0));gpiod_put(ds18b20_data_pin);return 0;
}static const struct of_device_id ask100_ds18b20[] = {{ .compatible = "100ask,ds18b20" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver ds18b20_driver = {.probe      = ds18b20_probe,.remove     = ds18b20_remove,.driver     = {.name   = "100ask_ds18b20",.of_match_table = ask100_ds18b20,},
};/* 2. 在入口函数注册platform_driver */
static int __init ds18b20_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 注册file_operations     */major = register_chrdev(0, "ds18b20", &ds18b20_fops);  ds18b20_class = class_create(THIS_MODULE, "ds18b20_class");if (IS_ERR(ds18b20_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "ds18b20");return PTR_ERR(ds18b20_class);}init_waitqueue_head(&ds18b20_wq);err = platform_driver_register(&ds18b20_driver); return err;
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*     卸载platform_driver*/
static void __exit ds18b20_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);platform_driver_unregister(&ds18b20_driver);class_destroy(ds18b20_class);unregister_chrdev(major, "ds18b20");
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(ds18b20_init);
module_exit(ds18b20_exit);MODULE_LICENSE("GPL");

DS18B20驱动编程相关推荐

  1. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  2. linux内核_Linux驱动编程的本质就是Linux内核编程

    由于Linux驱动编程的本质属于Linux内核编程,因此我们非常有必要熟悉Linux内核以及Linux内核的特点. 这篇文章将会帮助读者打下Linux驱动编程的基础知识. 本篇文章分为如下三个小节进行 ...

  3. Linux驱动编程 step-by-step (二) 简单字符设备驱动

    简单字符设备驱动 1.主次设备号 主设备号标识设备连接的的驱动,此设备好由内核使用,标识在相应驱动下得对应的设备 在linux中设备号是一个32位的dev_t类型 typedef __u32    _ ...

  4. Linux驱动编程 step-by-step (五)主要的文件操作方法实现

    主要的文件操作方法实现 文件操作函数有很多的操作接口,驱动编程需要实现这些接口,在用户编程时候系统调用时候会调用到这些操作 [cpp] view plaincopy struct file_opera ...

  5. 数据即代码:元驱动编程

    几个小伙伴在考虑下面这个各个语言都会遇到的问题: 问题:设计一个命令行参数解析API 一个好的命令行参数解析库一般涉及到这几个常见的方面: 1) 支持方便地生成帮助信息 2) 支持子命令,比如:git ...

  6. [内核编程] 内核环境及其特殊性,驱动编程基础篇

    [内核编程] 内核环境及其特殊性,驱动编程基础篇  在学习汉江独钓一书后,打算总结一下内核编程应该注意的事项,以及有关的一些基础知识.第一次接触内核编程,还真是很生疏,很多东西不能一下马上消化.这里做 ...

  7. linux驱动read函数 copytouser,Linux驱动编程 step-by-step (五)主要的文件操作方法实现...

    主要的文件操作方法实现 文件操作函数有很多的操作接口,驱动编程需要实现这些接口,在用户编程时候系统调用时候会调用到这些操作 structfile_operations { ... loff_t (*l ...

  8. CAN 总线嵌入式驱动编程

    摘要:介绍了uclinux 操作系统的内核结构以及设备驱动编程的基本原理,并对CAN 总线的嵌入式系统进行了硬件设计及软件驱动编程,提出CAN 总线技术应用于嵌入式系统的一种方案. 1 引言     ...

  9. Windows驱动编程基础教程

    前言     本书非常适合熟悉Windows应用编程的读者转向驱动开发.所有的内容都从最基础的编程方法入手.介绍相关的内核API,然后举出示范的例子.这本书只有不到70页,是一本非常精简的小册子.所以 ...

  10. Windows驱动编程基础教程 (转)

     Windows驱动编程基础教程(转) 我经常在网上遇到心如火燎的提问者.他们碰到很多工作中的技术问题,是关于驱动开发的.其实绝大部分他们碰到的"巨大困难"是被老牛们看成初级得 ...

最新文章

  1. IT培训课、视频教程和书本之PK
  2. linux nm工具 查看静动态库导出函数
  3. maven_使用Maven将文件上传和下载到S3
  4. LintCode 1677. 石头(自定义优先队列)
  5. unreal4怎么设置游戏模式_ue4(虚幻4)基础 Unreal4 服务器模式详细介绍
  6. 20_python基础—面向对象-私有属性和私有方法
  7. Jquery常用开发插件收集
  8. 小甲鱼python电子版_小甲鱼学python
  9. leetcode 75.颜色分类
  10. 不能创建对象qmdispatch_运行时错误 429,ACTIVEX部件不能创建对象的解决方法小结...
  11. 互联网十大网络流行语
  12. 2000-2019全中国省、市、县企业注册数据(包含经纬度、注册数目等多指标信息)
  13. blockchain 初步了解区块链
  14. python的dev包怎么安装_python-dev如何安装 sudo apt-get install python-dev ?
  15. 华为鸿蒙电池,4700mAh电池+新鸿蒙系统华为Mate40,华为Mate30再创超低价神话
  16. k8s介绍及与docker搭建集群
  17. 嵌入式ARM设计编程(二) 字符串拷贝
  18. c语言 空指令的作用,单片机C语言编程空指令产生短延时怎么办
  19. css及css3学习
  20. 电子书籍下载网站集锦(不断更新中...)

热门文章

  1. 拦截器和过滤器的执行顺序和区别
  2. Hyperf初体验-JsonRpc的使用
  3. IP一键替换[非原创]
  4. 六安技师学院计算机网络技术,安徽六安技师学院2021年招生简章
  5. 从ISSCC2021论文看未来技术发展趋势
  6. duet设置_Duet Display 使用体验 - iPad 变身扩展屏幕
  7. 如何给计算机安装驱动程序,电脑系统怎么安装驱动程序
  8. usb网卡android驱动win7+64,万能USB驱动 for win7 64bit v2017.11.15.955
  9. python 常用快捷键
  10. 威纶触摸屏做modbus rtu主站控制风机 ZLAN5143的应用案例