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;让其十六进制数转化为十进制(此处就是正常按照十六进制转化,最低位就是160 ),再乘以分辨率就是温度值。
小数部分计算理解:当取其小数位第一位时,可以先让低四位(转化为十进制数据)乘以10在除以16取商,这样代表的就是小数位第一位值,小数第二位就是让低四位乘以100再除以16取商。
例如-55 ℃,十六进制就是0xFC90,1111 1100 1001 0000,取反加一就是 0000 0011 0111 0000,其中整数部分就是黄色部分0000 0011 0111,正常转化为十进制就是55;小数部分正常转化为就是0。
上述代码不理解的地方:其复制到用户空间的是四字节表示的整数部分,是否多余?
浙公网安备 33010602011771号