清采NOTE

理解他人 善待自己

用户工具

站点工具


courses:embedded_system:ds18b20_温度测量

DS18B20温度测量

实验目的

学习DS18B20的操作。

实验内容

学习使用单总线技术,通过它来实现STM32和外部温度传感器(DS18B20)的通信,并把从温度传感器得到的温度数据通过LCD1602显示出来。


实验说明

在既有框架下,主要编写 main.cds18b20.c 程序,完成相应的功能。

main.c
/*******************************************************************************
*                           		       
--------------------------------------------------------------------------------
* 实 验 名      : DS18B20温度传感器实验
* 实验说明      : 通过LCD1602显示
* 连接方式      : 
* 注    意      : 所用函数在头文件.c文件内
*******************************************************************************/
 
#include "public.h"
#include "Lcd1602.h"
#include "ds18b20.h"
#include "systick.h"
 
/****************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/
int main()
{   u16 wd;
    double temp;
    LCD1602_GPIO_Init();		 
    LCD1602_Init();	 //LCD1602初始化
    ds18b20_init();	 //DS18B20初始化
    while(1)
    {
        temp=readtemp();  //读取温度
        wd=temp*100;	 //显示二位小数
        LCD1602_MoveToPosition(0,0);
            LCD1602_DisplayString("wendu");	
        LCD1602_MoveToPosition(1,0);
            LCD1602_DisplayOneCharOnAddr(0,9,wd/1000+0x30);//显示十位	
            LCD1602_DisplayOneCharOnAddr(0,10,wd%1000/100+0x30);//显示个位 
            LCD1602_DisplayOneCharOnAddr(0,11,'.');//显示. 
            LCD1602_DisplayOneCharOnAddr(0,12,wd%1000%100/10+0x30);//显示小数1位 
            LCD1602_DisplayOneCharOnAddr(0,13,wd%1000%100%10+0x30);//显示小数2位 
            LCD1602_DisplayOneCharOnAddr(0,14,0xdf); //℃
            LCD1602_DisplayOneCharOnAddr(0,15,'C');//显示C 	
    }
}

ds18b20.c
#include "ds18b20.h"
 
/*******************************************************************************
* 函 数 名      : ds18b20_init
* 函数功能      : IO端口时钟初始化函数	   
* 输    入      : 无
* 输    出      : 无
*******************************************************************************/
void ds18b20_init()
{
    GPIO_InitTypeDef GPIO_InitStructure; // 初始化结构体类型
 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 连接端口 GPIOB 时钟
 
    GPIO_InitStructure.GPIO_Pin=dq; // 端口连接
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // 初始化为推挽式输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 端口速率
    GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure); // 端口初始化
}
 
/*******************************************************************************
* 函 数 名      : DQININT
* 函数功能      : 输入配置	   
* 输    入      : 无
* 输    出      : 无
*******************************************************************************/
void DQININT()  //输入配置
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin=dq;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure);	
}
 
/*******************************************************************************
* 函 数 名      : DQOUTINT
* 函数功能      : 输出配置	   
* 输    入      : 无
* 输    出      : 无
*******************************************************************************/
void DQOUTINT() //输出配置
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin=dq;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure);	
}
 
/*******************************************************************************
* 函 数 名      : ds18b20init
* 函数功能      : DS18B20初始化时序	   
* 输    入      : 无
* 输    出      : 无
*******************************************************************************/
void ds18b20init()
{
    DQOUTINT();//输出
    ds18b20_dq_L;
    delay_us(480);//延时480微妙	
    ds18b20_dq_H;
    delay_us(480);//延时480微妙
}
 
/*******************************************************************************
* 函 数 名      : ds18b20wr
* 函数功能      : DS18B20写数据时序	   
* 输    入      : dat
* 输    出      : 无
*******************************************************************************/
void ds18b20wr(u8 dat)
{
    u8 i=0;
    DQOUTINT();//输出
 
    for(i=0;i<8;i++) // 一次8位,即1字节
    {
        ds18b20_dq_L; //拉低
        delay_us(15); //延时15微妙
 
        if((dat&0x01)==1) // 判断最低位
        {
            ds18b20_dq_H;
        }
        else
        {
            ds18b20_dq_L;
        }
        delay_us(60);//延时60微妙
        ds18b20_dq_H;
 
        dat>>=1; // 右移一位,准备下一位数据的发送	
    }
}
 
/*******************************************************************************
* 函 数 名      : DS18b20rd
* 函数功能      : DS18B20读数据时序	   
* 输    入      : 无
* 输    出      : value
*******************************************************************************/
u8 DS18b20rd()
{
    u8 i=0,value=0;
 
    for(i=0;i<8;i++)
    {
        value>>=1; // 右移一位,留出最高位
        DQOUTINT(); //输出
        ds18b20_dq_L; //拉低
        delay_us(4); //延时4微妙
        ds18b20_dq_H;
        delay_us(10); //延时10微妙
        DQININT(); //输入配置
 
        if(GPIO_ReadInputDataBit(GPIO_ds18b20,dq)==1)
        {
            value|=0x80; // value和最高位比较,如果是1就读进去,8次移位之后高位变低位;读数据 从低位开始
        }
 
        delay_us(45); //延时45微妙
    }
    return value;	
}
 
/*******************************************************************************
* 函 数 名      : readtemp
* 函数功能      : DS18B2温度寄存器配置,温度读取	   
* 输    入      : 无
* 输    出      : value
*******************************************************************************/
double readtemp()   //读取温度内需要复位的
{
    u16 temp;
    u8 a,b;
    double value;
    ds18b20init(); //初始化
    ds18b20wr(0xcc); //发送忽略ROM指令
    ds18b20wr(0x44); //发送温度转换指令
    delay_ms(800); // 12位分辨率时,转换时间需大于750ms
    ds18b20init(); //初始化
    ds18b20wr(0xcc); //发送忽略ROM指令
    ds18b20wr(0xbe); //发读暂存器指令
    a=DS18b20rd(); //温度的低八位
    b=DS18b20rd(); //温度的高八位
    temp=b;
    temp=(temp<<8)+a; // temp是16位,先把temp中b左移8为,放到temp的高8位;再+a即将a放到temp的低8位
                        // 使用 temp=(temp<<8)|a 也一样
    if((temp&0xf800)==0xf800) // 如果前5为是1,表示温度是负值(根据数据存储表),用负数的补码公式:取反+1
    {
        temp=(~temp)+1;
        value=temp*(-0.0625);
    }
    else
    {
        value=temp*0.0625;	
    }
    return value;
}

实验步骤

1. 使用1根1P杜邦线连接核心板PB8与“两路温度传感器”单元JP35(WD1)相连。
2. 使用1根8P杜邦线连接核心板PA0~PA7与“LCD1602液晶”单元JP33(D0~D7)。
3. 使用3根1P线连接PA8~PA11与“LCD1602液晶”单元JP31(RS,RW,EN)。
4. 在KEIL软件中调试运行“DS18B20温度测量”工程文件。
5. 实验现象:在液晶上显示“wendu xx.xx℃”。

实验任务

1. 按上述步骤调试出结果;
2. 显示器上的“wendu”改为“Temperature”,设置温度显示范围为小数点后4位;
3. 改变测量温度的分辨率为10位,即最小刻度变化为0.25°C,此时可以观察到温度显示的4位小数中最后两位始终为0。

任务解答

任务1.c
int main()
{
    u32 wd; // 这里要改为 u32,因为u16最多表示2^16=65536
    double temp;
    LCD1602_GPIO_Init();		 
    LCD1602_Init();
    ds18b20_init(); //DS18B20初始化
    while(1)
    {
        temp=readtemp(); //读取温度
        wd=temp*10000; //显示四位小数
        LCD1602_MoveToPosition(0,0);
            LCD1602_DisplayString("Temperature:");	
        LCD1602_MoveToPosition(1,0);
            LCD1602_DisplayOneCharOnAddr(1,7,wd/100000+0x30);//显示十位	
            LCD1602_DisplayOneCharOnAddr(1,8,wd%100000/10000+0x30);//显示个位 
            LCD1602_DisplayOneCharOnAddr(1,9,'.');//显示. 用ox2e效果一样
            LCD1602_DisplayOneCharOnAddr(1,10,wd%100000%10000/1000+0x30);//显示小数1位 
            LCD1602_DisplayOneCharOnAddr(1,11,wd%100000%10000%1000/100+0x30);//显示小数2位 
            LCD1602_DisplayOneCharOnAddr(1,12,wd%100000%10000%1000%100/10+0x30);//显示小数3位 
            LCD1602_DisplayOneCharOnAddr(1,13,wd%100000%10000%1000%100%10+0x30);//显示小数4位 
            LCD1602_DisplayOneCharOnAddr(1,14,0xdf); //显示°,对照LCD1602的字符表查询
            LCD1602_DisplayOneCharOnAddr(1,15,'C');//显示C 	
    }
}
任务2.m
/* 第1步:在 ds18b20.c 中添加配置函数修改分辨率 */
 
void resolution_conf()
{
    ds18b20init();
    ds18b20wr(0xcc); // 发送忽略ROM指令
    ds18b20wr(0x4e); // 发送写寄存器指令
    ds18b20wr(0x7D); // 配置触发寄存器最高125°
    ds18b20wr(0xc9); // 配置触发寄存器最低-55°
    ds18b20wr(0x3f); // 配置分辨率9位1f,即 0 00 11111,默认12位为7f,即 0 11 11111
    //	ds18b20wr(0x48); // 写入非易失性的EEPROM
}
 
/* 第2步:在 ds18b20.h 中声明定义的配置函数 */
void resolution_conf(void);
 
/* 第3步:在 main.c 中调用 resolution_conf() */
    ds18b20_init(); //DS18B20初始化
    resolution_conf(); // 调用
 
/* 第4步:在 readtemp() 中修改温度转换时间为
    delay_ms(200);