一、前言
继上次发布的光照传感器讲解,这次继续讲一些简单的适合大学生学习使用的传感器。这次要讲的是一款温度传感器,想要完整代码工程的,可以在文章末尾的链接下载。
二、芯片介绍
1、简介
DS18B20是一款数字型温度传感器,这款传感器已经有长的历史了,驱动方式简单,很适合初学者使用,具体的我就不多说了,很多人应该都是知道这个传感器的。
2、引脚定义
[tr]引脚名称说明[/tr]
1 | GND | 供电电源负极 |
2 | DQ | 数据输入输出引脚(和单片机IO口相连的时候一定要接上拉电阻) |
3 | VCC | 供电电源正极 |
3、通讯方式
DS18B20用的是单总线方式,单片机给DQ引脚输出一定规则的时序信号即可配置和驱动DS18B20,同样的,单片机按照时序接收DS18B20发送的数据即可得到温度数据。
4、工作原理
DS18B20通过传感威廉希尔官方网站
把温度转换成对应的电压信息,然后转换成数字信号,再把温度相关的数据存到自身的寄存器里面,单片机去读取这些数据,就可以知道当前的温度了。简单的说就是把模拟信号转换成数字信号,然后把这些数据存起来交给单片机,大概的原理是这样,如果你想继续深入了解,可以去找一下相关的文章,关于这方面的介绍有很多。
三、编程讲解
1、DS18B20驱动程序
//单片机只需要用一个普通的IO口和DS18B20的DQ引脚相连,然后控制这个IO口输出高低电平即可
//复位DS18B20
//作用:复位
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //把单片机的IO口配置为输出
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us,这个时间是根据DS18B20本身的规则定的,可以在数据手册找到相关介绍
DS18B20_DQ_OUT=1; //拉高DQ
delay_us(15); //15US
}
//等待DS18B20的回应
//作用:检查单片机和DS18B20的通讯是否正常
//返回1:未检测到DS18B20的存在(可能是DQ引脚没有上拉电阻,通讯的时序不对,芯片损坏等原因)
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//把IO口配置为输入,目的是为了接收DS18B20发过来的数据
while (DS18B20_DQ_IN&&retry<200)//如果IO口是低电平,则是正常的,否则一直进while循环
{
retry++;
delay_us(1);
};
if(retry>=200)
{//通讯有误,返回1
return 1;
}
else
{//正常
retry=0;
}
while (!DS18B20_DQ_IN&&retry<240)//继续读取电平,如果IO口是高电平,则是正常的
{
retry++;
delay_us(1);
};
if(retry>=240)
{//通讯有误,返回1
return 1;
}
return 0;//通讯正常,返回0
}
//从DS18B20读取一个位
//作用:读取一个位数据,重复调用该函数可以把温湿度数据读出来
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT();//单片机输出一个由低到高的上升沿脉冲给DS18B20
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();//把IO口配置为输入,读取电平
delay_us(12);
if(DS18B20_DQ_IN)//如果是高电平,则DS18B20输出的数据是'1',否则为'0'
data=1;
else
data=0;
delay_us(50);
return data;
}
//从DS18B20读取一个字节
//作用:连续读8个位,并合成一个字节数据
//返回值:读到的数据
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();//连续调用8次
dat=(j<<7)|(dat>>1);//每次读取到1个位的数据后左移1位,读取完8个位的数据之后就可以合成1个字节了
}
return dat;//返回合成的1字节数据
}
//写一个字节到DS18B20
//作用:写数据到DS18B20,调用这个函数可以发送指令控制DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;//把传进来的这个数据的最高位提取出来
dat=dat>>1;//dat的数据左移1位,作用是把次高位移到最高位
if (testb) //如果最高位数据为'1'
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;//输出60us高电平,相当于告诉DS18B20要传的数据是'1'
delay_us(60);
}
else //如果最高位数据为'0'
{
DS18B20_DQ_OUT=0;//输出60us低电平,相当于告诉DS18B20要传的数据是'0'
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//开始温度转换
//作用:从DS18B20中读取温度数据
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();//复位
DS18B20_Check();//检查单片机和DS18B20的通讯是否正常
DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
DS18B20_Write_Byte(0x44);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
}
//初始化DS18B20的IO口DQ 同时检测DS18B20的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出1
DS18B20_Rst();//复位
return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
//DS18B20_Start (); //开始采集温度
DS18B20_Rst();//复位
DS18B20_Check();//检查单片机和DS18B20通讯是否正常
DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
DS18B20_Write_Byte(0xbe);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
TL=DS18B20_Read_Byte(); //读取数据低字节
TH=DS18B20_Read_Byte(); //读取数据高字节
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}
else
{
temp=1;//温度为正
}
tem=TH;//获得高字节数据
tem<<=8;//高字节位左移8位
tem+=TL;//左移的高8位加上低8位合成一个16位数据
tem=(float)tem*0.625;//从DS18B20读取到的2个字节的数据还不是温度值,需要转换,转换公式参考数据手册
if(temp)
{
return tem; //返回温度值
}
else
{
return -tem;
}
}
2、main函数
int main()
{
short temperature;
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
OLED_Init(); //OLED初始化
OLED_Clear(); //OLED清屏
while(DS18B20_Init()) //DS18B20初始化
{
OLED_ShowString(50,2,"error",12);//DS18B20通讯有问题
}
while(1)
{
//读取温度
temperature=DS18B20_Get_Temp();
if(temperature<0)//温度低于0
{
OLED_ShowString(50,4,"-",16); //显示负号
temperature=-temperature; //转为正数
}
else //温度大于0
{
OLED_ShowString(50,4," ",16); //不显示负号,也不显示正号
}
OLED_ShowCHinese(0,4,0);//显示中文字体“温”
OLED_ShowCHinese(16,4,1);//显示中文字体“度”
OLED_ShowString(32,4,":",16);
OLED_ShowNum(60,4,temperature/10,2,16); //显示整数部分
OLED_ShowString(80,4,".",16);
OLED_ShowNum(88,4,temperature%10,1,16); //显示小数部分
OLED_ShowCHinese(100,4,9);//显示“℃”
}
一、前言
继上次发布的光照传感器讲解,这次继续讲一些简单的适合大学生学习使用的传感器。这次要讲的是一款温度传感器,想要完整代码工程的,可以在文章末尾的链接下载。
二、芯片介绍
1、简介
DS18B20是一款数字型温度传感器,这款传感器已经有长的历史了,驱动方式简单,很适合初学者使用,具体的我就不多说了,很多人应该都是知道这个传感器的。
2、引脚定义
[tr]引脚名称说明[/tr]
1 | GND | 供电电源负极 |
2 | DQ | 数据输入输出引脚(和单片机IO口相连的时候一定要接上拉电阻) |
3 | VCC | 供电电源正极 |
3、通讯方式
DS18B20用的是单总线方式,单片机给DQ引脚输出一定规则的时序信号即可配置和驱动DS18B20,同样的,单片机按照时序接收DS18B20发送的数据即可得到温度数据。
4、工作原理
DS18B20通过传感威廉希尔官方网站
把温度转换成对应的电压信息,然后转换成数字信号,再把温度相关的数据存到自身的寄存器里面,单片机去读取这些数据,就可以知道当前的温度了。简单的说就是把模拟信号转换成数字信号,然后把这些数据存起来交给单片机,大概的原理是这样,如果你想继续深入了解,可以去找一下相关的文章,关于这方面的介绍有很多。
三、编程讲解
1、DS18B20驱动程序
//单片机只需要用一个普通的IO口和DS18B20的DQ引脚相连,然后控制这个IO口输出高低电平即可
//复位DS18B20
//作用:复位
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //把单片机的IO口配置为输出
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us,这个时间是根据DS18B20本身的规则定的,可以在数据手册找到相关介绍
DS18B20_DQ_OUT=1; //拉高DQ
delay_us(15); //15US
}
//等待DS18B20的回应
//作用:检查单片机和DS18B20的通讯是否正常
//返回1:未检测到DS18B20的存在(可能是DQ引脚没有上拉电阻,通讯的时序不对,芯片损坏等原因)
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//把IO口配置为输入,目的是为了接收DS18B20发过来的数据
while (DS18B20_DQ_IN&&retry<200)//如果IO口是低电平,则是正常的,否则一直进while循环
{
retry++;
delay_us(1);
};
if(retry>=200)
{//通讯有误,返回1
return 1;
}
else
{//正常
retry=0;
}
while (!DS18B20_DQ_IN&&retry<240)//继续读取电平,如果IO口是高电平,则是正常的
{
retry++;
delay_us(1);
};
if(retry>=240)
{//通讯有误,返回1
return 1;
}
return 0;//通讯正常,返回0
}
//从DS18B20读取一个位
//作用:读取一个位数据,重复调用该函数可以把温湿度数据读出来
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT();//单片机输出一个由低到高的上升沿脉冲给DS18B20
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();//把IO口配置为输入,读取电平
delay_us(12);
if(DS18B20_DQ_IN)//如果是高电平,则DS18B20输出的数据是'1',否则为'0'
data=1;
else
data=0;
delay_us(50);
return data;
}
//从DS18B20读取一个字节
//作用:连续读8个位,并合成一个字节数据
//返回值:读到的数据
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();//连续调用8次
dat=(j<<7)|(dat>>1);//每次读取到1个位的数据后左移1位,读取完8个位的数据之后就可以合成1个字节了
}
return dat;//返回合成的1字节数据
}
//写一个字节到DS18B20
//作用:写数据到DS18B20,调用这个函数可以发送指令控制DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;//把传进来的这个数据的最高位提取出来
dat=dat>>1;//dat的数据左移1位,作用是把次高位移到最高位
if (testb) //如果最高位数据为'1'
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;//输出60us高电平,相当于告诉DS18B20要传的数据是'1'
delay_us(60);
}
else //如果最高位数据为'0'
{
DS18B20_DQ_OUT=0;//输出60us低电平,相当于告诉DS18B20要传的数据是'0'
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//开始温度转换
//作用:从DS18B20中读取温度数据
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();//复位
DS18B20_Check();//检查单片机和DS18B20的通讯是否正常
DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
DS18B20_Write_Byte(0x44);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
}
//初始化DS18B20的IO口DQ 同时检测DS18B20的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出1
DS18B20_Rst();//复位
return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
//DS18B20_Start (); //开始采集温度
DS18B20_Rst();//复位
DS18B20_Check();//检查单片机和DS18B20通讯是否正常
DS18B20_Write_Byte(0xcc);//寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
DS18B20_Write_Byte(0xbe);//0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
TL=DS18B20_Read_Byte(); //读取数据低字节
TH=DS18B20_Read_Byte(); //读取数据高字节
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}
else
{
temp=1;//温度为正
}
tem=TH;//获得高字节数据
tem<<=8;//高字节位左移8位
tem+=TL;//左移的高8位加上低8位合成一个16位数据
tem=(float)tem*0.625;//从DS18B20读取到的2个字节的数据还不是温度值,需要转换,转换公式参考数据手册
if(temp)
{
return tem; //返回温度值
}
else
{
return -tem;
}
}
2、main函数
int main()
{
short temperature;
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
OLED_Init(); //OLED初始化
OLED_Clear(); //OLED清屏
while(DS18B20_Init()) //DS18B20初始化
{
OLED_ShowString(50,2,"error",12);//DS18B20通讯有问题
}
while(1)
{
//读取温度
temperature=DS18B20_Get_Temp();
if(temperature<0)//温度低于0
{
OLED_ShowString(50,4,"-",16); //显示负号
temperature=-temperature; //转为正数
}
else //温度大于0
{
OLED_ShowString(50,4," ",16); //不显示负号,也不显示正号
}
OLED_ShowCHinese(0,4,0);//显示中文字体“温”
OLED_ShowCHinese(16,4,1);//显示中文字体“度”
OLED_ShowString(32,4,":",16);
OLED_ShowNum(60,4,temperature/10,2,16); //显示整数部分
OLED_ShowString(80,4,".",16);
OLED_ShowNum(88,4,temperature%10,1,16); //显示小数部分
OLED_ShowCHinese(100,4,9);//显示“℃”
}
举报