1.18b20特点
1)单总线双向传输
2)测温范围-55-+125度,精度±0.5度
3)支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
4)工作电源: 3.0~5.5V/DC (可以数据线寄生电源)。
5)在使用中不需要任何外围元件。
6)测量结果以9~12位数字量方式串行传送。
2.18b20信号类型
一共6种:复位脉冲、应答脉冲、写0、写1、读0和读1,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。
正点原子阿波罗F767:
信号线PB12
//IO方向设置
#define DS18B20_IO_IN() {GPIOB->MODER&=~(3<<(12*2));GPIOB->MODER|=0<<12*2;} //PB12输入模式
#define DS18B20_IO_OUT() {GPIOB->MODER&=~(3<<(12*2));GPIOB->MODER|=1<<12*2;} //PB12输出模式
//IO操作函数
#define DS18B20_DQ_OUT(n) (n?HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET) \
:HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET)) //数据端口PB12
#define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) //数据端口 PB12
1.复位
单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480 us,,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时15~60 us。
//复位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //设置为输出模式
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us(至少480us)
DS18B20_DQ_OUT=1; //DQ=1拉高释放总线
delay_us(15); //15US
//进入接受模式,等待应答信号。
}
2.应答信号
进入接收模式(Rx) 接着DS18B20拉低总线60~240 us,以产生低电平应答脉冲。
逻辑:首先判断有无低电平,后检查低电平时长。
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在 返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//SET PA0 INPUT
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
3.写时序
写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。
写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。
可看出先发送的是低位
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//设置PA0为输出
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb) //输出高
{
DS18B20_DQ_OUT=0;// 主机输出低电平
delay_us(2); //延时2us
DS18B20_DQ_OUT=1;//释放总线
delay_us(60); //延时60us
}
else //输出低
{
DS18B20_DQ_OUT=0;//主机输出低电平
delay_us(60); //延时60us
DS18B20_DQ_OUT=1;//释放总线
delay_us(2); //延时2us
}
}
}
4.读时序
典型的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us。
读1位
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT();//设置为输出
DS18B20_DQ_OUT=0; //输出低电平2us
delay_us(2);
DS18B20_DQ_OUT=1; //拉高释放总线
DS18B20_IO_IN();//设置为输入
delay_us(12);//延时12us
if(DS18B20_DQ_IN)data=1;//读取总线数据
else data=0;
delay_us(50); //延时50us
return data;
}
读取1字节:
看出先读出的最终在最低位
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
6.读温度时序
我们来看看DS18B20的典型温度读取过程,DS18B20的典型温度读取过程为:复位发SKIP ROM命令(0XCC)发开始转换命令(0X44)延时复位发送SKIP ROM命令(0XCC)发读存储器命令(0XBE)连续读出两个字节数据(即温度)结束。
可以看出先读放低位TL,后读高位
TH和TL定义的无符号数,虽然18b20内的数据为补码存储的有符号数,后续会做处理。
因TH无符号数,若TH大于7,说明前几位肯定为11111,温度为负数
说明:
1)short只是说明数据所占的位宽,并没规定是十进制还是十六进制
2)c语言可以给a赋值负数 a=-2,a有符号数,那么就以补码形式存储
3)18b20是补码形式存储,从高位开始第五位是符号位,从第六位开始是数值,那么如果温度是负数,那么低12位就是一个负数的补码形式,高5位均为1,直接整个16位取反加1就是负数的绝对值,也可以认为是负数的原码取正数,比如算出来-55度,全部取反加1就是算出来十进制正55度,那么对于最后这个数,就直接加个负号赋值给返回值就可以。如果取反没有加1可能是因为加1不加1对最后结果影响很小。
4)负数原码求补码和补码求原码都是符号位不动取反加1
对于正数,原码反码补码一样,负数反码和补码求解时都保持符号位不变
5)疑问:给有符号数赋值一个负数,如果负数以二进制表示,是赋值原码还是补码