DS18B20模块温转代码

DS18B20模块

单总线设备,可读可写;

可测范围:-55℃~ +125℃,温度/数据对应关系如下:

当启动温转命令后,读寄存器的前两个字节的值得到温度数据:默认上电是12位精度,分辨率是0.0625,高字节的Bit11-Bit15是符号位;

 

实现驱动中的读函数(代码来自百问网):

static ssize_t ds18b20_read(struct file* file,char __user* buf, size_t size,loff_t* offset){
  unsigned long flags;
  unsigned char DL= 0,DH = 0;
  unsigned char de1,de2,del;
  unsigned int integer;
  local_irq_save(flags);
  if(ds18b20_reset()){
    local_irq_restore(flags);
    return -ENODEV;
  }
  ds18b20_write_byte(0xcc);
  ds18b20_write_byte(0x44);//启动温转
  gpiod_direction_output(ds18b20_pin,1);
  local_irq_restore(flags); 
  set_current_state(TASK_INTERRUPTIBLE);//使用schedule_timeout先设置状态
  schedule_timeout(HZ);//延时1s,温转需要时间
  local_irq_save(flags);//再次关中断
  ds18b20_write_byte(0xcc);
  ds18b20_write_byte(0xbe);//读取寄存器
  // 读取的字节顺序?
  DL = ds18b20_read_byte();//低八位
  DH = ds18b20_read_byte();//高八位
  if(DH > 0x7f){
    DL = ~DL + 1;//负数则 补码加一
    DH = ~DH;
    integer = DL/16 + DH*16;
    de1 = (DL&0x0f)*10/16;
    de2 = (DL&0x0f)*100/16;
    del = de1*10 + de2; 
  }
  else{
    //分辨率:0.0625
    integer = DL/16 + DH*16;
    de1 = (DL&0x0f)*10/16;
    de2 = (DL&0x0f)*100/16;
    del = de1*10 + de2;
  }
  local_irq_restore(flags);
  gpiod_direction_output(ds18b20_pin,1);
  copy_to_user(buf, &integer,4);//为什么用四个字节表示整数
  copy_to_user(buf+4,&del,1);
  return 5;
}

上述代码中,若为负数,则表示的是补码,让其取反加一;正数则正常计算。

小数部分的计算:分辨率是0.0625 = 1/16;让其十六进制数转化为十进制(此处就是正常按照十六进制转化,最低位就是16),再乘以分辨率就是温度值。

小数部分计算理解:当取其小数位第一位时,可以先让低四位(转化为十进制数据)乘以10在除以16取商,这样代表的就是小数位第一位值,小数第二位就是让低四位乘以100再除以16取商。

例如-55 ℃,十六进制就是0xFC90,1111 1100 1001 0000,取反加一就是 0000 0011 0111 0000,其中整数部分就是黄色部分0000 0011 0111,正常转化为十进制就是55;小数部分正常转化为就是0。

上述代码不理解的地方:其复制到用户空间的是四字节表示的整数部分,是否多余?

posted @ 2022-11-04 16:16  QianFa01  阅读(218)  评论(0)    收藏  举报