基于ARM-LINUX的温度传感器驱动18B20(2)
2019-07-13 03:37发布
生成海报
Linux字符驱动之DS18B20温度传感器驱动
一、硬件分析
在 [OK210开发板体验]的第二篇:板载资源中,简单分析了DS18B20传感器的功能和作用。其实对DS18B20的操作,包含两部分,一是对字符设备驱动的深入理解,二是对DS18B20传感器时序的掌握。前面3篇功能体验,分别对GPIO的输出(LED)和输入(Key)进行了驱动的编写,而这篇将同时涉及GPIO的输入和输出。
首先从OK210的底板原理图中可知,OK210开发板上的DS18B20连接通过一个上拉电阻连接到了核心板的XM0ADDR3引脚上,如下图所示:
而XM0ADDR3引脚由S5PV210用户手册,可知,该引脚位于MP0_4[3]引脚上,默认连接到了EBI接口上,如下图所示:
所以,我们要对DS18B20进行操作,就是通过对MP0_4[3]引脚的设置进行实现
二、软件基础
该部分首先总结一下,字符设备驱动的注册过程,然后简单介绍一下DS18B20驱动编写过程中,注意的事项:
1 字符设备的注册与注销
以下的步骤,一般在驱动初始化函数中和驱动退出函数中实现。
第一步:注册设备号
信息#tail -f /var/log/message
注册函数:
register_chrdev_region() 或 查看#lsmod
alloc_chrdev_region() 或 查看#cat
/proc/devices
register_chrdev()
注销函数:
unregist_chrdev_region() 或
unregister_chrdev()
第二步:初始化cdev并添加到系统
初始化cdev
静态初始化cdev_init() 或
动态初始化cdev_alloc()
添加到系统函数
cdev_add()
从系统删除函数
cdev_del()
第三步:创建设备节点
创建类
class_create() 将放于/sysfs 查看#ls
/sys/class
删除类
class_destroy()
创建节点
device_create() 或 class_device_create() 将存放于/dev 查看#ls
/dev
删除节点
device_destroy() 或 class_device_destroy()
2
DS18B20注意事项 DS18B20是由DALLAS半导体公司推出的一种的“一线总线”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。一线总线结构具有简洁且经济的特点,可使用户轻松地组建传感器网络,从而为测量系统的构建引入全新概念,测量温度范围为-55~+125℃,精度为±0.5℃。现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,并且可根据实际要求通过简单的编程实现9~l2位的数字值读数方式。它工作在3—5.5
V的电压范围,采用多种封装形式,从而使系统设计灵活、方便,设定分辨率及用户设定的报警温度存储在EEPROM中,掉电后依然保存。其内部结构如下图所示:
ROM中的64位序列号是出厂前被光记好的,它可以看作是该DS18B20的地址序列码,每DS18B20的64位序列号均不相同。64位ROM的排列是:前8位是产品家族码,接着48位是DS18B20的序列号,最后8位是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。ROM作用是使每一个DS18B20都各不相同,这样就可实现一根总线上挂接多个。
所有的单总线器件要求采用严格的信号时序,以保证数据的完整性。DS18B20共有6种信号类型:复位脉冲、应答脉冲、写0、写1、读0和读1。所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。
1)复位脉冲和应答脉冲
单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480 us,,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时15~60
us,并进入接收模式(Rx)。接着DS18B20拉低总线60~240us,以产生低电平应答脉冲,
若为低电平,再延时480
us。
2)写时序
写时序包括写0时序和写1时序。所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。
3)读时序
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态。典型的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us。
三、驱动编程
如上所述,驱动的编写,主要包括两部分,一是根据DS18B20时序,编写读写函数,二是根据字符设备,编写设备驱动程序。具体的代码见下,最后附上效果图:
1
驱动代码
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define DEVICE_NAME "DS18B20"
-
-
static struct cdev cdev;
-
struct class *tem_class;
-
static dev_t devno;
-
static int major = 100;
-
- unsigned int gpio=S5PV210_MP04(3);
-
-
void tem_reset(void)
-
{
- s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
-
gpio_set_value(gpio, 1);
-
//gpio_direction_output(gpio,1);
-
udelay(100);
-
gpio_set_value(gpio, 0);
-
udelay(600);
-
gpio_set_value(gpio, 1);
-
udelay(100);
-
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
-
// gpio_direction_input(gpio);
-
}
-
-
void tem_wbyte(unsigned char data)
-
{
-
int i;
-
-
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
-
for (i = 0; i < 8; ++i)
-
{
-
gpio_set_value(gpio, 0);
-
udelay(1);
-
-
if (data & 0x01)
-
{
-
gpio_set_value(gpio, 1);
-
}
-
udelay(60);
-
gpio_set_value(gpio, 1);
-
udelay(15);
-
data >>= 1;
-
}
-
gpio_set_value(gpio, 1);
-
}
-
-
unsigned char tem_rbyte(void)
-
{
-
int i;
-
unsigned char ret = 0;
-
-
for (i = 0; i < 8; ++i)
-
{
-
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
-
gpio_set_value(gpio, 0);
-
// gpio_direction_output(gpio,0);
-
udelay(1);
-
gpio_set_value(gpio, 1);
-
-
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
-
// gpio_direction_input(gpio);
-
ret >>= 1;
-
if (gpio_get_value(gpio))
-
{
-
ret |= 0x80;
-
}
-
udelay(60);
-
}
-
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
-
-
-
return ret;
-
}
-
-
static ssize_t tem_read(struct file *filp, char *buf, size_t len, loff_t *offset)
-
{
-
unsigned char low, high;
-
-
tem_reset();
-
udelay(420);
-
tem_wbyte(0xcc);
-
tem_wbyte(0x44);
-
-
mdelay(750);
-
tem_reset();
-
udelay(400);
-
tem_wbyte(0xcc);
-
tem_wbyte(0xbe);
-
-
low = tem_rbyte();
-
high = tem_rbyte();
-
-
*buf = low / 16 + high * 16;
-
-
*(buf + 1) = (low & 0x0f) * 10 / 16 + (high & 0x0f) * 100 / 16 % 10;
-
return 0;
-
}
-
-
static struct file_operations tem_fops =
-
{
-
.owner = THIS_MODULE,
-
.read = tem_read,
-
};
-
-
static int __init tem_init(void)
-
{
-
int result;
-
devno = MKDEV(major, 0);
-
-
result = register_chrdev_region(devno, 1, DEVICE_NAME);
-
if (result)
-
{
-
printk("register failed
");
-
return result;
-
}
-
cdev_init(&cdev, &tem_fops);
-
cdev.owner = THIS_MODULE;
-
cdev.ops = &tem_fops;
-
result = cdev_add(&cdev, devno, 1);
-
if (result)
-
{
-
printk("cdev add failed
");
-
goto fail1;
-
}
-
-
tem_class = class_create(THIS_MODULE, "tmp_class");
-
if (IS_ERR(tem_class))
-
{
-
printk("class create failed
");
-
goto fail2;
-
}
-
-
device_create(tem_class, NULL, devno, DEVICE_NAME, DEVICE_NAME);
-
return 0;
-
fail2:
-
cdev_del(&cdev);
-
fail1:
-
unregister_chrdev_region(devno, 1);
-
return result;
-
}
-
-
static void __exit tem_exit(void)
-
{
-
device_destroy(tem_class, devno);
-
class_destroy(tem_class);
-
cdev_del(&cdev);
-
unregister_chrdev_region(devno, 1);
-
}
-
-
module_init(tem_init);
-
module_exit(tem_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("gjianw217@163.com");
-
MODULE_DESCRIPTION("DS18B20 driver");
复制代码
2 测试程序
-
#include "stdio.h"
-
#include "sys/types.h"
-
#include "sys/ioctl.h"
-
#include "stdlib.h"
-
#include "termios.h"
-
#include "sys/stat.h"
-
#include "fcntl.h"
-
#include "sys/time.h"
-
-
main()
-
{
-
int fd;
-
unsigned char buf[2]={0};
-
float result;
-
-
if ((fd=open("/dev/DS18B20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
-
{
-
printf("Open Device DS18B20 failed.
");
-
exit(1);
-
}
-
else
-
{
-
printf("Open Device DS18B20 successed.
");
-
while(1)
-
{
-
read(fd, buf, sizeof(buf));
-
printf("%d.%d C
", buf[0], buf[1]);
-
sleep(1);
-
}
-
close(fd);
-
}
-
}
复制代码
3 Makefile
-
#DS18B20 Makefile
-
ARCH=arm
-
CROSS_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
-
APP_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
-
#obj-m := app-drv.o
-
obj-m := ds18b20-drv.o
-
#KDIR := /path/to/kernel/linux/
-
KDIR := /home/ok210/android-kernel-samsung-dev/
-
PWD := $(shell pwd)
-
default:
-
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
-
app:ds18b20-app.c
-
$(APP_COMPILE)gcc -o app ds18b20-app.c
-
clean:
-
$(MAKE) -C $(KDIR) M=$(PWD) clea
复制代码
链接:http://www.forlinx.com/xiazai/96.htm
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮