017——DS18B20驱动开发(基于I.MX6uLL)

2024-04-08 22:28
文章标签 开发 驱动 017 ds18b20 mx6ull

本文主要是介绍017——DS18B20驱动开发(基于I.MX6uLL),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、 模块介绍

1.1 简介

1.2 主要特点

1.3 存储器介绍

1.4 时序

1.5 命令

1.5.1 命令大全   

1.5.2 命令使用

1.5.3 使用示例

1.6 原理图

二、 驱动程序

三、 应用程序

四、 测试


一、 模块介绍

1.1 简介

        DS18B20 温度传感器具有线路简单、体积小的特点,用来测量温度非常简单,在一根通信线上可以挂载多个 DS18B20 温度传感器。用户可以通过编程实现9~12 位的温度读数,每个 DS18B20 有唯一的 64 位序列号,保存在 rom 中,因此一条总线上可以挂载多个 DS18B20。

1.2 主要特点

■采用单总线接口仅需一个端口引脚进行通信
■每颗芯片具有全球唯一的64位的序列号
■具有多点分布式测温功能
■无需外围元器件
■可通过数据线供电;供电电压范围为2.5V∽5.5V
■测度测量范围为-55°C to +125°C(-67°F to +257°F)
■在-10°C∽70°C范围内精确度为±0.4°C
■温度分辨率9-12位可选
■最高12位精度下,温度转换速度小于400ms
■具有用户自定义的非易失性温度报警设置
■报名搜索命令识别并标识超过程序设定温度的器件
■超强静电保护能力:HBM 8000V MM 800V
■可提供贴片的MSOP8封装和3脚的TO-90封装
■应用包括温度控制、工业系统、消费品、粮情测温、温度计或任何感热系统

1.3 存储器介绍

        以前玩这个的时候都忽略这里了,就看时序图和数据帧了。

        DS18B20 内部有个 64 位只读存储器( ROM)和 64 位配置存储器( SCRATCHP)。64 位只读存储器( ROM)包含序列号等,具体格式如下图

        低八位用于 CRC 校验,中间 48 位是 DS18B20 唯一序列号,高八位是该系列产品系列号(固定为 28h)。因此,根据每个 DS18B20 唯一的序列号,可以实现一条总线上可以挂载多个 DS18B20 时,获取指定 DS18B20 的温度信息。

        64 位配置存储器( SCRATCHP)由 9 个 Byte 组成,包含温度数据、配置信息等,具体格式如下图:

⚫ Byte[0:1]:温度值。也就是当我们发出一个测量温度的命令之后,还需
要发送一个读内存的命令才能把温度值读取出来。
⚫ Byte[2:3]: TL 是低温阈值设置, TH 是高温阈值设置。当温度低于/超过
阈值,就会报警。 TL、 TH 存储在 EEPROM 中,数据在掉电时不会丢失;
⚫ Byte4:配置寄存器。用于配置温度精度为 9、 10、 11 或 12 位。配置寄存
器也存储在 EEPROM 中,数据在掉电时不会丢失;
⚫ Byte[5:7]:厂商预留;
⚫ Byte[8]: CRC 校验码。
 

1.4 时序

上面这些资料来源于这位老前辈的毕业设计翻译,翻译的挺好就是有点糊。

① ① 初始化时序
类似前面的 DHT11,主机要跟 DS18B20 通信,首先需要发出一个开始信号。
深黑色线表示由主机驱动信号,浅灰色线表示由 DS18B20 驱动信号。
最开始时引脚是高电平,想要开始传输信号,
a) 必须要拉低至少 480us,这是复位信号;
b) 然后拉高释放总线,等待 15~60us 之后,
c) 如果 GPIO 上连有 DS18B20 芯片,它会拉低 60~240us。
如果主机在最后检查到 60~240us 的低脉冲,则表示 DS18B20 初始化成功
② 写时序
⚫ 如果写 0,拉低至少 60us(写周期为 60-120us)即可;
⚫ 如果写 1,先拉低至少 1us,然后拉高,整个写周期至少为 60us 即可
③ 读时序
⚫ 主机先拉低至少 1us,随后读取电平,如果为 0,即读到的数据是 0,如果
为 1,即可读到的数据是 1。
⚫ 整个过程必须在 15us 内完成, 15us 后引脚都会被拉高
 

1.5 命令

(这块的图直接用韦东山老师的了,原来的老哥翻译的这个图片太马赛克了。但是韦老师的也不太好,后面有水印影响观感。)

1.5.1 命令大全   

     现在我们知道怎么发 1 位数据,收 1 位数据。发什么数据才能得到温度值,这需要用到“命令”。DS18B20 中有两类命令: ROM 命令、功能命令,列表如下:

1.5.2 命令使用

DS18B20 芯片手册中有 ROM 命令、功能命令的流程图,先贴出来,下一小节再举例。

1.5.3 使用示例

        总线上只一个 DS18B20 设备时,根据下表发送命令、读取数据。 因为只有一个 DS18B20,所以不需要选择设备,发出“ Skip ROM”命令。 然后发户“ ConvertT”命令启动温度转换;等待温度转换成功后,要读数据前,也要发出“ Skip ROM”命令。 下表列得很清楚:

        总线上有多个 DS18B20 设备时,根据下表发送命令、读取数据。 首先肯定是要选中指定设备:使用“ Match ROM”命令发出 ROM Code 来选择中设备; 然后发户“Convert T”命令启动温度转换; 等待温度转换成功后,要读数据前,也要发出“Match ROM”命令、 ROM Code。 下表列得很清楚:

1.6 原理图

二、 驱动程序

(今天破了一个案,dht11和ds18b20一点都不一样,以前一直没深入了解过ds18b20看来小觑它了)

#include "acpi/acoutput.h"
#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "asm/gpio.h"
#include "asm/uaccess.h"
#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>struct gpio_desc{int gpio;int irq;char *name;int key;struct timer_list key_timer;
} ;static struct gpio_desc gpios[] = {{115, 0, "ds18b20", },
};/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_class;static spinlock_t ds18b20_spinlock;static void ds18b20_udelay(int us)
{u64 time = ktime_get_ns();while (ktime_get_ns() - time < us*1000);
}static int ds18b20_reset_and_wait_ack(void)
{int timeout = 100;gpio_set_value(gpios[0].gpio, 0);ds18b20_udelay(480);gpio_direction_input(gpios[0].gpio);/* 等待ACK */while (gpio_get_value(gpios[0].gpio) && timeout--){ds18b20_udelay(1);}if (timeout == 0)return -EIO;/* 等待ACK结束 */timeout = 300;while (!gpio_get_value(gpios[0].gpio) && timeout--){ds18b20_udelay(1);}if (timeout == 0)return -EIO;return 0;}static void ds18b20_send_cmd(unsigned char cmd)
{int i;gpio_direction_output(gpios[0].gpio, 1);for (i = 0; i < 8; i++){if (cmd & (1<<i)) {/* 发送1 */gpio_direction_output(gpios[0].gpio, 0);ds18b20_udelay(2);gpio_direction_output(gpios[0].gpio, 1);ds18b20_udelay(60);}else{/* 发送0 */gpio_direction_output(gpios[0].gpio, 0);ds18b20_udelay(60);		gpio_direction_output(gpios[0].gpio, 1);}}
}static void ds18b20_read_data(unsigned char *buf)
{int i;unsigned char data = 0;gpio_direction_output(gpios[0].gpio, 1);for (i = 0; i < 8; i++){gpio_direction_output(gpios[0].gpio, 0);ds18b20_udelay(2);gpio_direction_input(gpios[0].gpio);ds18b20_udelay(15);if (gpio_get_value(gpios[0].gpio)){data |= (1<<i);}ds18b20_udelay(50);gpio_direction_output(gpios[0].gpio, 1);}buf[0] = data;
}/********************************************************/  
/*DS18B20的CRC8校验程序*/  
/********************************************************/   
/* 参考: https://www.cnblogs.com/yuanguanghui/p/12737740.html */   
static unsigned char calcrc_1byte(unsigned char abyte)   
{   unsigned char i,crc_1byte;     crc_1byte=0;                //设定crc_1byte初值为0  for(i = 0; i < 8; i++)   {   if(((crc_1byte^abyte)&0x01))   {   crc_1byte^=0x18;     crc_1byte>>=1;   crc_1byte|=0x80;   }         else     crc_1byte>>=1;   abyte>>=1;         }   return crc_1byte;   
}/* 参考: https://www.cnblogs.com/yuanguanghui/p/12737740.html */   
static unsigned char calcrc_bytes(unsigned char *p,unsigned char len)  
{  unsigned char crc=0;  while(len--) //len为总共要校验的字节数  {  crc=calcrc_1byte(crc^*p++);  }  return crc;  //若最终返回的crc为0,则数据传输正确  
}  static int ds18b20_verify_crc(unsigned char *buf)
{unsigned char crc;crc = calcrc_bytes(buf, 8);if (crc == buf[8])return 0;elsereturn -1;
}static void ds18b20_calc_val(unsigned char ds18b20_buf[], int result[])
{unsigned char tempL=0,tempH=0;unsigned int integer;unsigned char decimal1,decimal2,decimal;tempL = ds18b20_buf[0]; //读温度低8位tempH = ds18b20_buf[1]; //读温度高8位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; 				//小数两位}result[0] = integer;result[1] = decimal;
}/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t ds18b20_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{unsigned long flags;int err;unsigned char kern_buf[9];int i;int result_buf[2];if (size != 8)return -EINVAL;/* 1. 启动温度转换 *//* 1.1 关中断 */spin_lock_irqsave(&ds18b20_spinlock, flags);/* 1.2 发出reset信号并等待回应 */err = ds18b20_reset_and_wait_ack();if (err){spin_unlock_irqrestore(&ds18b20_spinlock, flags);printk("ds18b20_reset_and_wait_ack err\n");return err;}/* 1.3 发出命令: skip rom, 0xcc */ds18b20_send_cmd(0xcc);/* 1.4 发出命令: 启动温度转换, 0x44 */ds18b20_send_cmd(0x44);/* 1.5 恢复中断 */spin_unlock_irqrestore(&ds18b20_spinlock, flags);/* 2. 等待温度转换成功 : 可能长达1s */set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(msecs_to_jiffies(1000));/* 3. 读取温度 *//* 3.1 关中断 */spin_lock_irqsave(&ds18b20_spinlock, flags);/* 3.2 发出reset信号并等待回应 */err = ds18b20_reset_and_wait_ack();if (err){spin_unlock_irqrestore(&ds18b20_spinlock, flags);printk("ds18b20_reset_and_wait_ack second err\n");return err;}/* 3.3 发出命令: skip rom, 0xcc */ds18b20_send_cmd(0xcc);/* 3.4 发出命令: read scratchpad, 0xbe */ds18b20_send_cmd(0xbe);/* 3.5 读9字节数据 */for (i = 0; i < 9; i++){ds18b20_read_data(&kern_buf[i]);}/* 3.6 恢复中断 */spin_unlock_irqrestore(&ds18b20_spinlock, flags);/* 3.7 计算CRC验证数据 */err = ds18b20_verify_crc(kern_buf);if (err){printk("ds18b20_verify_crc err\n");return err;}/* 4. copy_to_user */ds18b20_calc_val(kern_buf, result_buf);err = copy_to_user(buf, result_buf, 8);return 8;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {.owner	 = THIS_MODULE,.read    = ds18b20_read,
};/* 在入口函数 */
static int __init ds18b20_init(void)
{int err;int i;int count = sizeof(gpios)/sizeof(gpios[0]);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);spin_lock_init(&ds18b20_spinlock);for (i = 0; i < count; i++){		err = gpio_request(gpios[i].gpio, gpios[i].name);gpio_direction_output(gpios[i].gpio, 1);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_ds18b20", &gpio_key_drv);  /* /dev/gpio_desc */gpio_class = class_create(THIS_MODULE, "100ask_ds18b20_class");if (IS_ERR(gpio_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_ds18b20");return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "myds18b20"); /* /dev/myds18b20 */return err;
}/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*/
static void __exit ds18b20_exit(void)
{int i;int count = sizeof(gpios)/sizeof(gpios[0]);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, "100ask_ds18b20");for (i = 0; i < count; i++){gpio_free(gpios[i].gpio);}
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(ds18b20_init);
module_exit(ds18b20_exit);MODULE_LICENSE("GPL");

三、 应用程序


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>static int fd;/** ./button_test /dev/myds18b20**/
int main(int argc, char **argv)
{int buf[2];int ret;int i;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s <dev>\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR | O_NONBLOCK);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}while (1) {if (read(fd, buf, 8) == 8)printf("get ds18b20: %d.%d\n", buf[0], buf[1]);elseprintf("get ds18b20: -1\n");sleep(5);}close(fd);return 0;
}

四、 测试

注意一下这次设备的名字前面有个my剩下的就是老样子,暂时先直接用韦老师的后面我在按需修改。

 

这篇关于017——DS18B20驱动开发(基于I.MX6uLL)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/886554

相关文章

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

JavaWeb系列六: 动态WEB开发核心(Servlet) 上

韩老师学生 官网文档为什么会出现Servlet什么是ServletServlet在JavaWeb项目位置Servlet基本使用Servlet开发方式说明快速入门- 手动开发 servlet浏览器请求Servlet UML分析Servlet生命周期GET和POST请求分发处理通过继承HttpServlet开发ServletIDEA配置ServletServlet注意事项和细节 Servlet注

手把手教你入门vue+springboot开发(五)--docker部署

文章目录 前言一、前端打包二、后端打包三、docker运行总结 前言 前面我们重点介绍了vue+springboot前后端分离开发的过程,本篇我们结合docker容器来研究一下打包部署过程。 一、前端打包 在VSCode的命令行中输入npm run build可以打包前端代码,出现下图提示表示打包完成。 打包成功后会在前端工程目录生成dist目录,如下图所示: 把

Sapphire开发日志 (十) 关于页面

关于页面 任务介绍 关于页面用户对我组工作量的展示。 实现效果 代码解释 首先封装一个子组件用于展示用户头像和名称。 const UserGrid = ({src,name,size,link,}: {src: any;name: any;size?: any;link?: any;}) => (<Box sx={{ display: "flex", flexDirecti

ROS2从入门到精通4-4:局部控制插件开发案例(以PID算法为例)

目录 0 专栏介绍1 控制插件编写模板1.1 构造控制插件类1.2 注册并导出插件1.3 编译与使用插件 2 基于PID的路径跟踪原理3 控制插件开发案例(PID算法)常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。 🚀详情:《ROS2从入门到精通》 1 控制插

JavaWeb 学习笔记 spring+jdbc整合开发初步

JdbcTemplate类是Spring的核心类之一,可以在org.springframework.jdbc.core中找到它。JdbcTemplate类在内部已经处理数据库的建立和释放,可以避免一些常见的错误。JdbcTemplate类可直接通过数据源的应用实例化,然后在服务中使用,也可在xml配置中作为JavaBean应用给服务使用直接上一个实例步骤1.xml配置 <?xml version

Android开发的一些不错的学习资料

一个有趣的学习网站:http://hukai.me/android-training-course-in-chinese/index.html 这个是一些基础的教程,看看很好的,赏心悦目。 工具下载网站:http://www.androiddevtools.cn/ 这里的东西很不错,AndroidStudio,UIStyle的压缩工具,开发必备。

同城跑腿APP开发,随叫随到超方便!

随着移动互联网的发展和人们生活节奏的加快,越来越多的人们没有闲暇的时间来做一些繁琐的事情,比如说买药、挂号、排队、送花、取文件等等。如果没有时间去处理这些事情怎么办?开发同城跑腿APP,提供跑腿服务,随时办事随时下单,只需在手机上轻轻一点,就可完成跑腿需求。 首先,跑腿小程序有几种开发方式。第一种是自己组建开发,这种方式比较适合有软件开发能力的企业,比较花费时间和金钱成本。第二种是找到第三方