基于迅为Itop4412开发板上控制ds18b20测量温度

原创 2016年09月25日 16:30:26

1、说明:

供电为3.3V(3—5V),DQ引脚为gpio的13脚;
如果要直接编译进入内核,需要配置内核驱动字符目录下的Makefile、Kconfig、make menuconfig三处文件,如果以平台设备的方式,还需配置mach-itop4412.c这个文件。原在4412上13脚原为485,需要先去掉。


2、驱动代码

/*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
#include <linux/init.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
#include <linux/module.h>
/*三个字符设备函数*/
#include <linux/fs.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
/*分配内存空间函数头文件*/
#include <linux/slab.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*MKDEV转换设备号数据类型的宏定义*/
#include <linux/kdev_t.h>
/*字符定义*/
#include <linux/string.h>
/*linux系统提供的申请端口函数和设置端口状态的函数*/
#include <linux/gpio.h>
/*设置GPIO状态,上下拉,输入输出就,复用等等相关函数*/
#include <plat/gpio-cfg.h>      
/*包含GPIO端口的宏定义*/
#include <mach/gpio-exynos4.h>
#include <linux/mm.h>
/*dev_t等的定义*/
#include <linux/types.h>
/*包含copy_to_user和copy_from_user的头文件*/
#include <asm/uaccess.h>
/*包含寄存器操作函数的头文件*/
#include <asm/io.h>
/*延时定义*/
#include <linux/delay.h>
/*包含函数device_create 结构体class等头文件*/
#include <linux/device.h>
/*错误诊断和输出需要的头文件*/
#include <linux/errno.h>

#define ds18b20_io (EXYNOS4_GPA0(7))/*4412开发板的gpio部分,gpio第13引脚,控制总线*/
#define DEVICE_NAME "ds18b20"   /*定义的设备节点,于/dev目录下,通过其对具体设备进行访问*/

#define ds18b20_MAJOR 245   /*主设备号*/
#define ds18b20_MINOR 0     /*次设备号*/
#define DEVICE_MINOR_NUM 1  /*次设备个数*/

/*主次设备号赋值*/
int ds18b20_major = ds18b20_MAJOR;
int ds18b20_minor = ds18b20_MINOR;

/*创建了一个总线类型,会在/sys/class下生成myclass目录*/
static struct class *ds18b20_class;

/*字符驱动结构体*/
struct ds18b20_dev{
    struct cdev cdev;
};
struct ds18b20_dev *ds18b20_device;

/*ds18b20的初始化*/
void ds18b20_reset(void)
{
    int ret;

    s3c_gpio_cfgpin(ds18b20_io,S3C_GPIO_SFN(1));/*配置成输出*/
    gpio_set_value(ds18b20_io,1);/* 向18B20发送一个上升沿,并保持高电平状态约100微秒*/
    udelay(100);
    gpio_set_value(ds18b20_io,0);/*向18B20发送一个下降沿,并保持低电平状态约600微秒*/
    udelay(600);
    gpio_set_value(ds18b20_io,1);/* 向18B20发送一个上升沿,此时可释放DS18B20总线*/
    udelay(100);
    /*以上操作是给DS18B20一个复位脉冲*/

    s3c_gpio_cfgpin(ds18b20_io,S3C_GPIO_SFN(0));/*配置为输入,可以检测到DS18B20是否复位成功*/
    /*如果低电平出现说明总线上有器件已做出应答*/
    ret = gpio_get_value(ds18b20_io);/*读取io上的电平.若总线在释放后总线状态为高电平,则复位失败*/
    /*if(!ret){
        printk(KERN_EMERG "ds18b20 init is success!\n");
    }
    else{
        printk(KERN_EMERG "ds18b20 init is failed!\n");
    }*/
}

/*写一个字节*/
/*写“1”时隙:
   保持总线在低电平1微秒到15微秒之间
   然后再保持总线在高电平15微秒到60微秒之间
   理想状态: 1微秒的低电平然后跳变再保持60微秒的高电平

写“0”时隙:
    保持总线在低电平15微秒到60微秒之间
    然后再保持总线在高电平1微秒到15微秒之间
    理想状态: 60微秒的低电平然后跳变再保持1微秒的高电平
    */
void write_data (unsigned char dat)
{
    unsigned char i;

    s3c_gpio_cfgpin(ds18b20_io,S3C_GPIO_SFN(1));/*端口设置为输出*/
    for(i=0;i<8;i++){
/*主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束。*/
        gpio_set_value(ds18b20_io,0);
        udelay(1);

        /*此处为写"1"*/
        /*若byte变量的D0位是1,则需向总线上写“1”
         根据写“1”时隙规则,电平在此处翻转为高*/
        if(((dat)&(0x01))==1)
            gpio_set_value(ds18b20_io,1);
        udelay(80);
        gpio_set_value(ds18b20_io,1);
        udelay(15);
        dat = dat>>1;
    }
    gpio_set_value(ds18b20_io,1);
}

/*读一个字节*/
/* 读“1”时隙:
    若总线状态保持在低电平状态1微秒到15微秒之间
    然后跳变到高电平状态且保持在15微秒到60微秒之间
    就认为从DS18B20读到一个“1”信号
    理想情况: 1微秒的低电平然后跳变再保持60微秒的高电平

读“0”时隙:
    若总线状态保持在低电平状态15微秒到30微秒之间
    然后跳变到高电平状态且保持在15微秒到60微秒之间
    就认为从DS18B20读到一个“0”信号
    理想情况: 15微秒的低电平然后跳变再保持46微秒的高电平
    */
unsigned char read_data(void)
{
    unsigned char i;
    unsigned char val = 0;

    for(i=0;i<8;i++){
        s3c_gpio_cfgpin(ds18b20_io,S3C_GPIO_SFN(1));
        gpio_set_value(ds18b20_io,0);
        udelay(1);
        val >>=1;
        gpio_set_value(ds18b20_io,1);
        s3c_gpio_cfgpin(ds18b20_io,S3C_GPIO_SFN(0));
        udelay(1);

        /*若总线在我们设它为低电平之后若1微秒之内变为高
          则认为从DS18B20处收到一个“1”信号
          因此把byte的D7为置“1”   */
        if(gpio_get_value(ds18b20_io))
            val = val | 0x80;
        udelay(60);
    }
    return val;
}

/*打开文件函数*/
static int ds18b20_open(struct inode *inide,struct file *flip)
{
    int ret;
    /*申请gpio*/
    ret = gpio_request(ds18b20_io,"DS18B20");
    if(ret<0){
        printk(KERN_EMERG "gpio_request is failed!\n");
        return 1;
    }
    printk(KERN_EMERG "open DS18B20\n");

    return 0;
}

/*读文件函数*/
static ssize_t ds18b20_read(struct file *flip,char __user *buff,size_t count,loff_t *f_ops)
{
    unsigned char buf[2];/*DS18B20将产生的温度数据以两个字节的形式存储到高速暂存器的温度寄存器中*/

    ds18b20_reset();
    udelay(420);
    write_data(0xcc);/*跳过序列号命令*/
    write_data(0x44);/*发送转换命令44H,完成温度测量和AD转换*/
    mdelay(800);
    ds18b20_reset();
    udelay(400);
    write_data(0xcc);
    write_data(0xbe);/*发送读取命令,从0位到第9位*/
    buf[0] = read_data();/*读取低位温度*/
    buf[1] = read_data();/*读取高位温度*/
    copy_to_user(buff,buf,sizeof(buf));/*传输数据到用户空间*/

    return 0;
}

static int ds18b20_release(struct inode *inode, struct file *filp)
{
    printk(KERN_EMERG "ds18b20_release is success!\n");

    return 0;
}

/*文件结构体*/
static struct file_operations ds18b20_fops = {
    .owner  =   THIS_MODULE,
    .open   =   ds18b20_open,
    .read   =   ds18b20_read,
    .release    =   ds18b20_release,
};

/*注册设备到系统*/
static void ds18b20_setup_cdev(struct ds18b20_dev *dev,int index)
{
    int err;
    /*获取设备号*/
    int devno = MKDEV(ds18b20_major,index);

    /*cdev结构体初始化*/
    cdev_init(&dev->cdev,&ds18b20_fops);
    dev->cdev.owner = THIS_MODULE;/*给cdev结构体赋值*/
    dev->cdev.ops = &ds18b20_fops;
    /*注册进系统*/
    err = cdev_add(&dev->cdev,devno,1);
    if(err){
        printk(KERN_EMERG "cdev_add %d is failed! %d\n",index,err);
    }
    else{
        printk(KERN_EMERG "cdev_add %d is success!\n",ds18b20_major);
    }
}

static int ds18b20_init(void)
{
    int ret = 0;
    /*dev_t在cdev字符驱动结构体里定义,必须通过dev_t来描述设备号*/
    dev_t ds18b20_dev;

    /*打印输出主次设备号*/
    printk(KERN_EMERG "ds18b20_major is %d!\n",ds18b20_major);
    printk(KERN_EMERG "ds18b20_minor is %d!\n",ds18b20_minor);

    /*申请主次设备号*/
    if(ds18b20_major){
        /*MKDEV为设备号处理宏命令*/
        ds18b20_dev = MKDEV(ds18b20_major,ds18b20_minor);
        /*主设备号不为0则静态注册设备*/
        ret = register_chrdev_region(ds18b20_dev,DEVICE_MINOR_NUM,DEVICE_NAME);
    }
    else{
        /*动态注册设备*/
        ret = alloc_chrdev_region(&ds18b20_dev,ds18b20_minor,DEVICE_MINOR_NUM,DEVICE_NAME);
        ds18b20_major = MAJOR(ds18b20_dev);/*得到主设备号*/
        printk(KERN_EMERG "alloc_chrdev_region is %d\n",ds18b20_major);
    }
    if(ret<0){
        printk(KERN_EMERG "register_chrdev_region is %d failed!\n",ds18b20_major);
    }
    /*创建一个ds18b20_class的总线*/
    ds18b20_class = class_create(THIS_MODULE,DEVICE_NAME);
    /*申请内存空间*/
    ds18b20_device = kmalloc(DEVICE_MINOR_NUM * sizeof(struct ds18b20_dev),GFP_KERNEL);
    if(!ds18b20_device){
        ret = -ENOMEM;
        goto fail;
    }
    /*清空内存空间的数据*/
    memset(ds18b20_device,0,DEVICE_MINOR_NUM*sizeof(struct ds18b20_dev));
    /*注册设备到系统*/
    ds18b20_setup_cdev(ds18b20_device,0);
    /*创建设备节点*/
    device_create(ds18b20_class,NULL,MKDEV(ds18b20_major,ds18b20_minor),NULL,DEVICE_NAME);
    printk(KERN_EMERG "ds18b20 is initation!\n");
    return 0;

    /*注册失败*/
fail:
    unregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),DEVICE_MINOR_NUM);
    printk(KERN_EMERG "ds18b20 exit!\n");
    return ret;
}

/*设备注销*/
static void __exit ds18b20_exit(void)
{
    /*注销设备号*/
    unregister_chrdev_region(MKDEV(ds18b20_major,ds18b20_minor),DEVICE_MINOR_NUM);
    /*注销设备*/
    cdev_del(&(ds18b20_device->cdev));
    /*摧毁设备节点*/
    device_destroy(ds18b20_class,MKDEV(ds18b20_major,ds18b20_minor));
    /*释放总线*/
    class_destroy(ds18b20_class);
    /*释放内存*/
    kfree(ds18b20_device);
    /*释放gpiio*/
    gpio_free(ds18b20_io);
}

module_init(ds18b20_init);
module_exit(ds18b20_exit);

MODULE_AUTHOR("star sky");/*作者*/
MODULE_DESCRIPTION("ITOP4412 ds18b20 driver");/*模块功能描述*/
MODULE_LICENSE("Dual BSD/GPL");/*开源声明*/
MODULE_VERSION("ds18b20 V1.0");/*代码修订版本*/

3、测试程序

#include <stdio.h>//标准输入输出
#include <sys/types.h>//open和creat函数需要的头文件
#include <sys/stat.h>//open和creat函数需要的头文件
#include <fcntl.h>//open和creat函数需要的头文件
#include <unistd.h>//close,read,write函数需要的头文件
#include <sys/ioctl.h>//ioctl函数需要的头文件

int main()
{
    int fd;
    unsigned int tem = 0;
    float temperature;
    char buf[10];
    char *ds18b20_node = "/dev/ds18b20";

/*O_RDWR只读打开,O_NDELAY非阻塞方式*/    
    if((fd = open(ds18b20_node,O_RDWR|O_NDELAY))<0)
    {
        printf("ds18b20 open %s failed",ds18b20_node);
        return -1;
    }
    else{
        /*printf("ds18b20 open %s success",ds18b20_node);*/
        while(1)
        {
            read(fd,buf,2);/*从buf中读出数据*/
            tem = buf[1];
            tem <<= 8;/*高位移到前面*/
            tem = tem | buf[0]; /*得到读出的数据*/
            /*18B20是定点数据表示方式,12.4的编码,
            即前12位是温度整数部分,后4位为小数部分,
            4位分辨率就是1/16;
            转换为10进制结果要乘以1/16=0.0625
            */
            temperature = tem*0.0625;/*要求出正数的十进制值,必须将读取到的LSB字节,MSB字节进行整合处理,然后乘以0.0625即可*/
            printf("temperature is :%7.4f\n",temperature);/*打印出温度*/
            tem = 0;
            sleep(1);
        }
    }

    close(fd);
    return 0;
}

4、Makefile

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译DS18B20.c这个文件编译成中间文件DS18B20.o
obj-m += DS18B20.o 

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
    make -C $(KDIR) M=$(PWD) modules

#make clean执行的操作是删除后缀为o的文件
clean:
    rm -rf *.mod.c *.o *.order *.mod.o *.symvers 

5、实验现象

实时测量温度:
这里写图片描述
注册的设备类:
这里写图片描述
设备节点:
这里写图片描述


6、参考链接

http://blog.csdn.net/tandesir/article/details/7247558
http://blog.csdn.net/benjamin_xc/article/details/5110483

版权声明:原创文章转载请注明出处。 举报

相关文章推荐

基于Tiny6410的ds18b20驱动

【更新】 2012-6-9,添加编译步骤的学习参考。  从网站上下载了lixin的mini2410的ds18b20代码,并做了修改,成功实现了Tiny6410的ds18b20驱动。感谢署名为lix...

iTop4412之DS18B20驱动开发

执行序列 通过单线总线端口访问 DS18B20 的协议如下: 步骤1. 初始化 步骤2. ROM 操作指令 步骤3. DS18B20 功能指令 步骤1. 初始化 主机首先发出一个480...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

Socket再学习——开发板ds18b20获取温度值并上报服务器

经过一段时间的学习、积累,自己对于物联网、计算机网络、socket编程等相关的领域和知识有了新的理解,网络部分一直是重中之重。因此重新再学习了Linux下的socket,并结合了一个简单的实际例子再来...

树莓派使用DS18B20模块测量温度

第一步,允许单总线接口sudo raspi-config 进入interfacingoptions enable one-wire interface第二步,接线 接BCM编码为4即图上物理引脚7第...

基于51单片机多路温度采集系统 采用读取ds18b20的序列号进行测量

#include"intrins.h" #include #define uchar unsigned char sbit dq=P1^5; sbit key_clk=P3^2;//键盘时钟...

DS18B20温度测量

 DS18B20 温度读取函数参考步骤: DS18B20 开始转换: 1.DS18B20 复位。 2.写入跳过 ROM 的字节命令,0xCC。 3.写入开始转换的功能命令,0x44。 ...

51+DS18B20测量温度(续)

上文中,我们提到要在一个具体的工程里面调用我们已经封装好的DS18B20来获取当前的温度。那么就来看看在下面的例子里面怎样调用已经写好的getTemp函数来实现测量温度的功能。 首先,我们的设计包括...
  • xmfthu
  • xmfthu
  • 2013-07-28 14:43
  • 1092

DS18B20温度测量报警 (可以设定温度上下限)

这是我大二的上学期的一个作品,代码有参考别人的,就是温度转换,LCD显示部分, 剩下的逻辑是自己写的, 给出来大家参考,代码没问题,实物验证过的。 #include #include uch...

迅为iTOP4412开发板上如何移植SDIO接口WIFI

近期需要把WiFi无线网络功能移植到在iTOP4412 开发平台,查阅了相关资料,经过一段时间的研究、调试,终于成功,将WiFi功能移植到了开发板上面,这里笔者记录移植过程及注意事项,方便以后工作需要...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)