上一篇单总线时序分析: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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
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 %4f \r\n", result);
37 sleep(2);
38 }
39 close(fd);
40
41 return 0;
42 } /* ----- End of main() ----- */