上一篇单总线时序分析:https://blog.csdn.net/qq_40215005/article/details/96435251
这是ds18b20驱动大致结构
硬件初始化BYTE ds18b20_reset(void) 复位脉冲和应答脉冲函数
BYTE ds18b20_reset(void) { s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); //设置引脚GPG0为输出 s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); //设置单总线信号为低电平 udelay(480);//产生复位脉冲 s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); //设置单总线信号为高电平 udelay(60);//从机等待 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT);//设置为输入,读取从机发送的信号 if(s3c2410_gpio_getpin(S3C2410_GPG(0))) //判断为低电平就应答成功 { printk("ds18b20 reset failed.\r\n"); return 1; } udelay(240);//保持60~240us时间 return 0; }file opreation中定义了.read=s3c2440_ds18b20_read操作,就是从ds18b20获取温度。 s3c2440_ds18b20_read
static ssize_t s3c2440_ds18b20_read(struct file *filp, char *buff, size_t len, loff_t *off) { ds18b20_proc(); buff[0] = data[0]; buff[1] = data[1]; return 1; }然后调用了ds18b20_proc();
void ds18b20_proc(void)//获取温度子函数 { while(ds18b20_reset()); //主从设备初始化 udelay(120); ds18b20_write_byte(0xcc); ds18b20_write_byte(0x44);//发送获取温度转换命令 udelay(5); while(ds18b20_reset()); udelay(200); ds18b20_write_byte(0xcc); ds18b20_write_byte(0xbe);//读取暂存器值命令 data[0] = ds18b20_read_byte(); data[1] = ds18b20_read_byte(); }
BYTE ds18b20_write_byte(BYTE byte)
BYTE ds18b20_write_byte(BYTE byte) { BYTE i; s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); //设置为输出 for(i = 0; i < 8; i++) //八个位需要发送 { s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); udelay(15); if(byte & HIGH)//写1时就拉高信号线 { s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); } else//写0就拉低 { s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); } udelay(45); s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); udelay(1); byte >>= 1;//命令八个位依次右移 } s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH); return 0; }比如发CCH命令 CC 11001100 00000001 & 与八次,总共发送一个字节的命令。
BYTE ds18b20_read_byte(BYTE byte);
BYTE ds18b20_read_byte(void) { BYTE i = 0; BYTE byte = 0; for(i = 0; i < 8; i++) { s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_OUTPUT); s3c2410_gpio_setpin(S3C2410_GPG(0), LOW); udelay(1); byte >>= 1; s3c2410_gpio_setpin(S3C2410_GPG(0), HIGH);//上拉代表释放总线 s3c2410_gpio_cfgpin(S3C2410_GPG(0), S3C2410_GPIO_INPUT);//采集信号 if(s3c2410_gpio_getpin(S3C2410_GPG(0)))//为高电平则读1 byte |= 0x80;//读一个字节 udelay(50); } return byte; }ds18b20转化后得到的12位数据,存储在ds18B20的两个8比特的RAM中,二进制中的前面5位是符号位,如果测得的温度大于0, 这5位为0,只要将测到的数值乘于0.0625即可得到实际温度;如果温度小于0,这5位为1,测到的数值需要取反加1再乘于0.0625即可得到实际 温度。 例如+125℃的数字输出为07D0H,+25.0625℃的数字输出为0191H,-25.0625℃的数字输出为FE6FH,-55℃的数字输出为FC90H 。可以看做后四位为小数部分,精度为0.625,中间七位为整数部分。 所以测试程序中要对得到的两个字节做处理 测试程序
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/ioctl.h> 4 #include <stdlib.h> 5 #include <termios.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <sys/time.h> 9 10 int main (int argc, char **argv) 11 { 12 int fd; 13 double result = 0; 14 unsigned char buff[2]; 15 unsigned short temp = 0; 16 int flag = 0; 17 18 if ((fd=open("/dev/ds18b20",O_RDWR | O_NDELAY | O_NOCTTY)) < 0) 19 { 20 perror("open device ds18b20 failed.\r\n"); 21 exit(1); 22 } 23 while(1) 24 { 25 printf("open device ds18b20 success.\r\n"); 26 read(fd, buff, sizeof(buff)); 27 temp=((unsigned short)buff[1])<<8; 28 temp|=(unsigned short)buff[0]; 29 if(temp & 0x0800) 30 { 31 temp &= 0xF000; 32 result=0.0625*((double)(~temp+1)); 33 } 34 else 35 result=0.0625*((double)temp); 36 printf("temperature is O \r\n", result); 37 sleep(2); 38 } 39 close(fd); 40 41 return 0; 42 } /* ----- End of main() ----- */