单片机
返回首页

S5PV210之温度传感器DS18B20 linux3.0.8驱动

2024-12-31 来源:cnblogs

一 Ds18b20功能描述

 FEATURES(特点)

1) Unique 1-WireTM interface requires only oneport pin for communication

独特的单总线接口,使用一个引脚实现双线通线
2) Multidrop capability simplifies distributed temperature sensing applications

多分功能简化分布式温度传感器的应用
3) Requires no external components

不需要外部器件
4) Can be powered from data line.  Power supply range is 3.0V to 5.5V

可以从数据线获得电压。功作电源3-5.5V
5) Zero standby power required

不需要备用电源
6) Measures temperatures from -55°C to +125°C. Fahrenheit equivalent is -67°F to
+257°F 

测温范围:-55~+125°C, 等效于华氏温度范围:-67~257°F

7) ±0.5°C accuracy from -10°C to +85°C

-10~85°C范围的分辨率为±0.5°C
8) Thermometer resolution is programmable from 9 to 12 bits

可编程温度计分辨率范围9~12位(测量结果以9~12位数字量存储);
9) Converts 12-bit temperature to digital word in 750 ms (max.)
10) User-definable, nonvolatile temperature alarm settings
11) Alarm search command identifies and addresses devices whose temperature is
outside of programmed limits (temperature alarm condition)
12) Applications include thermostatic controls, industrial systems, consumer products,
thermometers, or any thermally sensitive system

 

二. Ds18b20时序分析

  ds18b20时序分为:复位时序,读时序,写时序。 

  最好按时序来编程,这样可以增强可移植性。

  具体的时序分析,网上或苡片资料上有。

  比如:ds18b20写时序

从上图可知,在前15us内首先把数据线拉低然后写0或1,然后ds18b20在15~60us间自动读取数据线的值。写该时序代码时,最好在15内向ds18b20数据线写值,并等待ds18b20反应30us以上。案例二上有说明。

三. 总结

案例一:总结:错在81行return((gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01);
    导致读的值为0;
    原因:因为gpio_get_value(S5PV210_GPE0(3))函数返回的
    值为指定引脚的高或低电平,即1或0。

案例二:错误总结:

  错误部分:dat >>1;

       temp = gpio_get_value(S5PV210_GPE0(3) & 0x01);

       if ((ds18b20_back_value & 0x08) >> 3) 

  ds18b20读写函数中,没有按读写时序来写延时的时间。

正确写法:dat >>=1;

     temp = gpio_get_value(S5PV210_GPE0(3)) & 0x01;

     if ((init_DS18B20()) //因为gpio_get_value(S5PV210_GPE0(3))函数返回的
    值为指定引脚的高或低电平,即1或0。 

  最后按ds18b20的时序来解决上面时序的延时时间。那么就能在开发板上有正确的结果。

时序是很重要的,如果想这时序代码能在多平台上运用,最好延时取中值以上。

              
案例一:
mini210_ds18b20.c文件中:


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include   //其中copy_to*在其中

#include
#include
#include

spinlock_t lock;  //加不加这都 可以

#define DEVICE_NAME 'DS18B20'


void set_conIN(void)
{
    s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_INPUT);
    //gpio_set_value(S5PV210_GPE0(3), 1);    
}

void set_conOUT(void)
{
    s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
}

void set_data(int i)
{
    if (i == 0) {
        gpio_set_value(S5PV210_GPE0(3), 0);    
    }    else if(i == 1) {
        gpio_set_value(S5PV210_GPE0(3), 1);    
    }
}

unsigned int reset_ds18b20(void)
{
    unsigned int retValue;
  set_conOUT();

  set_data(1);
    __udelay(1);
    set_data(0);
    __udelay(600);
    set_data(1);
    __udelay(20);
    set_conIN();
    __udelay(100);
    /*稍做延时后 如果x=0则初始化成功
    x=1则初始化失*/
    //retValue = (gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01;
    retValue = gpio_get_value(S5PV210_GPE0(3));
    printk('init is %dn',retValue);
    return retValue;
}

unsigned int read_bit(void)
{
    spin_lock(&lock);
    set_conOUT();
    set_data(0);
    __udelay(2);
    set_conIN();
    __udelay(1);    
    spin_unlock(&lock);
    return(gpio_get_value(S5PV210_GPE0(3)) & 0x01);
    //return((gpio_get_value(S5PV210_GPE0(3)) >> 3) & 0x01);
}

/*写一位命令*/
void write_bit(char bitValue)
{
    spin_lock(&lock);
    set_conOUT();
    set_data(0);
    __udelay(15);
    if( bitValue == 1 ){
        set_data(1);
    }else{
        set_data(0);
    }
    spin_unlock(&lock);
    __udelay(45);
    set_conIN();
    __udelay(2);
}

/*写命令*/
void write_cmd(char cmd)
{
  unsigned char i;
  unsigned char temp;

  for(i=0; i<8;i++){
    temp = cmd>>i;
    temp &= 0x01;
    write_bit(temp);
  }
  //__udelay(10);
}

static int ds18b20_open(struct inode *inode, struct file *filp)
{
    printk (KERN_INFO 'Device openedn');
    spin_lock_init(&lock);
    return 0;
}

 /*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
  char lowValue=0,highValue=0;
  unsigned int i;
  int wendu_value;
  //float value;

    if(reset_ds18b20()){
      printk('init errorn');
  }
  __udelay(400);
  set_conOUT();
  set_data(1);
  write_cmd(0xCC);
  write_cmd(0x44);
  __udelay(100000);

  if(reset_ds18b20()){
     printk('init errorn');
  }
  __udelay(400);
  set_conOUT();
  set_data(1);
  write_cmd(0xcc);
  write_cmd(0xBE);
  /*读取温度转化数值*/

  for(i=0; i<8; i++){
    if( read_bit() ){
        lowValue |= (0x01<    }
    __udelay(62);
  }
  printk('lowValue is %dn',lowValue);
  for(i=0; i<8; i++){
    if( read_bit() ){
        highValue |= (0x01<    }
    __udelay(62);
  }
  printk('highValue is %dn',highValue);

  if((highValue & 0xf8) != 0x00) {
        lowValue = (~lowValue) + 1;
        
        if (lowValue > 255)
            highValue = (~highValue) + 1;
    }
    wendu_value = (highValue * 16 + lowValue/16) + ((lowValue%16)*10/16);
    
    printk('read_wendu--dat_L: %d    dat_H: %d    wendu: %d.%dn', lowValue, highValue,
        wendu_value - ((lowValue%16)*10/16), ((lowValue%16)*10/16));
 
#if 0
  i = highValue;
  i <<= 8;
  i = i|lowValue;
  value = i*0.0625;
  printk('kernel is %dn',value);
#endif

  highValue <<= 4;
  highValue |= ((lowValue&0xf0)>>4) ;
 
  copy_to_user(buffer, &highValue, sizeof(highValue));

  /*拷贝内核数据到用户空间*/
  //copy_to_user(buffer, &highValue, sizeof(highValue));
  return 0;
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    return 0;
}

static int ds18b20_release(struct inode *inode,struct file *filp)
{
    printk (KERN_INFO 'device closedn');
    return 0;
}

static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    return 0;
}

static struct file_operations ds18b20_fops = {
    .owner            = THIS_MODULE,
    .open    =    ds18b20_open,
    .read = ds18b20_read,
    .write = ds18b20_write,
    .unlocked_ioctl    = ds18b20_ioctl,
    .release = ds18b20_release,
};

static struct miscdevice ds18b20_dev = {
    .minor            = MISC_DYNAMIC_MINOR,
    .name            = DEVICE_NAME,
    .fops            = &ds18b20_fops,
};

static int __init ds18b20_dev_init(void) {
    int ret;
    int i;

    ret = gpio_request(S5PV210_GPE0(3), 'DS18b20');
    if (ret) {
        printk('%s: request GPIO %d for LED failed, ret = %dn', DEVICE_NAME,
            S5PV210_GPE0(3), ret);
        return ret;

        s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
        gpio_set_value(S5PV210_GPE0(3), 1);
    }

    ret = misc_register(&ds18b20_dev);

    printk(DEVICE_NAME'tinitializedn');

    return ret;
}

static void __exit ds18b20_dev_exit(void) {
    int i;

    for (i = 0; i < 1; i++) {
        gpio_free(S5PV210_GPE0(3));
    }

    misc_deregister(&ds18b20_dev);
}

module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);

MODULE_LICENSE('GPL');
MODULE_AUTHOR('mingLi.');

 

案例二:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include   //其中copy_to*在其中

#include
#include
#include

spinlock_t lock;  //不用也行

#define DEVICE_NAME 'DS18B20'

//********************************
//功能:设置引脚为输入功能
//********************************
void set_con_in(void)
{
    s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_INPUT);
    //gpio_set_value(S5PV210_GPE0(3), 1);    
}

//********************************
//功能:设置引脚为输出功能
//********************************
void set_con_out(void)
{
    s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
}


//********************************
//功能:引脚输出高或低电平功能,i=1(高)
//********************************

void set_output_data(int i)
{
    if (i == 0) {
        gpio_set_value(S5PV210_GPE0(3), 0);    
    }    else if(i == 1) {
        gpio_set_value(S5PV210_GPE0(3), 1);    
    }
}

//********************************
//功能:ds18b20复位
//********************************
int init_DS18B20(void)
{
    int result = 10;
    set_con_out();
    __udelay(3);    //短时间延迟
    set_output_data(1);
    __udelay(3);    //短时间延迟
    set_output_data(0);
    __udelay(550); //480-960us

    set_output_data(1);
    __udelay(20); //15-60us,最好大于15us

    set_con_in();
    __udelay(100); //60-240us, ds18b20回应值保持时间
    result = gpio_get_value(S5PV210_GPE0(3));
    printk('init_DS18B20--result:%dn', result);

    set_con_out();
    __udelay(3);
    set_output_data(1);
    //__udelay(300);

    return result;
    
}

//*************************************
//功能:从ds18b20读一个字节的数据
//*************************************
unsigned char read_one_char(void)
{
    unsigned char i = 0;
    unsigned char dat = 0;
    unsigned char temp = 0;

    spin_lock(&lock);

    //苡片手册上说写周期不少于60us
    //但时从时序图可知少于60us也行
    //或者取中值左右,最好是大于60us

    //for (i=8; i > 0; i--) {
    for(i=0; i<8; i++) {
        set_con_out();
        __udelay(3);
        set_output_data(1);
        dat >>= 1;
        /*set_output_data(0);     //++    
        __udelay(3);
        set_output_data(1); //将数据线'人为'拉高,为单片机检测DS18B20的输出电平作准备
        __udelay(3);
        */
        //
        set_output_data(0); //该行与下行等效该行上面的4行
        __udelay(18);  //按时序来延时,不能太小或太大
        
        set_con_in();
        __udelay(1);
        //temp = gpio_get_value(S5PV210_GPE0(3) & 0x01);  
        //错在S5PV210_GPE0(3)后面少加')'
        temp = gpio_get_value(S5PV210_GPE0(3)) & 0x01;
        if (temp)
            dat |= 0x80;
        else
            dat |= 0x00;
        
        printk('read_one_char--temp: %dn', temp);
        __udelay(65);    
        
    }
    spin_unlock(&lock);
    printk('read_one_char--dat: %dn', dat);

    return dat;
    
}

//*************************************
//功能:向ds18b20写一个字节的数据
//*************************************
void write_one_char(unsigned char dat)
{
    //printk('write_one_char--dat: %dn', dat);
    unsigned char i = 0;

    spin_lock(&lock);
    set_con_out();

    for(i=0; i<8; i++) {

        set_output_data(1);
        __udelay(1);
        
        set_output_data(0);
        __udelay(5);    
        set_output_data(dat & 0x01);
        __udelay(55);//延时约55us,DS18B20在拉低后的约
                //15~60us期间从数据线上采样
                //最好取中值以上,太小可得会出错
                //芯片手册上说一个写周期不少于60us
                //但我使用时,少于60us也可以,
                //但不能太小,一般中值以上
                //总结:为能可移值性,
                //最好是一个写周期在于60us
                
        set_output_data(1);
        __udelay(2);
        dat >>= 1;    
    }
    spin_unlock(&lock);
    __udelay(30);
}

//********************************
//功能:读取ds18b20的温度
//********************************
unsigned int read_wendu(void)
{
    unsigned char dat_L = 0, dat_H = 0;
    unsigned int wendu_value;
    int ds18b20_back_value;
    
    ds18b20_back_value  = init_DS18B20();
    //if ((ds18b20_back_value & 0x08) >> 3)  //错,init_DS18B20()返回值为0或1
    if (ds18b20_back_value)
        printk('ds18b20 init error!!!n');
    else
        printk('ds18b20_back_value %dn', ds18b20_back_value);
    write_one_char(0xCC);
    write_one_char(0x44);
    
    if (init_DS18B20())
        printk('ds18b20 init error!!!n');
    else
        printk('ds18b20 init ok n');
    write_one_char(0xcc);
    write_one_char(0xBE);

    dat_L = read_one_char();
    dat_H = read_one_char();

    if((dat_H & 0xf8) != 0x00) {
        dat_L = (~dat_L) + 1;
        
        if (dat_L > 255)
            dat_H = (~dat_H) + 1;
    }
    wendu_value = (dat_H * 16 + dat_L/16) * 10 +((dat_L%16)*10/16);
    
    printk('read_wendu--dat_L: %d    dat_H: %d    wendu: %d.%dn',dat_L, dat_H,
        wendu_value/10, wendu_value%10);
    return(wendu_value);
    //return (dat_H*256 + dat_L);
}

static int ds18b20_open(struct inode *inode, struct file *filp)
{
    printk (KERN_INFO 'Device openedn');
    spin_lock_init(&lock);
    return 0;
}

 /*读取数据*/
static int ds18b20_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
{
    unsigned int wendu_value = 0;

    wendu_value = read_wendu();
    printk('wendu_valu is %ldn', wendu_value);

    copy_to_user(buffer, &wendu_value, sizeof(wendu_value));

    return 0;
    
}
/*写命令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
    return 0;
}

static int ds18b20_release(struct inode *inode,struct file *filp)
{
    printk (KERN_INFO 'device closedn');
    return 0;
}

static long ds18b20_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    return 0;
}

static struct file_operations ds18b20_fops = {
    .owner            = THIS_MODULE,
    .open    =    ds18b20_open,
    .read = ds18b20_read,
    .write = ds18b20_write,
    .unlocked_ioctl    = ds18b20_ioctl,
    .release = ds18b20_release,
};

static struct miscdevice ds18b20_dev = {
    .minor            = MISC_DYNAMIC_MINOR,
    .name            = DEVICE_NAME,
    .fops            = &ds18b20_fops,
};

static int __init ds18b20_dev_init(void) {
    int ret;
    int i;

    ret = gpio_request(S5PV210_GPE0(3), 'DS18b20');
    if (ret) {
        printk('%s: request GPIO %d for GPE0 failed, ret = %dn', DEVICE_NAME,
            S5PV210_GPE0(3), ret);
        return ret;

        s3c_gpio_cfgpin(S5PV210_GPE0(3), S3C_GPIO_OUTPUT);
        gpio_set_value(S5PV210_GPE0(3), 1);
    }

    ret = misc_register(&ds18b20_dev);

    printk(DEVICE_NAME'tinitializedn');

    return ret;
}

static void __exit ds18b20_dev_exit(void) {
    int i;

    for (i = 0; i < 1; i++) {
        gpio_free(S5PV210_GPE0(3));
    }

    misc_deregister(&ds18b20_dev);
}

module_init(ds18b20_dev_init);
module_exit(ds18b20_dev_exit);

MODULE_LICENSE('GPL');
MODULE_AUTHOR('mingli.');


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章