网上关于DS18B20 传感器资料很多,但是代码部分说的畏畏缩缩,好像怕我们学会一样,在我写成功后,于是在此进行分享。本篇只针对没写过DS18B20的新手,且是单个传感器。多个传感器本篇没有任何介绍。
1.主机(控制器STM32,下同)拉低电平,持续480us-960us,然后释放(拉高电平,下同)
2.等待15us-60us(在程序中给了30)//第一和第二步均为输出,但是第二部后要切换为输入模式
3.从机(DS18B20 传感器,下同)会低电平,持续时间60us-240us,//这一步是检测传感器在不在的关键一步,加上第二步释放后的时间,所以我们要在90us(30+60)-270us(30+240)内检测电平高低来判断传感器是否存在。在此时应为输入模式。
4.主机接收至少480us,所以我们检测完后还需等待时序结束,时间=480us-释放后到检测时时间
返回数值。
代码:
1.初始化代码
#include "stm32f10x.h" // Device header
#include "main.h" //这里面没什么(除了delay函数)
#define DS18B20 GPIO_Pin_15 //如果复制使用,只需改这行Pin口和下行通道还开启有时钟
#define DS18B20_PROT GPIOB //其他代码不用更改,只需补全delay和显示函数就行
#define DS18B20_LOW GPIO_ResetBits(DS18B20_PROT,DS18B20)
#define DS18B20_HIGH GPIO_SetBits(DS18B20_PROT,DS18B20)
void DS18B20_Init(void) //初始化函数
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启对应通道时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = DS18B20;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DS18B20_PROT,&GPIO_InitStruct);
}
2.模式切换函数,1为写/输出模式,0为读/输入模式
void DS18B20_Output_Input(u8 cmd) //输入输出模式切换,1输出,0输入/读取
{
GPIO_InitTypeDef GPIO_InitStruct;
if(cmd) //为1 是输出模式
{
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = DS18B20;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
}
else //为0,输入模式
{
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = DS18B20;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
}
GPIO_Init(DS18B20_PROT,&GPIO_InitStruct);
}
3. 初始化代码
u8 DS18B20_Starup(void) //判断DS18B20 是否存在的一个函数
{
u8 data;
DS18B20_Output_Input(1); //为输出模式
DS18B20_LOW; //拉低电平
Delay_us(480); //delay函数,需要自己写,网上资料很多,保证时间准确就行
DS18B20_HIGH; //拉高电平,也是 释放总线
Delay_us(100);
DS18B20_Output_Input(0); //为输入模式
data = GPIO_ReadInputDataBit(DS18B20_PROT,DS18B20); //根据时序存在返回0,不存在是1
Delay_us(380);
return data;
}
4.此时我们需要验证下,在main函数里进行数据显示
int main(void)
{
OLED_Init();
DS18B20_Init();
while (1)
{
OLED_ShowNum(2, 5, DS18B20_Starup(), 1);//用自己的方式验证,存在为0,否则为1
}
}
如果显示0,在拔下传感器的数据线后显示为1,插入后为0.则以上代码和传感器没有问题
代码
void DS18B20_Write_Byte(u8 data) //写数据
{
for(u8 i=0;i<8;i++)
{
DS18B20_Output_Input(1);
DS18B20_LOW;
Delay_us(2); //拉低2us进入书写时序
(data&0x01) ? DS18B20_HIGH:DS18B20_LOW;//从低位往高位写移位7次后将是最高位
Delay_us(45); //延时45us
DS18B20_HIGH; //释放总线
data >>=1;
}
}
代码:
u8 DS18B20_Read_Byte(void) //读程序
{
u8 data=0;
for(u8 i=0;i<8;i++)
{
data >>=1;
DS18B20_Output_Input(1); //写时序,拉低2us后释放
DS18B20_LOW;
Delay_us(2); //拉低2us进入读时序
DS18B20_HIGH;
DS18B20_Output_Input(0); //进入读时序
if((GPIO_ReadInputDataBit(DS18B20_PROT,DS18B20)) == SET)
{
data |= 0x80;
}
Delay_us(45);
}
return data;
}
代码:最后的代码*10,为方便显示小数
void DS18B20_Read_Temp(u16 *data)
{
u8 LSB=0,HSB=0;u16 Temp=0; //LSB 低位的8位数据
DS18B20_Starup();
DS18B20_Write_Byte(0xCC); //跳过匹配步骤
DS18B20_Write_Byte(0x44); //温度转换,12位时间为750ms,注意时间单位
Delay_ms(750);
DS18B20_Starup();
DS18B20_Write_Byte(0xCC);
DS18B20_Write_Byte(0xBE); //进行数据读写
LSB = DS18B20_Read_Byte(); //先读取的低8位
HSB = DS18B20_Read_Byte(); //再读取的高8位
Temp = (HSB<<8) | LSB;
if((Temp&0xF800)==0xF800) //S=1为真否则位0
{
*data = (((~Temp + 0x01)*-0.0625))*10;//为负温度
}
else
{
*data = (Temp*0.0625)*10; //正温度
}
}
在main里进行显示,需要取地址操作
代码:
u16 Temp=0; //u16 类型值
int main(void)
{
OLED_Init();
DS18B20_Init();
while (1)
{
DS18B20_Read_Temp(&Temp); //取值
OLED_ShowSignedNum(2, 1, (Temp/10), 2); //整数位
OLED_ShowString(2, 4, ".");
OLED_ShowNum(2, 5, (Temp%10), 1);//小数位一位
}
}
关于delay和显示函数,用的是江科大的代码。需要的话我有空也贴出来。
还有我觉得CSDN一些博主写内容故意挖坑是很不好的行为,不限于代码故意写错,内容故意颠倒顺序,注释故意于内容不符。想教就认真写,想藏私就别写。
代码出错谁都不能避免,但是故意就很恶心。
最后感谢对于知识无私分享的人(不含我)。