> 文章列表 > ds18b20-温度传感器-linux驱动-混杂设备

ds18b20-温度传感器-linux驱动-混杂设备

ds18b20-温度传感器-linux驱动-混杂设备

文章目录

  • ds18b20读取温度数据步骤
  • ds18b20时序图:
    • 初始化时序
      • DS18B20初始化时序的步骤:
    • 读/写时序
      • DS18B20写步骤:
      • DS18B20读步骤:
  • DS18B20驱动实现
      • 结果如下:
      • 参考:

ds18b20读取温度数据步骤

  1. 初始化:将总线拉低至少480μs,然后释放总线并等待15μs。
  2. 发送“跳过ROM”命令(0xCC):该命令用于跳过在总线上连接的所有设备的唯一地址,直接定位到DS18B20。
  3. 发送“温度转换”命令(0x44):该命令告诉DS18B20开始进行温度转换,并将其存储在内部寄存器中。转换时间取决于DS18B20的分辨率设置,通常在750ms左右。
  4. 等待温度转换结束:可以使用忙等待方式,不断地向DS18B20发送“读取状态”命令(0xBE),当DS18B20返回0xFF时,表明温度转换已经完成。
  5. 发送“读取数据”命令(0xBE):该命令用于从DS18B20的内部寄存器中读取转换后的温度值。
  6. 读取温度值:从总线上读取9个字节的数据,其中第一个字节是温度的低8位,第二个字节是温度的高8位,第三个字节是温度的符号位(0代表正数,1代表负数),后面6个字节是校验位。
  7. 计算温度值:将低8位和高8位按照二进制拼接成16位的原始温度值,然后按照符号位进行判断,将原始温度值转换为实际温度值。

ds18b20时序图:

初始化时序

ds18b20-温度传感器-linux驱动-混杂设备

DS18B20初始化时序的步骤:

  1. 必须要拉低至少480us,这是复位信号;
  2. 然后拉高释放总线,等待15~60us之后,
  3. 若存在DS18B20,其会拉低总线60~240us表示DS18B20初始化复位成功。

读/写时序

ds18b20-温度传感器-linux驱动-混杂设备

DS18B20写步骤:

  • 写0,拉低至少60us,写周期为60-120us
  • 写1,拉低1us,写周期至少60us

DS18B20读步骤:

  • 整个读周期需要在15us内完成
  • 主机拉低总线至少1us,接着读取总线电平,为0表示读到的bit数据为0,若为1则表示读到数据是1

DS18B20驱动实现

使用混杂设备驱动框架

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/ioctl.h>
#include <cfg_type.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/ktime.h>// DS18B20设备节点名称
#define DS18B20_DEV_NAME    "ds18b20"
// DS18B20设备资源定义
#define DS18B20_GPIO_PIN 	(PAD_GPIO_C + 17)static void ds18b20_delay_us(int us)
{ktime_t kt;u64 pre,last;kt = ktime_get();pre = ktime_to_ns(kt);while(1){kt = ktime_get();last = ktime_to_ns(kt);if(last-pre >= us*1000){break;}}
}
static int ds18b20_pulse_init(void) {/* 设置引脚为输出模式 */gpio_direction_output(DS18B20_GPIO_PIN, 0);ds18b20_delay_us(500);  // 拉低至少480微秒gpio_direction_input(DS18B20_GPIO_PIN);ds18b20_delay_us(80);   // 等待传感器拉低if (gpio_get_value(DS18B20_GPIO_PIN) == 0) {  // 如果传感器存在ds18b20_delay_us(120);  // 等待传感器完成初始化return 1;}return 0;
}static void ds18b20_write_bit(int bit) {gpio_direction_output(DS18B20_GPIO_PIN, 0);if (bit)ds18b20_delay_us(10);elseds18b20_delay_us(60);gpio_direction_input(DS18B20_GPIO_PIN);ds18b20_delay_us(10);
}static void ds18b20_write_byte(uint8_t data) {int i;for (i = 0; i < 8; i++) {ds18b20_write_bit(data & 0x01);data >>= 1;}
}static uint8_t ds18b20_read_bit() {uint8_t bit;gpio_direction_output(DS18B20_GPIO_PIN, 0);ds18b20_delay_us(2);gpio_direction_input(DS18B20_GPIO_PIN);ds18b20_delay_us(10);bit = gpio_get_value(DS18B20_GPIO_PIN);ds18b20_delay_us(48);return bit;
}static uint8_t ds18b20_read_byte() {uint8_t data = 0;int i;for (i = 0; i < 8; i++) {data |= ds18b20_read_bit() << i;}return data;
}static float ds18b20_read_temperature() {uint8_t temp_l, temp_h;float temp;if (!ds18b20_pulse_init()) {printk(KERN_ERR "DS18B20 sensor not found\\n");return -1.0;}ds18b20_write_byte(0xCC);  // 跳过ROM指令ds18b20_write_byte(0x44);  // 温度转换命令mdelay(800);  				// 等待转换完成 至少750msif (!ds18b20_pulse_init()) {printk(KERN_ERR "DS18B20 sensor not found\\n");return -1.0;}ds18b20_write_byte(0xCC);  // 跳过ROM指令ds18b20_write_byte(0xBE);  // 读取scratchpad命令temp_l = ds18b20_read_byte();temp_h = ds18b20_read_byte();temp = ((temp_h << 8) | temp_l) / 16.0;return temp;
}static ssize_t ds18b20_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{float temp = ds18b20_read_temperature();if (copy_to_user(buf, &temp, sizeof(temp))){printk(KERN_ERR "ds18b20: failed to copy data to user\\n");return -EFAULT;}*f_pos += sizeof(temp);return sizeof(temp);
}static struct file_operations ds18b20_fops = {.owner          =   THIS_MODULE,.read           =   ds18b20_read,
};static struct miscdevice gec6818_adc_miscdev = {.minor		= MISC_DYNAMIC_MINOR,	//MISC_DYNAMIC_MINOR,动态分配次设备号.name		= "ds18b20",		//设备名称,/dev/ds18b20	.fops		= &ds18b20_fops,	//文件操作集
};static int __init ds18b20_init(void)
{int ret = -1;//混杂设备的注册ret = misc_register(&gec6818_adc_miscdev);if (ret) {printk("7""misc_register fail\\n");goto err_misc_register;}gpio_free(DS18B20_GPIO_PIN);	//防止gpio驱动有冲突先释放ret = gpio_request(DS18B20_GPIO_PIN, "ds18b20");if(ret < 0) {printk(KERN_ERR"gpio_request fail\\n");goto err_gpio_request;}printk(KERN_INFO "ds18b20: ds18b20 init.\\n");return 0;err_gpio_request:misc_deregister(&gec6818_adc_miscdev);
err_misc_register:return ret;
}static void __exit ds18b20_exit(void)
{misc_deregister(&gec6818_adc_miscdev);gpio_free(DS18B20_GPIO_PIN);printk(KERN_INFO "ds18b20: ds18b20 exit.\\n");
}module_init(ds18b20_init);
module_exit(ds18b20_exit);
MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define DS18B20_DEV_NAME            "/dev/ds18b20"int main(int argc, char **argv)
{int fd;int ret;float temp;// 打开设备节点fd = open(DS18B20_DEV_NAME, O_RDWR);if (fd < 0) {perror("open");exit(1);}while(1) {// 读取温度值ret = read(fd, &temp, sizeof(temp));if (ret < 0) {perror("read");close(fd);exit(1);}printf("tmp = %f\\n",temp);sleep(1);}// 关闭设备节点close(fd);return 0;
}

结果如下:

ds18b20-温度传感器-linux驱动-混杂设备

参考:

https://cloud.tencent.com/developer/article/1974916

https://blog.csdn.net/qq_36413982/article/details/122674749

https://blog.csdn.net/qq_45661238/article/details/114002415