用18b20 测试温度是非常常用的,不过18B20的调试不是这么容易的,有些内容网上很多的,不再重复说了,我先把波形说一下,再说程序部分:
整个都温度数据的顺序是:
1.700uS的低电平复位并测试18B20的低电平响应
2.主机发送0xCC,0x44两个字节,表示跳过地址,只有一个18B20就不需要地址
3.再次复位
4.发送0xCC,0xBE,两个字节让它转换温度
5.读取2个字节,这两个字节就是温度了。
6.这两个字节乘0.625就是温度了。
有一点说明一下,主机输出用GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;用开漏不行。
代码贴一下:
void b12_18b20_in()
{
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void b12_18b20_out()
{
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
管脚自己注意一下
#define DS18B20_DQ_OUT0 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
#define DS18B20_DQ_OUT1 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)
#define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)
void DS18B20_Reset(void)
{
//设置DS18B20为输出模式
b12_18b20_out();
//拉低总线480-960us
DS18B20_DQ_OUT0;
delay_us(660);
//释放总线15-60us
DS18B20_DQ_OUT1;
delay_us(15);
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在 返回0:存在
uint8_t DS18B20_Check(void)
{
uint8_t retry = 0;
b12_18b20_in(); //设置为输入
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;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t j;
uint8_t testb;
b12_18b20_out(); //设置为输出
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb) //输出高
{
DS18B20_DQ_OUT0; //输出低电平
delay_us(2); //延时2us
DS18B20_DQ_OUT1; //输出高电平
delay_us(60); //延时60us
}
else //输出低
{
DS18B20_DQ_OUT0; //输出低电平
delay_us(60); //延时60us
DS18B20_DQ_OUT1; //输出高电平
delay_us(2); //延时2us
}
}
}
//从DS18B20读取一个位
//返回值:1/0
uint8_t DS18B20_Read_Bit(void) //读一位
{
uint8_t data;
b12_18b20_out(); //设置为输出
DS18B20_DQ_OUT0; //输出低电平
delay_us(2);
DS18B20_DQ_OUT1; //拉高
b12_18b20_in(); //设置为输入
delay_us(12); //延时12us
if(DS18B20_DQ_IN)data=1; //读取总线数据
else data=0;
delay_us(50); //延时50us
return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
uint8_t DS18B20_Read_Byte(void) //读一字节
{
uint8_t i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
void DS18B20_start()
{
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xCC);
DS18B20_Write_Byte(0x44);
}
short Get_temp(void)
{
uint8_t temp;
short tem;
DS18B20_start();
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xCC);
DS18B20_Write_Byte(0xBE);
uint8_t TL = DS18B20_Read_Byte();
uint8_t TH = DS18B20_Read_Byte();
if( TH > 7 )
{
temp = 0; //温度为负
TH = ~TH;
TL = ~TL;
}
else
{
temp = 1; //温度为正
}
tem = TH;
tem <<= 8;
tem += TL;
//printf("=== %f\r\n", tem);
tem = tem * 6.25;
if(temp == 1)
{
return tem;
}
else
{
return ~tem;
}
}
输出
short temp = Get_temp();
uint16_t t = temp ;
printf("wendu = %02d.%02d\r\n" , t/100, t%100);
因为浮点数直接打印有点问题,现在这样如果有负问题可能存在问题,自己注意一下。
使用了short。
us延时函数看我的前面一篇文章。