Linux下18b20温度传感器驱动代码及测试实例

驱动代码:

#include    <linux/module.h>
#include    <linux/fs.h>
#include    <linux/kernel.h>
#include    <linux/init.h>
#include    <linux/delay.h>
#include    <linux/cdev.h>
#include    <linux/device.h>
#include    <linux/gpio.h>
#include    <plat/gpio-cfg.h>

#define    DEVICE_NAME "TEM0"

#define    TEM_SHOW_CODE 0x01

//static struct cdev cdev;
struct class *tem_class;
//static dev_t devno;
//static int major = 243;//可以用int alloc_chrdev_region(dev_t *dev,unsigned baseminor,
//unsigned count,const char *name);向系统动态申请未被占用的设备号。

struct tem_dev_t
{
    struct cdev cdev;
}tem_dev;

/**
 *  * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
 *   * @pin pin The pin number to configure.
 *    * @to to The configuration for the pin's function.
 *     *
 *      * Configure which function is actually connected to the external
 *       * pin, such as an gpio input, output or some form of special function
 *        * connected to an internal peripheral block.
 *         *
 *          * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
 *           * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
 *            * will then generate the correct bit mask and shift for the configuration.
 *             *
 *              * If a bank of GPIOs all needs to be set to special-function 2, then
 *               * the following code will work:
 *                *
 *                 *    for (gpio = start; gpio < end; gpio++)
 *                  *       s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
 *                   *
 *                    * The @to parameter can also be a specific value already shifted to the
 *                     * correct position in the control register, although these are discouraged
 *                      * in newer kernels and are only being kept for compatibility.
 *                       */
unsigned int gpio=0;

void tem_reset(void)
{
    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));//当x=0时是输入功能,x=1时是输出功能
    gpio_set_value(gpio, 1);
    udelay(100);//延迟0.1ms
    gpio_set_value(gpio, 0);
    udelay(600);
    gpio_set_value(gpio, 1);
    udelay(100);
    s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
}

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);
        udelay(1);
        gpio_set_value(gpio, 1);

        s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
        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;
}
/*******************************************************************
*
*ioctl 还不准确,需要改进
*    by mhb
*
**********************************************************************/
int tem_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{  
   printk("in the ioctl!!\n");//debug 
   switch(cmd)
   {
   case TEM_SHOW_CODE:
       {
           int i;
           unsigned char fc,sn[6],crc;
           tem_reset();
           udelay(400);
           tem_wbyte(0x33);
           fc = tem_rbyte;
           for (i = 0; i < 5; i++)
           {
               /* code */
               sn[i]=tem_rbyte;
           }
           crc=tem_rbyte;
           printk("familycode=%x\n",fc);
           printk("serialnumber=%x%x%x%x%x%x\n",sn[5],sn[4],sn[3],sn[2],sn[1],sn[0]);
           printk("crc=%x\n",crc);
           break;
       }
   default:
       {
          return - ENOTTY;
       }
   }
}

static struct file_operations tem_fops = 
{
    .owner    = THIS_MODULE,
    .read    = tem_read,
    .ioctl   =tem_ioctl,
};

static int __init tem_init(void)
{
    int result;
    int major;
    int minor;

    cdev_init(&tem_dev.cdev,&tem_fops);/*init cdev*/
    tem_dev.cdev.owner=THIS_MODULE;
//  devno = MKDEV(major, 0);
//  result = register_chrdev_region(devno, 1, DEVICE_NAME);
    result = alloc_chrdev_region(&tem_dev.cdev.dev,0,1,DEVICE_NAME);
    major=MAJOR(tem_dev.cdev.dev);
    minor=MINOR(tem_dev.cdev.dev);
    if(major)
    { 
        printk("majior=%d\n",major);
        printk("minor=%d\n",minor);
    }else
        printk("can not get device num!!\n");

    if (result)
    {
        printk("register failed\n");    
        return result;
    }
#ifdef CONFIG_OK210_BOARD_V2
     gpio=S5PV210_MP04(3);
#else
     gpio=S5PV210_GPH3(1);
#endif
//    cdev_init(&cdev, &tem_fops);
//    cdev.owner = THIS_MODULE;
//    cdev.ops = &tem_fops;
    result = cdev_add(&tem_dev.cdev, tem_dev.cdev.dev, 1);
    if (result)
    {
        printk("cdev add failed\n");    
        goto fail1;
    }

    tem_class = class_create(THIS_MODULE, "tmp_class");/*在sys目录下创建tmp_class这个类,/sys/class/~*/
    if (IS_ERR(tem_class))
    {
        printk("class create failed\n");    
        goto fail2;
    }

    device_create(tem_class, NULL, tem_dev.cdev.dev, DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/TEM0*/
    return 0;
fail2:
    cdev_del(&tem_dev.cdev);
fail1:
    unregister_chrdev_region(tem_dev.cdev.dev, 1);
    return result;
}

static void __exit tem_exit(void)
{
    device_destroy(tem_class, tem_dev.cdev.dev);
    class_destroy(tem_class);
    cdev_del(&tem_dev.cdev);
    unregister_chrdev_region(tem_dev.cdev.dev, 1);
}

module_init(tem_init);
module_exit(tem_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mhb");

测试代码:

#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"
#define TEM_SHOW 0x01
main()
{
    int fd;
#if 1
    unsigned char buf[2];
#else
    unsigned int tmp;
#endif
    float result;

    if ((fd=open("/dev/TEM0",O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
    {
        printf("Open Device DS18B20 failed.\r\n");
        exit(1);
    }
    else
    {
        printf("Open Device DS18B20 successed.\r\n");
        while(1)
        {
//            read(fd, buf, sizeof(buf));
//            result = tmp * 1000;
//            result = *(int *)buf;
            read(fd, buf, sizeof(buf));
#if 0
            printf("%d\n", buf[0]);
            printf("%d\n", buf[1]);
            result = (float)buf[0];
            result /= 16;
            result += ((float)buf[1] * 16);
#endif
#if 0
    //        printf("%f .C\r\n", result);
            sleep(1);
#else
                printf("%d.%d C\r\n", buf[0], buf[1]);
                sleep(1);
                ioctl(fd,TEM_SHOW,0);
#endif
        }
        close(fd);
    }
}

 

posted on 2013-08-25 15:32  熊猫酒仙是也  阅读(1281)  评论(0编辑  收藏  举报

导航