STM32内置温度传感器,但芯片温度上升等问题很多,与实际温度大不相同,因此介绍了如何通过STM32读取外部数字温度传感器的温度。可以得到更准确的环境温度。

在本章中,我们将学习使用单总线技术,通过它来实现 STM32 和外部温度传感器( DS18B20)的通信,并把从温度传感器得到的温度数据通过 printf 打印输出在串口助手上。 本章分为以下学习目标:

1. 学习 DS18B20 的操作

1.1 DS18B20 简介

DS18B20 是由 DALLAS 半导体公司推出的一种“一线总线”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。一线总线结构具有简洁且经济的特点,可使用户轻松地组建传感器网络,从而为测量系统的构建引入全新概念,测量温度范围为-55~+125℃ ,精度为±0. 5℃。现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。它能直接读出被测温度,并且可根据实际要求通过简单的编程实现 9~l2 位的数字值读数方式。它工作在3—5. 5 V 的电压范围,采用多种封装形式,从而使系统设计灵活、方便,设定分辨率及用户设定的报警温度存储在 EEPROM 中,掉电后依然保存。其内部结构如图所示:

ROM 中的 64 位序列号是出厂前被光刻好的,它可以看作是该 DS18B20 的地址序列码,每个 DS18B20 的 64 位序列号均不相同。 64 位 ROM 的排列是:前 8 位是产品家族码,接着 48 位是 DS18B20 的序列号,最后 8 位是前面 56 位的循环冗余校验码(CRC=X8+X5+X4 +1)。 ROM 作用是使每一个 DS18B20 都各不相同,这样就可实现一根总线上挂接多个。所有的单总线器件要求采用严格的信号时序,以保证数据的完整性。 DS18B20 共有 6 种信号类型:复位脉冲、应答脉冲、写 0、写 1、读 0 和读 1。所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。这里我们简单介绍这几个信号的时序:

1) 复位脉冲和应答脉冲

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us,,以产生复位脉冲。接着主机释放总线, 4.7K 的上拉电阻将单总线拉高,延时 15~60 us,并进入接收模式(Rx)。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,若为低电平,再延时 480 us。

2) 写时序

写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次独立的写时序之间至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总线。写 1 时序:主机输出低电平,延时 2us,然后释放总线,延时 60us。写 0 时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。

3)读时序

单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的 15us 之内采样总线状态。典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us。

在了解了单总线时序之后,我们来看看 DS18B20 的典型温度读取过程, DS18B20 的典型温度读取过程为:

复位发 SKIP ROM 命令( 0XCC)

发开始转换命令( 0X44)

延时复位发送 SKIP ROM 命令( 0XCC) 发读存储器命令( 0XBE) 连续读出两个字节数据(即温度)。

结束。DS18B20 的介绍就到这里,更详细的介绍,请大家参考 DS18B20 的技术手册。

1.2 DS18B20 原理图

从原理图中,我们知道了 DS18B20 使用的是单片机的 PG11。

1.3 DS18B20 的初始化

1. 在进行初始化之前,要先进行 IO 口的初始化。

/******************************************************************************
*
* 函 数 名 : ds18b20_init
* 函数功能
: IO 端口时钟初始化函数
* 输 入 : 无
* 输 出 : 无*******************************************************************************
/
void ds18b20_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
GPIO_Ini;
GPIO_Ini;
GPIO_Ini;
GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure);
}

管脚定义是在其头文件内:

#define dq (GPIO_Pin_11) //PG11
#define GPIO_ds18b20 GPIOG
#define ds18b20_dq_H GPIO_SetBits(GPIO_ds18b20,dq)
#define ds18b20_dq_L GPIO_ResetBits(GPIO_ds18b20,dq)

2. DS18B20 的初始化

主机首先发出一个 480-960 微秒的低电平脉冲,然后释放总线变为高电 平,并在随后的 480 微秒时间内对总线进行检测,如果有低电平出现说明总 线上有器件已做出应答。若无低电平出现一直都是高电平说明总线上无器件 应答。作为从器件的 DS18B20 在一上电后就一直在检测总线上是否有 480-960 微秒的低电平出现,如果有,在总线转为高电平后等待 15-60 微秒后将 总线电平拉低 60-240 微秒做出响应存在脉冲, 告诉主机本器件已做好准备。 若没有检测到就一直在检测等待。

3. 初始化时序图

4. 例程代码:

/******************************************************************************
*
* 函 数 名 : ds18b20init
* 函数功能
: DS18B20 初始化时序
* 输 入 : 无
* 输 出 : 无
*******************************************************************************
/
void ds18b20init()
{
DQOUTINT();//输出
ds18b20_dq_L;
delay_us(480);//延时 480 微妙
ds18b20_dq_H;
delay_us(480);//延时 480 微妙
}

1.4DS18B20 读操作

主机发出各种操作命令都是向 DS18B20 写 0 和写 1 组成的命令字节, 接 收数据时也是从 DS18B20 读取 0 或 1 的过程。因此首先要搞清主机是如何 进行写 0、写 1、读 0和读 1 的。写周期最少为 60 微秒,最长不超过 120 微秒。写周期一开始做为主机先 把总线拉低1 微秒表示写周期开始。随后若主机想写 0,则将总线置为低电 平,若主机想写 1,则将总线置为高电平,持续时间最少 60 微秒直至写周期 结束,然后释放总线为高电平至少 1微秒给总线恢复 。而 DS18B20 则在检 测到总线被拉底后等待 15 微秒然后从 15us 到45us 开始对总线采样, 在采样 期内总线为高电平则为 1,若采样期内总线为低电平则为0。

1.读操作时序图

2.读操作程序

/******************************************************************************
*
* 函 数 名 : 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;//读数据 从低位开始
}
delay_us(45);//延时 45 微妙
}
return value;
}

1.5DS18B20 写操作

对于读数据操作时序也分为读 0 时序和读 1 时序两个过程。 读周期是从主机把单总线拉低 1 微秒之后就得释放单总线为高电平,以让 DS18B20 把数据传输到单总线上。作为从机 DS18B20 在检测到总线被拉低 1 微 秒后,便开始送出数据,若是要送出 0 就把总线拉为低电平直到读周期结束。若 要送出 1 则释放总线为高电平。主机在一开始拉低总线 1 微秒后释放总线,然后 在包括前面的拉低总线电平 1 微秒在内的 15 微秒时间内完成对总线进行采样检 测,采样期内总线为低电平则确认为 0。采样期内总线为高电平则确认为 1。完 成一个读时序过程,至少需要 60 微秒才能完成。

1.写操作时序图

2.写操作程序

/***************************************************************************
****
* 函 数 名 : ds18b20wr
* 函数功能
: DS18B20 写数据时序
* 输 入 : dat
* 输 出 : 无
***************************************************************************
****/
void ds18b20wr(u8 dat)
{
u8 i=0;
DQOUTINT();//输出
for(i=0;i<8;i++)
{
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;//准备下一位数据的发送
}
}

1 .6 DS18B20 的寄存器简介

1.DS18B20 内部结构主要由四部分组成:

1) 64 位光刻 ROM光刻 ROM 中的 64 位序列号是出厂前被光刻好的,它可以看作是 该 DS18B20的地址序列码。 64 位光刻 ROM 的排列是:开始 8 位 (地址: 28H )是产品类型标号,接着的 48 位是该 DS18B20 自身 的序列号,并且每个 DS18B20 的序列号都不相同,因此它可以看作是 该 DS18B20 的地址序列码; 最后 8 位则是前面 56 位的循环冗余校验 码( CRC=X8+X5+X4+1 ) 。由于每一个 DS18B20 的ROM 数据都各 不相同,因此微控制器就可以通过单总线对多个 DS18B20 进行寻址, 从而实现一根总线上挂接多个 DS18B20 的目的。

2) 温度传感器

3) 非挥发的温度报警触发器 TH 和 TL

4) 配置寄存器。

2.DS18B20 的存储器由一个高速暂存 RAM 和一个非易失性、 电可擦除 (E2)RAM 组成。

在这里我们看一下第 4 个字节(CONFIG)配置寄存器。

出场设置默认 R0、R1 为 11。也就是 12 位分辨率,也就是 1 位代表 0.0625 摄氏度。

1 .7DS18B20 命令简介

1.8 读取温度操作

1. 读取温度操作

DS18B20 经转换所得的温度值以二字节补码形式存放在高速暂存存储器 的第 0 和第1 个字节。所以当我们只想简单的读取温度值的时候,只用读取 暂存器中的第 0 和第 1 个字节就可以了。读取一次 D18B20 温度的操作步骤 如下:

a) 初始化 DS18B20

b) 跳过 ROM 操作(ROM 里面可以读取 DS18B20 的地址、型号,还有 配置分辨率等,我们只使用一个 DS18B20,所以不用读取地址型号,配置直接使用默认的 12 位分辨率就好了。 )

c) 发送温度转换命令。

d) 跳过 ROM 操作

e) 发送读取温度命令

f) 读取温度值。

2 补码介绍 什么是补码

1) 正数的补码是正数本身

2) 负数的补码是原码取反,然后再加 1。

 DS18B20 存储的温度值是以补码的形式存储的,所以读出来的温度 值是实际温度值的补码,要把的转换为原码。

1) 正温度的话,原码就是补码本身,所以在 12 位分辨率下,温度 的计算公式是: 温度值=读取值*0.0625

2) 负温度的话,原码是补码减 1 再取反,所以在 12 位分辨率下, 计算公式为: 温度值= -(读取值减 1 再取反)*0.0625

3. 读取温度程序函数

/***************************************************************************
****
* 函 数 名 : readtemp
* 函数功能
: DS18B2 温度寄存器配置,温度读取
* 输 入 : 无
* 输 出 : value
***************************************************************************
****/
double readtemp()
//读取温度内需要复位的
{
u16 temp;
u8 a,b;
double value;
ds18b20init();
//初始化
ds18b20wr(0xcc); //发送忽略 ROM 指令
ds18b20wr(0x44); //发送温度转换指令
delay_ms(800);
ds18b20init(); //初始化
ds18b20wr(0xcc); //发送忽略 ROM 指令ds18b20wr(0xbe); //发读暂存器指令
a=DS18b20rd();
//温度的低八位
b=DS18b20rd();
//温度的高八位
temp=b;
temp=(temp<<8)+a;
if((temp&0xf800)==0xf800)
{
temp=(~temp)+1;
value=temp*);
}
else
{
value=temp*0.0625;
}
return value;
}

1.9 例程主函数

/***************************************************************************
*
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
***************************************************************************
*/
int main()
{double temp;
printf_init(); //printf 初始化
ds18b20_init();
//DS18B20 初始化
while(1)
{
temp=readtemp(); //读取温度
printf("当前温度为:%0.4lf ℃rn",temp);
}
}

主程序的效果是,读取到的温度值通过 printf 输出打印到串口助手上,如下:

当程序下载进去后,打开串口,对 DTR 前进行勾选,然后在取消。再通过发送字符即可以显示。

相关推荐