基于STM32F103——DS18B20温度采集+串口打印
Posted 皮卡丘吉尔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于STM32F103——DS18B20温度采集+串口打印相关的知识,希望对你有一定的参考价值。
好久没更新文章了,最近终于能抽空写写笔记了。坚持!!! 加油!
DS18B20温度传感器
DS18B20相关介绍
DS18B20特性
1.独特的单总线接口,就需一条线则可实现双向通信(测温)
2.测温范围:-55℃~+125℃,可通过编程设定9—12位分辨率,对应分辨温度分别为0.5、0.25、0.125、0.0625℃。
3.支持多点组网(可连接多个DS18B20温度传感器),多个DS18B20可以并联(3或2线)实现多个组网测温,但注意超过8个要解决好供电问题,否则电压过低会导致传输不稳定,从而数据不准确。
4.工作电压:3.0~5.5V (寄生电源方式下可由数据线供电)
5.在使用过程中不需要外围电路,全部传感元件及转换电路都在芯片内了。(上拉电阻)
6.测温结果直接是数字量输出,单总线串行传送方式,同时可传送CRC校验码(校验数据采集是否正确),具有极强的抗干扰和纠错能力。
7.在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字。
8.负压特性:电源极性接反时,芯片不会因发热而烧毁, 但不能正常工作。
封装形式与引脚说明
供电方式(外部电源供电、寄生电源供电、寄生电源强上拉)
内部结构
DS18B20内部结构如图所示,其中与操作有关的是:64位光刻ROM、温度传感器、9个字节的RAM存储器、EEPROM(温度报警寄存器TH和TL、配置寄存器)。
光刻ROM中64位序列号是出厂前就光刻好的,相当地址序列号。排列是低位开始,低8位(产品类型标号),接着48位(自身序列号,)相当于身份证号、最高8位(前面56位的循环亢余校验码)。
如果一条总线挂接多个DS18B20需要MCU(微控制器)通过单总线对多个DS18B20进行寻址。
温度存储格式及配置寄存器(模式和分辨率)
DS18B20温度传感器进行测温,测温是以16位的二进制形式提供。
存放格式:
16位中 低4位是温度的小数部分、最高5位是温度的正负(全为0为正,全为1为负),中间的7位则是温度的整数部分。小数部分十进制等于16进制乘0.0625。
例子:
注意:如果是负数温度,那么得按位取反+1。
下面是数据处理例子
温度数据的处理
比如我接收temp数据:十进制:64656 16进制:0XFC90
二进制: 1111 1100 1001 0000
首先先看高5位 是1哦 好 那温度就是负数 (是0就是正数 不用取反+1)
我们得得取反+1 temp = ~temp + 1;
即 1111 1100 1001 0000
取反后 0000 0011 0110 1111
+1结果 0000 0011 0111 0000
此时结果为: 0000 0011 0111 0000
整数温度等于 温度整数 = temp >> 4; 把小数部分(低四位扔掉就行了)
二进制: 0011 0111
10进制:55 16进制: 0X37
小数温度等于 温度小数 = temp & 0x0f; 就要低四位 低四位是小数部分
二进制: 0000 0000
10进制: 0 16进制: 0X00
所以 温度就是 -55.0°C
如果看得比较绕 就直接往下看吧 看下面的代码。。。。。。
配置寄存器
TM | R1 | R0 | 1 | 1 | 1 | 1 | 1 |
---|
TM:测试模式位,用于设置是在工作方式还是测试模式。在DS18B20出厂时该位设为0,用户不要改动。
R1 R0:分辨率设置
R1 | R0 | 分辨率/位 | 温度最大转向时间/ms |
---|---|---|---|
0 | 0 | 9 | 93.75 |
0 | 1 | 10 | 187.5 |
1 | 0 | 11 | 375 |
1 | 1 | 12 | 750 |
需要修改精度的 往下看 下面有写
DS18B20指令(ROM指令操作)
序号 | 指令 | 代码 | 说明 |
---|---|---|---|
1 | 读取ROM | 33H | 读DS18B20的64位序列号(只能适用于总线上只有一个DS18B20) |
2 | 符合 ROM | 55H | 匹配指令,发出64位ROM编码,与总线上一个或多个DS18B20匹配,完全对应则响应。(单个或多个均可) |
3 | 跳过 ROM | CCH | 忽略64位ROM地址,直接向DS18B20发温度变换指令,适用于单片机工作。(适用于单个DS18B20)。 |
4 | 搜索 ROM | F0H | 用于确定挂接在总线上DS18B20个数和 识别64位ROM地址(一般用于多个DS18B20)。 |
5 | 报警搜索命令 | ECH | 执行后搜索温度超过设定值上限或下限才做出响应。 |
6 | 写暂存器 | 4EH | 在该写暂存器指令后向DS18B20的暂存器TH.TL以及配置寄存器中写入数据。 |
7 | 读暂存器 | BEH | 发送该指令后DS18B20将从一个字节开始,依次送出9个字节的内容。如果不想读完所有字节。控制器可以在任何时间发出复位指令中止读取或直接不读取。 |
8 | 复制暂存器 | 48H | 将TH.TL和配置寄存器的内容拷贝到EEPROM中,如果使用寄生电源,总线控制器必须在这条指令发出后10us内启动强上拉并保持至少10ms时间。 |
9 | 启动温度转换指令 | 44H | 温度转换完成后存放在第1个和第2个字节中,如果是寄生电源,总线必须在发出这条指令后的10us内启动强上拉。 |
10 | 复制EEPROM指令 | B8H | 把TH.TL和配置寄存器的值拷贝回暂存器。这种拷贝操作在DS18B20上电时自动执行,上电后,暂存器里就存了有效数据。 |
11 | 读供电方式指令 | B4H | 发给DS18B20后,再发出读时间间隙,后返回电源模式:0为寄生电源、1为外部电源。 |
注:每个指令在写都是 低位在前 高位在后 DS18B20发送也是先发低位,再发高位。 | |||
比如发送跳过ROM指令(CCH) 二进制位:1100 1100 。发送顺序为 | |||
0、0 、1、1、 0、 0、 1、 1 。 |
指令的使用
多个DS18B20情况: 对某一个操作时,主机先逐个与DS18B20挂接-搜索ROM——(F0H),发出匹配ROM指令(55H),紧接着提供64位序列号,之后操作就是针对DS18B20的了。
单个DS18B20情况: 不需要搜索ROM指令,读ROM指令以及匹配ROM等操作,直接跳过ROM指令(CCH),温度转换(44H),读温度操作(8EH)。
注意事项
一、 DS18B20硬件是简单,但软件就比较复杂,特别是时序要求。
二、 连接DS18B20线长限制:部分资料显示:
采用普通信号电缆传输超50m时,测温数据不稳定。
采用带屏蔽层双绞线电缆,正常通讯距离可达到150m。
采用每米绞合次数更多的带屏蔽层双绞线电缆时,通讯距离进一步加长。
三、 距离长了测温要考虑总线分布电容和阻抗匹配问题。
在测温程序设计中,一般如果硬件没什么问题,可以采用延时来跳过检测,但是如果要检测是否有应答要注意不要进入了死循环。
时序图
查看 DS18B20 状态 函数
/******************************************************************
描述: DS18B20 查看状态 函数
返回: 0:应答 1:不应答
*******************************************************************/
uint8_t ds18b20_check(void)
uint8_t ack = 0;
DS18B20_SET_OUT; //设置输出模式
DS18B20_HIGH; //起始拉高电平
DS18B20_LOW; //拉低电平
delay_us(480); //维持480us
DS18B20_HIGH; //释放总线
DS18B20_SET_IN; //设置输入模式
delay_us(25); //维持15~60us 最好是25us以上 25以下测试不够时间
if( GPIO_ReadInputDataBit(DS18B20_PORT, DS18B20_PIN) == SET)
ack = 1; //没应答
DS18B20_HIGH; //释放总线
delay_us(240); //保证时序完整
return ack;
写时序 DS18B20写一字节函数
/******************************************************************
描述: DS18B20 写一字节指令 函数
参数: cmd: 要写入的指令
*******************************************************************/
void ds18b20_write_cmd(uint8_t cmd)
uint8_t i;
DS18B20_SET_OUT;//设置输出模式
for(i=0; i<8; i++)
DS18B20_LOW; //拉低总线
delay_us(1); //至少1us
if(cmd & 0x01)
DS18B20_HIGH;
else
DS18B20_LOW;
delay_us(60); //继续维持至少60us 最多120us 电平
DS18B20_HIGH; //释放总线
cmd >>= 1; //右移一位
读时序 DS18B20读取一字节函数
/******************************************************************
描述: DS18B20 读取一字节数据 函数
返回: 返回读取到的数据
*******************************************************************/
uint8_t ds18b20_read_data(void)
uint8_t i;
uint8_t data = 0;
for(i=0; i<8; i++)
DS18B20_SET_OUT;//设置输出模式
DS18B20_LOW; //拉低总线
DS18B20_SET_IN; //设置输入模式
data >>= 1;
if( GPIO_ReadInputDataBit(DS18B20_PORT, DS18B20_PIN) == 1)
data |= 0x80;
delay_us(45);
DS18B20_HIGH; //释放总线
return data;
程序代码(部分)
由于代码多 我这里就不一一贴出来了 需要可以 留言
由于代码多 我这里就不一一贴出来了 需要可以 留言
每一次进行写ROM相关命令都记得初始化。
对于单个DS18B20我们可以直接跳过ROM指令 直接温度转换。读取温度
步骤:
1.初始化
2.跳过ROM指令
3.启动温度转换(转换出来需要时间)
4.延时(等待温度转换)加不加都行
5.初始化 (记得每写ROM相关命令记得需要从初始化开始)
6.读取温度
DS18B20 相关代码
DS18B20 修改精度函数
修改精度 需要用到一个指令 写暂存器 0X4E
写暂存器: 在该写暂存器指令后向DS18B20的暂存器TH.TL以及配置寄存器中写入数据。(不了解可以看看上面的结构图)
所以我们一次得写入3个参数 代码如下:
/*******************************************************************************
描述: DS18B20 设置低温限值、高温限值、精度 函数
参数: temp_low: 写高速缓存器TL低温限值 temp_high:写高速缓存器TH高温限值
accuracy: 精度设置 9/10/11/12 (默认12位)
********************************************************************************/
static uint8_t ds18b20_set_accuracy(uint8_t temp_low,uint8_t temp_high,uint8_t accuracy)
if(ds18b20_check() == 1)
return 1;
ds18b20_write_cmd(WRITE_MEMORY); //写暂存器指令4E
ds18b20_write_cmd(temp_high); //写高速缓存器TH高温限值 temp_high 度
ds18b20_write_cmd(temp_low); //写高速缓存器TL低温限值 temp_low 度
ds18b20_write_cmd(accuracy); //精度设置
return 0;
DS18B20初始化函数
#define DS18B20_SET_OUT ds18b20_set_output_mode() //设置输出模式
/******************************************************************
描述: DS18B20 设置成输出模式 函数
*******************************************************************/
void ds18b20_set_output_mode(void)
GPIO_InitTypeDef DS18B20_Struction; //定义结构体成员
RCC_APB2PeriphClockCmd(DS18B20_RCC, ENABLE); //打开时钟
DS18B20_Struction.GPIO_Pin = DS18B20_PIN; //引脚
DS18B20_Struction.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
DS18B20_Struction.GPIO_Speed = GPIO_Speed_50MHz;//速率
GPIO_Init(DS18B20_PORT,&DS18B20_Struction); //对成员进行初始化
/******************************************************************
描述: DS18B20 配置函数
参数: accuracy: 精度
默认是 12位分辨率 转换时间750ms
9位分辨率 0x1f : 0.5 °C 转换时间需要93.75ms
10位分辨率0x3f : 0.25 °C 转换时间需要187.5ms
11位分辨率0x5f : 0.125 °C 转换时间需要375ms
12位分辨率0x7f : 0.0625°C 转换时间需要750ms
返回: 0:成功 1:失败
*******************************************************************/
uint8_t ds18b20_init(uint8_t accuracy)
uint8_t status;
DS18B20_SET_OUT; //设置成输出模式
status = ds18b20_set_accuracy(0,70,accuracy); //设置转换精度
return status;
DS18B20读取温度函数
/******************************************************************
描述: DS18B20 读取温度 函数
返回: 读取成功:DS18B20_READ_SUCCESS 读取失败:DS18B20_READ_FAILURE
*******************************************************************/
uint8_t ds18b20_read_temperature(void)
uint8_t low,high;
uint16_t temp = 0;
if(ds18b20_check() == 1) //DS18B20 初始化
return DS18B20_READ_FAILURE;//读取失败
ds18b20_write_cmd(SKIP_ROM); //跳过ROM
ds18b20_write_cmd(TEMP_SWITCH); //启动温度转换
ds18b20_check(); //DS18B20 初始化
ds18b20_write_cmd(SKIP_ROM); //跳过ROM
ds18b20_write_cmd(READ_MEMORY); //发送读暂存存储器指令
//D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 16位数据 说明
//** 温度正负标志 ** ** 温度整数部分 ** **小数部分**
low = ds18b20_read_data(); //低字节
high = ds18b20_read_data(); //高字节 高5位是正负标志 全为1 负 全为0 正
temp = ((uint8_t)high<<8) | low;
if(temp & 0x8000)
ds18b20_temp_symbol = 1;//负温度
temp = ~temp + 1;
else
ds18b20_temp_symbol = 0;//正温度
ds18b20_temp_integer = temp >> 4; //整数部分
ds18b20_temp_decimal = temp & 0x0f; //小数部分
if(ds18b20_temp_integer >= 100)
ds18b20_temp_integer = 99; //保持在2位数
return DS18B20_READ_SUCCESS;//读取成功
串口 相关代码
如果 对 串口 不熟悉的 可以参考 我之前写的 文章STM32串口通信介绍
串口初始化 函数
/* 配置串口1 函数*/
void usart1_init(uint32_t baudRate)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //打开GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //打开串口1时钟
GPIO_InitTypeDef GPIO_initStruction;
USART_InitTypeDef USART_initStruction;
/*配置GPIOA TX */
GPIO_initStruction.GPIO_Pin = USART1_TX; // TX
GPIO_initStruction.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_initStruction.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_initStruction);
/*配置GPIOA RX */
GPIO_initStruction.GPIO_Pin = USART1_RX; // RX
GPIO_initStruction.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_initStruction);
/*配置USART1 TX和RX */
USART_initStruction.USART_BaudRate = baudRate; //波特率
USART_initStruction.USART_WordLength = USART_WordLength_8b; //8位有效数据位
USART_initStruction.USART_StopBits = USART_StopBits_1; //1个停止位
USART_initStruction.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_initStruction.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不硬件控制流
USART_initStruction.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送 和 接收
USART_Init(USART1, &USART_initStruction);
NVIC_USART1_configuration(); //串口1中断优先级配置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断
USART_Cmd(USART1, ENABLE); //使能串口1
串口 发送一字节 函数
/*串口 发送1字节 函数*/
void usart_sendByte(USART_TypeDef* USARTx,uint8_t data)
USART_SendData(USARTx, data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); //等待发送寄存器为空 证明发送完
串口 发送字符串 函数
/*串口 发送字符串 函数*/
void usart_sendString(USART_TypeDef* USARTx,char *str)
while(*str != '\\0')
usart_sendByte(USARTx,*str);
str++;
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET); //发送完成标志位
主程序 main
main.c(主函数)
#include "stm32f10x.h"
#include "ds18b20.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
int main()
char ds18b20_str[10] = 0;
usart1_init(9600); //串口1初始化 波特率9600
while(ds18b20_init(0x5f)) //DS18B20初始化 11位分辨率 0.125
usart_sendString(USART1,"DS18B20 error!\\r\\n");
usart_sendString(USART1,"DS18B20 success!\\r\\n");
while(1)
delay_ms(500);
if(ds18b20_read_temperature() == DS18B20_READ_SUCCESS)
//将温度转换成字符串
sprintf(ds18b20_str,"%2u.%1u%1u%1u\\r\\n",(uint32_t)ds18b20_temp_integer,((uint32_t)ds18b20_temp_decimal*10/16),
((uint32_t)ds18b20_temp_decimal*100/16%10),((uint32_t)ds18b20_temp_decimal*1000/16%10));
usart_sendString(USART1,ds18b20_str); //通过串口发送出去
else
usart_sendString(USART1,"DS18B20 error!\\r\\n");
项目展示
如果觉得这篇文章对你有用。欢迎大家点赞、评论哈哈
需要整个工程代码,欢迎大家打赏,评论区留上你的邮箱 或者+我Q:844797079 or vx or qq。o( ̄︶ ̄)o
继续加油!!!
以上是关于基于STM32F103——DS18B20温度采集+串口打印的主要内容,如果未能解决你的问题,请参考以下文章
ArduinoSTM32 利用DS18B20读取温度 on STM32F103C8
STM32F4 HAL库开发 -- 温度传感器(DS18B20)
STM32F4 HAL库开发 -- 温度传感器(DS18B20)
STM32F4 HAL库开发 -- 温度传感器(DS18B20)