温度传感器技术

温度传感器探头 (DS18B20和PT100的功能电路设计)

DS18B20原理图和CUBEMAX配置

之间的比较 PT100温度传感器 探针和 DS18B20模块
1) 信号采集的基本原理
① PT100的阻值随温度成比例变化 (温度越高, 阻力越大), 但电阻变化很小, 关于 0.385 哦 / 程度;
② PT100的温度测量范围为-200℃ -200℃, 且在0℃时, 电阻正好等于 100 哦;
③ PT100的工作电流应小于 5 嘛;
④ 虽然PT100的阻值随温度成比例变化, 其变化率 (那是, K值 K值 K值) 在不同的温度范围内是不同的.

2) PT100耐温变化表

PT100耐温变化表

3. PT100驱动电路

PT100驱动电路

PT100驱动电路

1) 通过分压法, AD采集PT100电压获取电阻值计算温度
PT100在常温水中的电阻值 (25℃25℃25℃) 是关于 109.89 哦.
单片机输出3.3V电压, 电压除以 PT100 大约为:
109.89 * 0.005 = 0.54945 V

根据AD转换公式转换后的AD值约为:
0.54945 / 3.3 * 4096 = 681.98 ≈ 682

当温度升高一度, 假设 PT100 的电阻仅上升 0.385 哦, 分压的变化值约等于:
0.385 * 0.005 = 0.001925 V

根据AD转换公式转换后的AD值约为:
0.001925 / 3.3 * 4096 = 2.39 ≈ 2

实验中, 发现由于stm32电源3.3V电压不稳定, ADC采集PT100电压波动,分压误差较大. 优化方案是设计恒流源电路. 通过采集PT100的电压和恒流源的电流, 即可求出PT100的阻值, 然后就可以得到温度值.

2) 基于LDO稳压器的恒流源电路 (MD5333)
网上有很多测试PT100的驱动电路, 如直流电桥电路, 基于运算放大器的恒流源电路, ETC. 作者在驱动电路的选择上也花了很多功夫, 考虑到电路板的制作难度和元件数量, 最终选择了基于LDO稳压的恒流源电路 (MD5333). 电路图如下:

LDO稳压器恒流源电路 (MD5333)

LDO稳压器恒流源电路 (MD5333)

在此刻, 硬件选型已基本完成. 使用的开发板是正电Atom F10ZET6 Elite Board

DS18B20模块
以便测试实时温度与PT100温度对比, 添加DS18B20模块进行校准对比测试

1) DS18B20简介
DS18B20是单总线温度传感器,测试温度范围为-55~+125℃,精度为±0.5℃. 现场温度以单总线数字方式直接传输, 大大提高了系统的抗干扰能力. 可直接读取被测温度, 并可根据实际需求通过简单编程实现9~12位数字值读取方式. 其工作电压范围为3~5.5V, 并且采用多种包装形式, 使系统设置灵活方便. 用户设置的设定分辨率和报警温度存储在EEPROM中,断电后仍然保存.

DS18B20电路设计

DS18B20电路设计

2) DS18B20工作时序介绍
所有单总线设备都需要严格的信号时序以确保数据完整性. DS18B20有 6 信号类型: 复位脉冲, 响应脉冲, 写 0, 写 1, 读 0 并阅读 1. 所有这些信号, 除了响应脉冲, 是主机发送的同步信号. 并且所有命令和数据都是以字节的低位在前发送.

DS18B20复位脉冲和响应脉冲

DS18B20复位脉冲和响应脉冲

① 复位脉冲和响应脉冲
单总线上的所有通信均以初始化序列开始. 主机输出低电平并保持低电平至少480us产生复位脉冲. 然后主机释放总线, 4.7K上拉电阻将单总线拉高, 延迟时间15~60us, 并进入接收模式 (接收). 然后DS18B20将总线拉低60~240us,产生低电平响应脉冲.

DS18B20写时序

DS18B20写时序

② 写入时序
写时序包括写 0 计时和写作 1 定时. 所有写入时序至少需要 60us, 两次独立写时序之间至少需要1us恢复时间. 两个写入时序均从主机拉低总线开始. 写 1 定时: 主机输出低电平, 延迟2us, 然后释放总线, 延迟60us. 写 0 定时: 主机输出低电平, 延迟60us, 然后延迟2us释放总线.

DS18B20读取时序

DS18B20读取时序

③ 读取时序
单总线设备仅在主机发出读时序时才向主机传输数据. 所以, 主机发出读数据命令后, 必须立即生成读取时序,以便从机可以传输数据. 所有读取时序至少需要 60us, 两次独立的读时序之间至少需要1us的恢复时间. 每次读取时序均由主机发起, 这会拉低总线至少 1us. 主机必须在读计时期间释放总线,并在计时开始后15us内采样总线状态. 典型的读时序过程是: 主机输出低电平延时2us, 然后主机切换到输入模式延迟12us, 然后读取单总线当前电平, 然后延迟50us.

DS18B20打开串口打印温度信息

DS18B20打开串口打印温度信息

了解单总线时序后, 我们看一下DS18B20的典型温度读取过程. DS18B20的典型温度读取流程为: 复位 → 发送 SKIPROM (0xCC) → 发送启动转换命令 (0x44) → 延时 → 复位 → 发送 SKIPROM 命令 (0xCC) → 发送内存命令 (0乙醚) → 读取两个字节的数据 (IE. 温度) 连续→结束.

3) 示意图和CUBEMAX配置
从原理图来看, 可以看到DS18B20通过PG11口使能打开串口打印温度信息

DS18B20原理图和CUBEMAX配置

DS18B20原理图和CUBEMAX配置

DS18B20温湿度传感器接口

DS18B20温湿度传感器接口

4) 代码部分
代码部分移植了正电Atom的ds18b20库并稍作修改

#ifndef __DS18B20_H
#定义__DS18B20_H

#包括 “蒂姆.h”
/***********************************************************************************/
/* DS18B20引脚定义 */

#定义 DS18B20_DQ_GPIO_PORT GPIOG
#定义 DS18B20_DQ_GPIO_PIN GPIO_PIN_11
#定义DS18B20_DQ_GPIO_CLK_ENABLE() 做{ __HAL_RCC_GPIOG_CLK_ENABLE(); }尽管(0) /* PG口时钟使能 */

/**********************************************************************************************/

/* IO操作功能 */
#定义DS18B20_DQ_OUT(x) 做{ x ? \
HAL_GPIO_WritePin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN, GPIO_PIN_RESET); \
}尽管(0) /* 数据端口输出 */
#定义 DS18B20_DQ_IN HAL_GPIO_ReadPin(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN) /* 数据端口输入 */

uint8_t DS18b20_init(空白); /* 初始化DS18B20 */
uint8_t DS18b20_check(空白); /* 检查DS18B20是否存在 */
短 ds18b20_get_温度(空白);/* 获取温度 */

#恩迪夫

5. 红外遥控模块
1) 无线模块编码协议

红外遥控广泛采用的编码方式有: PWM的NEC协议 (脉宽调制) 和飞利浦 PPM 的 RC-5 协议 (脉冲位置调制). 开发板自带的遥控器采用NEC协议, 它具有以下特点:

1. 8-位地址和8位指令长度;

2. 地址和命令传输两次 (确保可靠性);

3. PWM脉冲位置调制, 传输的红外载波的占空比代表 “0” 和 “1”;

4. 载波频率为38Khz;

5. 位时间为1.125ms或2.25ms;

在NEC协议中, 如何将协议中的数据设置为 ‘0’ 或“1”? 这里, 红外接收器和红外发射器分离.

红外发射器: 发送协议数据‘0’=载波信号传输560us + 560使用无载波信号传输

发送协议数据‘1’=载波信号传输560us + 1680使用无载波信号传输

红外发射器的位定义如下图所示

红外接收头: 接收协议数据‘0’=560us低电平 + 560美国高层

接收协议数据‘1’=560us低电平 + 1680美国高层

NEC远程控制命令的数据格式为: 同步终端, 地址码, 地址反码, 控制码, 控制反码. 同步码由9ms低电平和4.5ms高电平组成. 地址代码, 地址反码, 控制码, 和控制反码都是8位数据格式. 按低位在先、高位在后的顺序发送. 使用反码来增加传输的可靠性.

所以, 输入捕捉可测量高电平脉宽,实现遥控解码.
2) 示意图和CUBEMAX配置

从原理图来看, 我们可以看到无线模块通过PB9引脚使能并通过 4 TIM4通道:

TIM4_CH4的默认引脚不是PB9, 所以需要手动设置, 并且同时开启中断设置

3) 代码部分
通过tim回调函数捕获上升沿

此时, 可以得到解码信号:

此时, 数据比较复杂,可以稍微处理一下:

效果如下:
最后两位是解码后的码及其反码. 此时, 可以定义一个宏来调整温度阈值:

效果如下:

红外部分代码:

/* 用户代码开始标题 */
/**
******************************************************************************
* @文件 : 主程序
* @简短的 : 主程序体
******************************************************************************
* @注意力
*
* <小时2><中心>&复制; 版权 (c) 2024 意法半导体.
* 版权所有。</中心></小时2>
*
* 该软件组件由 ST 根据 BSD 3-Clause 许可证获得许可,
* 这 “执照”; 除非遵守以下规定,否则您不得使用此文件
* 执照. 您可以在以下位置获取许可证副本::
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* 用户代码结束标头 */
/* 包括 ——————————————————————*/
#包括 “主程序.h”
#包括 “蒂姆.h”
#包括 “usart.h”
#包括 “GPIO.h”

/* 私人包括 ———————————————————-*/
/* 用户代码开始包括 */
#包括 “stdio.h”
#包括 “字符串.h”
#定义最大 157
#定义最大下降 87
#定义 MINUP 221
#定义 MINDOWN 61
/* 用户代码结束 包括 */

/* 私有类型定义 ———————————————————–*/
/* 用户代码开始 PTD */

/* 用户代码结束 PTD */

/* 私人定义 ————————————————————*/
/* 用户代码开始 PD */
/* 用户代码结束 PD */

/* 私有宏 ————————————————————-*/
/* 用户代码开始 PM */

/* 用户代码 结束 PM */

/* 私有变量 ———————————————————*/

/* 用户代码开始PV */
uint32_t upCount=0;
uint16_t ValueUp=0;
uint16_t ValueDown=0;
uint8_t isUpCapt=1;
uint16_t 宽度=0;
uint16_t 缓冲区[128]={0};
uint16_t bufferId=0;
uint8_t rcvFalg=0;
/* 用户代码结束PV */

/* 私有函数原型 ———————————————–*/
无效系统时钟_配置(空白);
/* 用户代码开始 PFP */

/* 用户代码结束 PFP */

/* 私人用户代码 ———————————————————*/
/* 用户代码开始 0 */
无效 HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
向上计数++;
}
无效 HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
如果(是上尉)//如果是上升沿捕获
{
ValueUp=HAL_TIM_ReadCapturedValue(赫蒂姆,TIM_CHANNEL_4);
isUpCapt=0;
__HAL_TIM_SET_CAPTUREPOLARITY(赫蒂姆,TIM_CHANNEL_4、TIM_ICPOLARITY_FALLING);
向上计数=0;
}
别的{
ValueDown=HAL_TIM_ReadCapturedValue(赫蒂姆,TIM_CHANNEL_4);
isUpCapt=1;
__HAL_TIM_SET_CAPTUREPOLARITY(赫蒂姆,TIM_CHANNEL_4、TIM_ICPOLARITY_RISING);
宽度=ValueDown+upCount*65536-ValueUp;
如果(宽度>4400&&宽度<4600)
{
缓冲区ID=0;
缓冲[缓冲区ID++]=宽度;
}
否则如果(缓冲区ID>0)
{
缓冲[缓冲区ID++]=宽度;
如果(缓冲区ID>32)
{
rcvFalg=1;
缓冲区ID=0;
}
}
}
}
无效位缓冲区2num(字符数[])
{
编号[0]=0;
编号[1]=0;
编号[2]=0;
编号[3]=0;
为了(整数i=0;我<32;我++)
{
如果(缓冲[我+1]<1000)
{
编号[我/8]=数字[我/8]<<1;
}
别的
{
编号[我/8]=数字[我/8]<<1;
编号[我/8]|=0x01;
}
}
}
/* 用户代码结束 0 */

/**
* @brief 应用程序入口点.
* @retval整数
*/
整型主(空白)
{
/* 用户代码开始 1 */
字符打印缓冲区[128]={0};
字符数[4]={0};
字符键=0;
/* 用户代码结束 1 */

/* 单片机配置——————————————————–*/

/* 重置所有外设, 初始化Flash接口和Systick. */
HAL_初始化();

/* 用户代码开始初始化 */

/* 用户代码结束初始化 */

/* 配置系统时钟 */
系统时钟配置();

/* 用户代码开始 SysInit */

/* 用户代码结束 SysInit */

/* 初始化所有配置的外设 */
MX_GPIO_初始化();
MX_TIM4_初始化();
MX_USART1_UART_Init();
/* 用户代码开始 2 */

/* 用户代码结束 2 */

/* 无限循环 */
/* 用户代码开始同时 */
HAL_GPIO_TogglePin(LED0_GPIO_端口,LED0_引脚);
HAL_TIM_Base_Start_IT(&赫蒂姆4);//定时器更新产生中断
HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_4);//
尽管 (1)
{
如果(接收错误)
{
为了(整数i=0;我<4;我++)
{
位缓冲区2个数(编号);
冲刺函数(打印缓冲区,”0xx “,编号[我]);
HAL_UART_传输(&huart1,打印缓冲区,斯特伦(打印缓冲区),HAL_MAX_DELAY);
}
// 冲刺函数(打印缓冲区,”%你 “,缓冲[我]);
// HAL_UART_传输(&huart1,打印缓冲区,斯特伦(打印缓冲区),HAL_MAX_DELAY);
// }
HAL_UART_传输(&huart1,”\rn”,2,HAL_MAX_DELAY);
rcvFalg=0;
}
打印函数(“%drn”,编号[3]);
如果(编号[3]==157)
{
打印函数(“111111\rn”);
}
HAL_延迟(1000);
/* 用户代码结束同时 */

/* 用户代码开始 3 */
}
/* 用户代码结束 3 */
}

/**
* @brief系统时钟配置
* @retval 无
*/
无效系统时钟_配置(空白)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};