【蓝桥杯——物联网设计与开发】拓展模块3 - 温度传感器模块

一、温度传感器模块

(1)资源介绍

🔅原理图

蓝桥杯物联网竞赛实训平台提供了一个拓展接口 CN2 ,所有拓展模块均可直接安装在 Lora终端上使用;
图1 拓展接口

温度传感器模块电路原理图如下所示:
图2 温度传感器模块电路原理图

通过两张电路图连接可知,引脚资源配置情况为:

Temperature MCU
SCL PB6
SDA PB7
ALE PB0
[表1 引脚资源配置情况]

🔅STS30-DIS-B(以下资料来源于STS30-DIS-B数据手册)

STS3x-DIS 是盛思锐最新的高精度数字温度传感器。它依赖于业界成熟的CMOSens® 技术,与其前身相比,提供更高的智能,可靠性和更高的精度规格。其功能包括增强的信号处理,两个独特的用户可选择的I2C 地址和高达1 MHz 的通信速度。DFN封装的占地面积为2.5 x 2.5 mm2,同时保持0.9 mm的高度。这允许将STS3x-DIS 集成到各种各样的应用中。此外,2.15 V至5.5 V的宽电源电压范围保证了广泛应用的兼容性。总而言之,STS3x-DIS融合了盛思锐超过15年的数字传感器专业知识。
图3 STS30-DIS 功能框图

🌙引脚分配

Pin Name Comments
1 SDA 串行数据;输入/输出
2 ADDR 地址引脚;输入;连接到逻辑高或低,不要浮空
3 ALERT 指示警告状态;输出;如果不使用,必须保持浮空
4 SCL 串行时钟;输入/输出
5 VDD 电源电压;输入
6 nRESET 复位引脚,低电平有效;输入;如果不使用,建议保持浮空状态;可通过串联电阻R≥2kΩ与VDD连接
7 R 无电气功能;连接到VSS
8 VSS 接地
[表2 STS30-DIS-B引脚分配]

🌙通信

向传感器发送命令后,在传感器接收另一条命令之前,++需要最小的等待时间为1ms++ 。

所有STS30-DIS-B 命令和数据都映射到16位地址空间。此外,数据和命令受到CRC 校验和的保护。这提高了通信的可靠性。对传感器的16位命令已经包括3位CRC校验和。传感器发送和接收的数据总是经过一个8位的CRC校验。

  • 在写方向上,必须传输校验和,++因为STS30-DIS-B只接受后面跟着正确校验和的数据++;
  • 在读方向上,它留给主机来读取和处理校验和;

🌙时钟拉伸 (Clock Stretching)

  • 当没有时钟拉伸的命令发出时,如果没有数据存在,传感器响应一个带有不确认(NACK)的读报头;
  • 当发出带有时钟拉伸的命令时,传感器响应一个带有ACK 的读报头,然后拉下SCL 线。将SCL 线拉下,直到测量完成。一旦测量完成,传感器释放SCL线并发送测量结果;

🌙单次触发模式
图4 单次触发模式下的命令

由图4的流程图可知,单次触发模式的数据获取流程如下:

  1. 第一部分
    图5 发送流程第一部分

🟠️伪代码如下:

cpp 复制代码
I2C开始;
发送7位I2C地址+写命令位;
等待传感器发送ACK;
发送高8位命令;
等待传感器发送ACK;
发送低8位命令;
等待传感器发送ACK;
I2C结束;
  1. 第二部分
    图6 发送流程第二部分

🟠️伪代码如下:

cpp 复制代码
/* 时钟拉伸不使能 */
释放时钟线;(传感器测量中)
I2C开始;
发送7位I2C地址+读命令位;
等待传感器发送NACK;
I2C结束;
释放时钟线;(传感器测量中->传感器测量完成)
I2C开始;
发送7位I2C地址+读命令位;
等待传感器发送ACK;


/* 时钟拉伸使能 */
释放时钟线;(传感器测量中)
I2C开始;
发送7位I2C地址+读命令位;
等待传感器发送ACK;
(传感器将时钟线拉低)
  1. 第三部分
    图7 发送流程第三部分

🟠️伪代码如下:

cpp 复制代码
接收高8位温度数据;
发送ACK;
接收低8位温度数据;
发送ACK;
接收CRC校验和;
发送NACK;
I2C结束;

🌙温度数据转换

(2)STM32CubeMX 软件配置

🔅"工程建立、时钟树配置、Debug 串行线配置、代码生成配置" 在下文中有讲解,这里不再赘述❗️

【蓝桥杯------物联网设计与开发】基础模块1- GPIO输出https://blog.csdn.net/m0_63116406/article/details/135604705?spm=1001.2014.3001.5502

1️⃣点击引脚 PB6 → 选择 GPIO_Output 模式(此处默认为++推挽输出++);

点击引脚 PB7 → 选择 GPIO_Output 模式(此处配置为++开漏输出++);
图8 引脚配置

2️⃣初始化 OLED;(配置步骤在下文中有讲解,这里不再赘述);

【蓝桥杯------物联网设计与开发】基础模块6 - OLED_蓝桥杯物联网oled-CSDN博客

3️⃣生成代码即可;

(3)代码编写

🟢️main 函数

cpp 复制代码
/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t H_VALUE, L_VALUE, CRC_VALUE;    // 高8位数据、低8位数据、CRC校验数据
float temp;                            // 温度数据
uint16_t ui_dat_temp;                    // 显示数据
uint8_t puc_oled[17];                    // OLED显示存储区
/* USER CODE END PV */
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C3_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* 第一部分 */
	I2CStart2();
	I2CSendByte2(0x94);
	I2CWaitAck2();
	I2CSendByte2(0x24);
	I2CWaitAck2();
	I2CSendByte2(0x0B);
	I2CWaitAck2();
	I2CStop2();
	/* 第二部分 */
	HAL_Delay(2);
	I2CStart2();
	I2CSendByte2(0x95);
	I2CWaitAck2();
	I2CStop2();
	HAL_Delay(2);
	I2CStart2();
	I2CSendByte2(0x95);
	I2CWaitAck2();
    /* 第三部分 */
	H_VALUE = I2CReceiveByte2();
	I2CSendAck2();
	L_VALUE = I2CReceiveByte2();
	I2CSendAck2();
	CRC_VALUE = I2CReceiveByte2();
	I2CSendNotAck2();
	I2CStop2();
	if(CRC_VALUE)
	{
		;
	}
	temp = ((H_VALUE << 8) | L_VALUE) * 175.0 / 65535 - 45;
    ui_dat_temp = (uint16_t)(Temp_Read() * 10);
	sprintf((char*)puc_oled, "   Temperature  ");
	OLED_ShowString(0, puc_oled);
	sprintf((char*)puc_oled, "      %.1f  ", ui_dat_temp / 10.0);
	OLED_ShowString(2, puc_oled);
    HAL_Delay(500);    //延时一会儿
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(4)实验现象

能够实时测量环境温度。


二、温度采集接口函数封装

🟡️软件i2c.c

cpp 复制代码
#include "i2c_2.h"

#define DELAY_TIME 20

//I2C总线内部延时函数
static void delay1(unsigned int n)
{
    uint32_t i;
    for ( i = 0; i < n; ++i);
}

//配置SDA引脚为输入模式
void SDA_Input_Mode2(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = SDA2;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//配置SDA引脚为输出模式
void SDA_Output_Mode2(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = SDA2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//SDA引脚输出
void SDA_Output2(uint16_t val )
{
	if(val)
		GPIOB->BSRR |= SDA2;
	else
		GPIOB->BRR |= SDA2;
}
//SCL引脚输出
void SCL_Output2( uint16_t val )
{
	if(val)
		GPIOB->BSRR |= SCL2;
	else
		GPIOB->BRR |= SCL2;
}
//读取SDA引脚状态
uint8_t SDA_Input2(void)
{
	return HAL_GPIO_ReadPin(GPIOB, SDA2);
}

//I2C总线启动信号
void I2CStart2(void)
{
    SDA_Output2(1);
    delay1(DELAY_TIME);
    SCL_Output2(1);
    delay1(DELAY_TIME);
    SDA_Output2(0);
    delay1(DELAY_TIME);
    SCL_Output2(0);
    delay1(DELAY_TIME);
}

//I2C总线停止信号
void I2CStop2(void)
{
    SCL_Output2(0);
    delay1(DELAY_TIME);
    SDA_Output2(0);
    delay1(DELAY_TIME);
    SCL_Output2(1);
    delay1(DELAY_TIME);
    SDA_Output2(1);
    delay1(DELAY_TIME);

}

//等待应答
unsigned char I2CWaitAck2(void)
{
    unsigned short cErrTime = 5;
    SDA_Input_Mode2();
    delay1(DELAY_TIME);
    SCL_Output2(1);
    delay1(DELAY_TIME);
    while(SDA_Input2())
    {
        cErrTime--;
        delay1(DELAY_TIME);
        if (0 == cErrTime)
        {
            SDA_Output_Mode2();
            I2CStop2();
            return ERROR;
        }
    }
    SCL_Output2(0);
    SDA_Output_Mode2();
    delay1(DELAY_TIME);
    return SUCCESS;
}

//发送应答
void I2CSendAck2(void)
{
    SDA_Output2(0);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output2(1);
    delay1(DELAY_TIME);
    SCL_Output2(0);
    delay1(DELAY_TIME);

}

//发送非应答
void I2CSendNotAck2(void)
{
    SDA_Output2(1);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output2(1);
    delay1(DELAY_TIME);
    SCL_Output2(0);
    delay1(DELAY_TIME);

}

//发送一个字节数据
void I2CSendByte2(unsigned char cSendByte)
{
    unsigned char  i = 8;
    while (i--)
    {
        SCL_Output2(0);
        delay1(DELAY_TIME);
        SDA_Output2(cSendByte & 0x80);
        delay1(DELAY_TIME);
        cSendByte += cSendByte;
        delay1(DELAY_TIME);
        SCL_Output2(1);
        delay1(DELAY_TIME);
    }
    SCL_Output2(0);
    delay1(DELAY_TIME);
}

//接收一个字节数据
unsigned char I2CReceiveByte2(void)
{
    unsigned char i = 8;
    unsigned char cR_Byte = 0;
    SDA_Input_Mode2();
    while (i--)
    {
        cR_Byte += cR_Byte;
        SCL_Output2(0);
        delay1(DELAY_TIME);
        delay1(DELAY_TIME);
        SCL_Output2(1);
        delay1(DELAY_TIME);
        cR_Byte |=  SDA_Input2();
    }
    SCL_Output2(0);
    delay1(DELAY_TIME);
    SDA_Output_Mode2();
    return cR_Byte;
}

🟡️软件i2c.h

cpp 复制代码
#ifndef __I2C_2_H
#define __I2C_2_H

#include "main.h"
//I2C总线引脚定义
#define SCL2	GPIO_PIN_6
#define SDA2	GPIO_PIN_7

//接口函数
void I2CStart2(void);
void I2CStop2(void);
unsigned char I2CWaitAck2(void);
void I2CSendAck2(void);
void I2CSendNotAck2(void);
void I2CSendByte2(unsigned char cSendByte);
unsigned char I2CReceiveByte2(void);

#endif

🟡️温度采集函数

cpp 复制代码
/* 温度采集函数,中等可重复性+不使能时钟拉伸 */
float Temp_Read(void)
{
	uint8_t H_VALUE, L_VALUE, CRC_VALUE;
	float temp;
	I2CStart2();
	I2CSendByte2(0x94);
	I2CWaitAck2();
	I2CSendByte2(0x24);
	I2CWaitAck2();
	I2CSendByte2(0x0B);
	I2CWaitAck2();
	I2CStop2();
	HAL_Delay(2);
	
	I2CStart2();
	I2CSendByte2(0x95);
	I2CWaitAck2();
	I2CStop2();
	HAL_Delay(2);
	
	I2CStart2();
	I2CSendByte2(0x95);
	I2CWaitAck2();
	H_VALUE = I2CReceiveByte2();
	I2CSendAck2();
	L_VALUE = I2CReceiveByte2();
	I2CSendAck2();
	CRC_VALUE = I2CReceiveByte2();
	I2CSendNotAck2();
	I2CStop2();
	if(CRC_VALUE)
	{
		;
	}
	temp = ((H_VALUE << 8) | L_VALUE) * 175.0 / 65535 - 45;
	return temp;
}

🔴温度采集接口函数调用实例

cpp 复制代码
/* 采集任务函数 */
void Task_Colt(void)
{
    /* 200ms进入一次 */
	if(cnt_colt < 200)	return;
	cnt_colt = 0;
    /* 温度采集与转换 */
	ui_dat_temp = (uint16_t)(Temp_Read() * 10);
}

三、踩坑日记

(1)引脚配置问题

  1. 推荐使用软件模拟I2C(硬件I2C,在4ti测试出来有问题);
  2. PB7(SDA)配置为开漏输出、速度快;PB6(SCL)配置为推挽输出,速度快;

(2)底层驱动延时问题

🔅注意编写底层驱动时存在两次HAL_Delay(2),释放时钟线作用,根据芯片手册说明,此处需要≥1ms;

(3)ALERT引脚

🔅报警引脚Alert一般用于连接MCU的中断引脚。引脚的输出取决于可编程限制的温度读数值。当满足报警条件时,引脚拉高;

🔅根据手册说明,不使用时必须保持浮空。

相关推荐
嵌入式科普1 分钟前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣4 分钟前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室32 分钟前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费35 分钟前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_397562312 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo20172 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
艺术家天选3 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件
向阳逐梦3 小时前
基于STM32F4单片机实现ROS机器人主板
stm32·单片机·机器人
委员4 小时前
基于NodeMCU的物联网空调控制系统设计
单片机·mcu·物联网·智能家居
小猪写代码4 小时前
STM32 水质水位检测项目 (调试模块)和(延时模块)
stm32·单片机·嵌入式硬件