CH9-TEMP-WET

sts30

image-20240408153346795

STS30引脚图

STS30-DIS在给传感器发送命令后,再发送下一个命令签最少需要等待1ms、写操作时,需发送校验和,只有拥有正确校验和的数据才能被接收,读操作时,主机完成校验和的读取和处理、STS30-DIS支持l2C快速模式(频率最高可达到1000KHz)。

通过查阅STS30-DIS数据手册可知,ADDR引脚拉低时,==设备的地址为Ox4A(默认)==,ADDR引脚拉高时,==设备地址为Ox4B==。在12C通信时,需要用LSB来表示R/W,故设备==写地址时(LSB=0)为Ox94==,设备==读地址时(LSB=1)为0x95==。

image-20240409005031531

IIC数据地址

写时序:具体步骤:开始信号一发送I2C设备地址(8位的数据,高7位是设备地址,最后一位是读写位,1表示读操作,0表示写操作)一从机发送的应答信号(ACK)一再次发送开始信号—发送写入数据的寄存器地址─从机发送的应答信号(ACK)一停止信号

读时序:起始信号—发送要读取设备的地址给从设备(最后一位置0,因为是发送数据)—从机应答信号(ACK)—重新发送起始信号─发送将读取的寄存器地址─从机发送应答信号(ACK)一再一次发送起始信号一再一次发送要读取设备的地址给从设备(最后一位置1,因为要读取数据)一从机发送应答信号(ACK)一从I2c器件里面读取数据—一旦读取完成,主机就会发出NO ACK,表示从机不再需要发送应答信号了一停止信号,结束通信。

image-20240408150529418
主板原理图
image-20240408150033445
扩展模块原理图
引脚表
引脚序号 主板引脚 扩展版模块引脚
1 5v
2 ==PB6== SCL
3 GND GND
4 ==PB7== SDA
5 PB1
6 GND GND
7 PB0 ALE
8 PA8
9 VDD_NODE 3V3
10 PB4

==注意:IC1需要选择PB6,7两个引脚,不能直接通过cubmx默认选项==

温度转换公式
$$
\begin{aligned}
& R H=100 \times \frac{S_{R H}}{2^{16}-1} \
& T\left[^{\circ} \mathrm{C}\right]=-45+175 \times \frac{S_1}{2^{16}-1}\
& T\left[^{\circ} \mathrm{F}\right]=-49+315 \times \frac{S_1}{2^{16}-1}
\end{aligned}
$$

CubeMX配置

MDK配置

CubeMX配置

image-20240402233815111
下载线配置
image-20240409004520865
IIC TEMP配置
image-20240408010029580
Timer配置
image-20240408010115352
Timer的NVIC配置
image-20240406023118649
SPI配置1

由于SPI配置后只有三个引脚被配置,但数据通信时还有一个Lora通信SPI1_NSS对映的PA4需要配置为低电平

image-20240406023344830
SPI配置2
image-20240402233501605
OLED引脚配置
image-20240402233712239
GPIO引脚配置
image-20240402233846175
RTC配置
image-20240402233941646
USART_DMA配置
image-20240402234031056
USART参数配置
image-20240402234101539
USART中断配置(IDLE)
image-20240402234205995
NVIC配置
image-20240402234357385
时钟树配置
image-20240402234506717
生成文件配置1
image-20240402234538464
生成文件配置2

MDK代码编写

TEMP_READ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float STS30_Read(void)
{
unsigned char data[2];

data[0]=0x24;
data[1]=0x0B;

HAL_I2C_Master_Transmit(&hi2c1,0x4A<<1,data,2,10);

HAL_Delay(10);

HAL_I2C_Master_Receive(&hi2c1,(0x4A<<1)+1 ,data,2,10);

return (float)(data[0]<<8|data[1])*175/65535-45;
}

function.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include "function.h"
#include "gpio.h"
#include "stdio.h" //fputc() 函数
#include "string.h"
#include "oled.h"
#include "lora.h"

extern UART_HandleTypeDef huart2; //外部调用串口的结构体
extern DMA_HandleTypeDef hdma_usart2_tx;
extern DMA_HandleTypeDef hdma_usart2_rx;//外部调用串口DMA的结构体

extern I2C_HandleTypeDef hi2c3;//IIC的结构体
extern RTC_HandleTypeDef hrtc;//RTC结构体
extern SPI_HandleTypeDef hspi1;//spi结构体

#define Usart_RX_buffer_len 100//允许不定长接收的数据的缓存区长度
unsigned char usart_rx_sec_len;//接收到一帧串口数据的长度
unsigned char usart_rx_sec_flag;//接收到一帧串口数据接收时的标志位
unsigned char usart_rx_buffer[Usart_RX_buffer_len];//接收数据缓存数组

/********************************* 需要放进function.h *******************************************/
/* Init初始化函数 */
void ALL_Init(void)
{
HAL_TIM_Base_Start_IT(&htim7);
Usart_RX_Init();
IIC_OLED_Init(100);
}
/* IDLE接收函数组 */
void Usart_RX_Init(void)
{
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);//使能IDLE的接收中断
HAL_UART_Receive_DMA(&huart2,usart_rx_buffer,Usart_RX_buffer_len);//打开DMA串口接收函数,第一个变量为串口2结构体,第二个变量为接收的存储数组,第三个为接收数据的大小
}

void Usart_RX_EXTI(void)//需要将`USART_RX_IDLE_EXTI()`放进stm32l0xx_it.c中的`void USART2_IRQHandler(void)`中
{
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE) == SET)//判断IDLE的接收是否产生中断,如果接收到一帧数据,那么就会触发中断,FLAG被置1
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除中断标志位
HAL_UART_DMAStop(&huart2);//关闭DMA防止在处理数据时候接收数据,产生干扰

usart_rx_sec_len = Usart_RX_buffer_len - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//计算出接收缓存中的数据长度
usart_rx_sec_flag=1;//将检测接收完成的标志位置1
}
}
void Usart_RX_DEAL(void)
{
if(usart_rx_sec_flag==1)//判断接收完成标志位是否置1
{

if((Usart_RX_mess[0]=='L') && (Usart_RX_mess[1]=='E') && (Usart_RX_mess[2]=='D'))//用户自定义的函数,在这里我们可以根据需要,设置我们输入特定指令所触发的功能
{
HAL_UART_Transmit_DMA(&huart2,Usart_RX_mess,Usart_RX_sec_len);//
}


usart_rx_sec_flag=0;//将接收完成标志位置0
usart_rx_sec_len=0;//将接收到的数据清零
HAL_UART_Receive_DMA(&huart2,usart_rx_buffer,Usart_RX_buffer_len);//重新设置DMA下次要接收的数据字节数,使能DMA进入接收数据状态
}
}
/* Lora */
unsigned char SPI_WriteRead(unsigned char addr,unsigned char mss)//Lora读写函数
{
extern SPI_HandleTypeDef hspi1;

unsigned char tx_data[2],rx_data[2];
tx_data[0]=addr;//编写tx_data
tx_data[1]=mss;

HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);//将PA4拉低,开始发送数据

HAL_SPI_TransmitReceive(&hspi1,tx_data,rx_data,2,0xff);//SPI传输函数,它可以同时发送和接收数据,hspi是SPI柄,pTxata是要发送的数据缓区指针,pRxpata是接收数据的缓冲中区指针,size是要发送/接收的数据字节数,Timeout是超时时间。


HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);//将PA4拉高,结束发送数据

return rx_data[1];
}
/* IIC OLED */
void IIC_OLED_Init(unsigned char ms)//初始化函数,需要延时100ms
{
HAL_GPIO_WritePin(OLED_POWER_GPIO_Port, OLED_POWER_Pin, GPIO_PIN_RESET);//使能OLED,PB5=LOW
HAL_Delay(ms);//延时100ms
OLED_Init(); //OLED.C中自带的初始化函数
OLED_Clear();//OLED.C中自带的清屏函数,否则会出现乱码
}


void OLED_Write(unsigned char addr,unsigned char data)//OLED的写函数
{
unsigned char pdata[2];//发送的存储数组
pdata[0]=addr;//存储第一个数据
pdata[1]=data;//存储第二个数据

HAL_I2C_Master_Transmit(&hi2c3,0x78,pdata,2,0xff);//在阻塞模式下将大量数据写入特定的内存地址,第一个参数为I2C指针,即用I2C1 还是 I2C2;第二个参数器件地址uint16_t DevAddress(0X78);第三个参数指向发送数据的指针;第四个参数数据的长度;第五个参数发送所需要的时间
}

/* TEMP */
float STS30_Read(void)
{
unsigned char data[2];

data[0]=0x24;
data[1]=0x0B;

HAL_I2C_Master_Transmit(&hi2c1,0x4A<<1,data,2,10);

HAL_Delay(10);

HAL_I2C_Master_Receive(&hi2c1,(0x4A<<1)+1 ,data,2,10);

return (float)(data[0]<<8|data[1])*175/65535-45;
}
/* RTC */
unsigned char * RTC_Data(void)
{
static unsigned char rtc_data[7];

RTC_TimeTypeDef rtc_time_data;
RTC_DateTypeDef rtc_date_data;

HAL_RTC_GetTime(&hrtc,&rtc_time_data,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&rtc_date_data,RTC_FORMAT_BIN);

rtc_data[0]=rtc_date_data.Year;
rtc_data[1]=rtc_date_data.Month;
rtc_data[2]=rtc_date_data.WeekDay;
rtc_data[3]=rtc_date_data.Date;

rtc_data[4]=rtc_time_data.Hours;
rtc_data[5]=rtc_time_data.Minutes;
rtc_data[6]=rtc_time_data.Seconds;

return rtc_data;
}
/********************************* 不用放进function.h *******************************************/
/* printf函数的子函数 */
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,0xffff);
//while(__HAL_UART_GET_IT(&huart2,UART_IT_TC) == RESET){}

return ch;
}

/* 外部中断函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(USER_KEY_Pin==GPIO_Pin)
{
flag_send_rtc=1;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//timer回调函数
{
static int time_flag=0;//定义一个时间函数
if(htim7.Instance == TIM7)//判断是否为TIM7的定时中断
{
if(++time_flag>1000)//判断是否到了1s
{
time_flag=0;
flag_num=1;
}
}
}

function.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef __FUNCTION_H__
#define __FUNCTION_H__


void Layer_switch(const unsigned char layer_choose,const unsigned char layer_state);

void IDLE_RX_Init(void);
void IDLE_RX_Exit(void);
void IDLE_RX_Deal(void);

void Usart_puplish(const unsigned char *ms,const unsigned char ms_len);

unsigned char * RTC_Read(void);
unsigned char SPI_WriteRead(unsigned char addr,unsigned char mess);
unsigned char SPI_WriteRead(unsigned char addr,unsigned char mss);

void OLED_A_Init(unsigned char time_delay);
void OLED_Write(unsigned char addr,unsigned char mss);

void ALL_Init(void);

#endif

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "function.h"
#include "stdio.h"
#include "string.h"
#include "oled.h"
#include "lora.h"

int main(void)
{
ALL_Init();
extern unsigned char flag_num;
extern unsigned char oled_2_pub[16];
unsigned char *rtc_rec_data;
unsigned char oled_1_pub[16];
unsigned char oled_3_pub[16];
unsigned char lora_a_rx[5];
int temp_read;
float temp;
unsigned char temp_tx[5];
while (1)
{
rtc_rec_data=RTC_Read();
if(1==flag_num)
{
flag_num=0;
printf("\r\n RTC:%d-%d-%d %02d:%02d:%02d \r\n",2000+rtc_rec_data[0],rtc_rec_data[1],rtc_rec_data[3],rtc_rec_data[4],rtc_rec_data[5],rtc_rec_data[6]);
}
sprintf((char *)oled_1_pub,"RTC:%02d:%02d:%02d",rtc_rec_data[4],rtc_rec_data[5],rtc_rec_data[6]);
OLED_ShowString(0,oled_1_pub);
/*******************************************/
temp_read=STS30_Read() * 100;
temp=STS30_Read();
sprintf((char *)oled_1_pub,"%.2f",temp);
OLED_ShowString(0,oled_1_pub);
temp_tx[0]= temp_read/1000;
temp_tx[1]=(temp_read/100) % 10;
temp_tx[2]=(temp_read/10)%10;
temp_tx[3]=temp_read%10;
temp_tx[4]=0XAA;
LORA_Tx(temp_tx,5);

IDLE_RX_Deal();
/* USER CODE END WHILE */

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