哔哩哔哩视频效果链接:http://【毕业设计——STM32温湿度采集系统】 https://www.bilibili.com/video/BV1Hy421i7sk/?share_source=copy_web&vd_source=d711fa8bef565aeec8a4d279df8b85aa ~~大家可以给个关注,记得一键三连哦~~
一、项目描述:
设计是一种基于STM32的无线温湿度检测系统以智能化、自动化、高效化为出发点,充分利用物联网技术手段,实现温湿度检测系统,实现数据的采集、处理和反馈。首先STM32单片机通过温湿度传感器采集环境温湿度数据,并将数据显示在OLED显示屏上。其次STM32单片机对采集到的数据进行处理,包括计算、数据校验、异常检测等操作;接着将处理后的数据通过WIFI通信模块发送到数据上传到Things Cloud云平台,并在Things Cloud云平台和手机APP会记录采集好的数据显示出来;之后通过手机APP对接收到的数据进行分析处理,以判断环境温湿度是否异常;最后当环境温湿度异常时,STM32报警模块就发出报警及LED灯就会亮,Things Cloud云平台和手机App会记录采集好的数据并显示异常警告提醒用户和方便用户及时采取相应的措施以进一步改善温湿度环境,使室内温湿度环境更加的舒适性和稳定性。
二、项目功能模块:
主要技术:STM32开发、UART、DHT11传感器、OLED、WIFI通信和MQTT协议。
主要元器件:STM32F103、ESP8266、DHT11、舵机等。
编程软件:Keil5、ESPlorer。
平台:Things Cloud云平台
三、模块原理:
DHT11:
DHT11 时序 采用单总线双向串行通信协议,每次采集都要由单片机发起开始信号,然后 DHT11 会向单片机发送响应并开始传输 40 位数据帧,高位在前。数据格式为: 8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据 +8bit 校验位,温湿度小数部分默认为 0,即单片机采集的数据都是整数,校验位 为 4 个字节的数据相加取结果的低 8 位数据作为校验和:
具体时序图如下:
主机或者单片机需要发送一个开始信号给 DHT11 传感器:主机先将 IO 设置为输 出,然后主机拉低总线(时间需要大于 18ms)后设置为输入并释放数据总线,等 待从机(DHT11)响应,主机开始的信号时序为:
如果传感器正常且存在,则会在收到主机的开始信号后拉低总线并持续 80us 来通 知主机此时传感器正常,然后拉高总线 80us,通知主机准备接收,响应的时序为:
如果传感器正常且存在,则会在收到主机的开始信号后拉低总线并持续 80us 来通 知主机此时传感器正常,然后拉高总线 80us,通知主机准备接收,响应的时序为:
接着传感器开始按照高位在前的顺序将数据按照如下的格式,一位一位的输出给主 机:
程序要区分数据 0 和数据 1 的格式:先判断此时引脚的电平状态,如果是低电平 就一直循环等待,直到高电平出现,高电平出现后延时 40us,并读取延时后的电 平状态,如果此时是高电平,则数据为 1,否则为 0。 传输完 40 位数据后,传感器再次输出一个 50us 的低电平后,将数据总线释放, 采集过程结束。
SG90 伺服电机基本原理:
SG90 是一种常见的微型伺服电机,广泛用于远程控制汽车、船只、直升机以及机 器人等领域。图示如下:
sg90 舵机是分为两种的,一种是转角范围 180°的舵机,另外一种是 360°转角 的舵机。 180°舵机是给一个 PWM 信号就转动到一定的角度,然后保持在这个转动之后的 位置,直到有下一个不同的 PWM 信号,才会转到其他的角度。 360°舵机是给一个 PWM 信号,就会按照一定的速度转动。 我们使用的是 360°舵机,电平持续时间与转速关系如下:
即周期 20ms 时,占空比在 2.5%-7.5%时为正转,2.5%时为正转最大速度,占空 比在 7.5%-12.5%时为反转,12.5%时为反转最大速度。
1.接线方式如下:
ESP8266:
该模块提供对 GPIO(通用输入/输出)子系统的访问。
所有访问均基于 NodeMCU 开发套件上的 I/O 索引号,而不是内部 GPIO 引脚。 例如,开发套件上的 D0 引脚映射到内部 GPIO 引脚 16。
如果不使用 NodeMCU 开发套件,请参阅下面的 GPIO 引脚映射以获取索引↔gpio 映射。
引脚对应关系如下:
I2C原理:
概述:
I2C(Inter-Integrated Circuit)通信是一种由 Philips 公司开发的串行通信协议,主 要用于近距离、低速的芯片间通信。它只需要两条双向的信号线,一条数据线 SDA(用于收发数据)和一条时钟线 SCL(用于通信双方时钟的同步)。I2C 通信 是半双工通信,意味着数据在一条数据线上传输,且同一时刻只能单向传输,要么 从主机到从机,要么从从机到主机。每个数据包的大小为 8 位,采用高位在前、 低位在后的传输顺序。 I2C 通信中,主机通过时钟线 SCL 发送时钟信号,并通过数据线 SDA 发送数据 (如从机地址、指令、数据包等)。在发送完一帧数据后,主机需等待从机的响应 才能继续发送下一帧数据。I2C 总线的操作时序包括写单个存储字节、写多个存储 字节、读单个存储字节和读多个存储字节等不同模式。 I2C 总线支持多主机模式,即可以有多个主机设备在总线上发起通信。在多主机系 统中,仲裁过程是必要的,以避免冲突。当两个主机同时发送数据时,谁先发送高 电平的将会输掉仲裁,即仲裁失败的主机将不再产生时钟脉冲,并需等待总线空闲 时才能重新传输。 I2C 通信中,每个从机都有一个唯一的 7 位或 10 位地址,用于区分不同的从机设 备。I2C 的标准传输速率有多种模式,包括标准模式(100 kbit/s)、快速模式 (400 kbit/s)、快速+模式(1 Mbit/s)等,适用于不同的应用场景。
特征:
- IIC总线组成:由数据线SDA和时钟线SCL构成的串行总线,并且连接上拉电阻保证总线在空闲状态下,为高电平状态。
- 在总线上可以同时运行多个主控器和外围器件设备,使用唯一地址信息标识设备进行通信。
- 通信速率:标准模式100kbit/s,快速模式400kbit/s,高速模式3.4Mbit;
总线时序图:
在整个IIC通信过程中,包含3个特殊信号
- 起始信号:START
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。启动信号是一种电平跳变时序信号,而不是一个电平信号。启动信号是由主控器主动建立的,在建立该信号之前I2C总线必须处于空闲状态。
- 结束信号:STOP
在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。停止信号也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,建立该信号之后,I2C总线将返回空闲状态。
- 应答信号:ACK
I2C总线上的所有数据都是以8位字节传送的,发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
1) 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;
2) 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功.
应答信号:对于主设备和从设备都可以使用
在整个通信过程中,需要保证数据的有效性:
在进行数据位读写的时候,只有保证SCL为高电平的时候,数据位才有效。
四、软件功能配置:
ESP8266配置:
使用 ESPlorer 测试 1、下载并安装 lua 编程及调试工具 ESPlorer 官网链接:https://esp8266.ru/esplorer/配套软件文件夹有免安装版本。 请自行配置好电脑的运行环境。 2、启动 ESPlorer ,设定串口通讯的波特率为 9600。
下载好ESPlorer点击下面链接下载好固件
NodeMcu官方文档:NodeMCU Documentation
在线固件库构建NodeMCU custom builds (nodemcu-build.com)
打开ESPLorer,连接ESP8266,等待刷入新系统后,第一次系统载入。
云平台配置:
MQTT连接有三要素:
1:连接地址
2:用户名
3:密码
五、功能代码:
main.c文件:
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_I2C1_Init();
MX_ADC3_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_TIM1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_ShowCN(20,1,0);
OLED_ShowCN(40,1,1);
OLED_ShowCN(60,1,2);
OLED_ShowCN(20,3,3);
OLED_ShowCN(40,3,4);
OLED_ShowCN(60,3,5);
OLED_ShowCN(20,5,6);
OLED_ShowCN(40,5,7);
OLED_ShowCN(60,5,8);
OLED_ShowCN(90,1,9);
OLED_ShowStr(95,3,"%",2);
OLED_ShowStr(95,5,"J",2);
HAL_UART_Receive_IT(&huart2, (uint8_t *)rxBuffer, rxDataLen);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
sConfig.Channel = ADC_CHANNEL_6; // 设置为通道 6
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; // 设置适合该通道的采样时间
HAL_ADC_ConfigChannel(&hadc3, &sConfig); // 重新配置 ADC
// 开始 ADC 转换
HAL_ADC_Start(&hadc3);
// 等待转换完成
if (HAL_ADC_PollForConversion(&hadc3, 100) == HAL_OK)
{
// 读取 ADC 值
uint32_t light_sensor_data = HAL_ADC_GetValue(&hadc3);
// 将 ADC 值转换为 0-100 范围
int light_sensor_percentage = (int)((light_sensor_data * 100) / 4095);
// 格式化并发送数据
sprintf(msg, "L:%d%J", light_sensor_percentage);
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), 1000);
int L= light_sensor_percentage/10;
int L1= light_sensor_percentage%10;
OLED_ShowStr1(70,5,&L,1,2);
OLED_ShowStr1(80,5,&L1,1,2);
}
// 停止 ADC 转换
HAL_ADC_Stop(&hadc3);
//HAL_Delay(2000); // 稍微延迟,以便区分两个测量
/* 测量热敏电阻 */
//sConfig.Channel = ADC_CHANNEL_4; // 设置为通道 4
//sConfig.Rank = ADC_REGULAR_RANK_1;
//sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; // 可以根据需要调整
//HAL_ADC_ConfigChannel(&hadc3, &sConfig); // 重新配置 ADC
// 开始 ADC 转换
//HAL_ADC_Start(&hadc3);
// 等待转换完成
//if (HAL_ADC_PollForConversion(&hadc3, 100) == HAL_OK)
//{
// 读取 ADC 值
//uint32_t thermistor_data = HAL_ADC_GetValue(&hadc3);
// 将 ADC 值转换为 0-100 范围
//int thermistor_percentage = (int)((thermistor_data * 100) / 4095);
// 格式化并发送数据
//sprintf(msg, "温度 = %d%℃\r\n", thermistor_percentage);
//HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), 1000);
if(DHT_reade())
{
//组包,并准备发送
uint8_t len=snprintf((char
*)message,sizeof(message),"T:%d,H:%d%%",Data[2],Data[0]);
//通过串口发送
HAL_UART_Transmit(&huart1,message,(uint8_t)len,1000);
int T=Data[2]/10;
int T1=Data[2]%10;
int H=Data[0]/10;
int H1=Data[0]%10;
OLED_ShowStr1(70,1,&T,1,2);
OLED_ShowStr1(80,1,&T1,1,2);
OLED_ShowStr1(70,3,&H,1,2);
OLED_ShowStr1(80,3,&H1,1,2);
}
else
{
const char*error_msg="DHT11 fail\r\n";
HAL_UART_Transmit(&huart1,(uint8_t
*)error_msg,strlen(error_msg),1000);
}
if (Data[2] > thread)
{
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_0);
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); // 低电平亮
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); // 高电平熄灭
HAL_Delay(500);
//HAL_TIM_PWM_Start_IT(&htim3,TIM_CHANNEL_3);
}
else
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); // 高电平熄灭
HAL_Delay(500);
// HAL_TIM_PWM_Stop_IT(&htim3,TIM_CHANNEL_3);
}
HAL_Delay(2000);
}
//HAL_Delay(2000);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/*脴庐脵鸥脦禄脪陋脰戮脣鈥∶樎泵炩?溍嬧?⒚暵絓n,脮沤脵鸥脦禄脪陋脢露脣鈥∶樎泵炩?溍嬧?⒚暵絓r*/
if(huart->Instance == USART2)
{
if((USART_RX_STA & 0x8000) == 0)
{
if(USART_RX_STA & 0x4000)
{
if(rxData != 0x0a)
{
USART_RX_STA = 0;
}
else
{
USART_RX_STA |= 0x8000;
}
}
else
{
if(rxData == 0x0d)
{
USART_RX_STA |= 0x4000;
}
else
{
USART_RX_BUF[USART_RX_STA & 0X3FFF] = rxData;
USART_RX_STA++;
if(USART_RX_STA > (USART_REC_LEN - 1)) USART_RX_STA = 0;
}
}
}
if (USART_RX_STA & 0x8000)
{
if (strncmp((char *)USART_RX_BUF, "true", strlen("true")) == 0)
{
//HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
//HAL_Delay(500);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
htim3.Instance->CCR3 = 499;
}
else if (strncmp((char *)USART_RX_BUF, "false", strlen("false")) == 0)
{
//HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_3);
}
HAL_UART_Transmit(&huart2, (uint8_t*)USART_RX_BUF, USART_RX_STA & 0X3FFF, 1000); // 1000ms
USART_RX_STA = 0;
char rxBuffer[rxDataLen]="";
}
HAL_UART_Receive_IT(huart, &rxData, 1);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
DHT11.c文件:
#include "dht11.h"
uint8_t Data[5]={0x00,0x00,0x00,0x00,0x00};
//将 GPIO 调节为输入模式
void SET_PIN_INPUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//将 GPIO 调节为输出模式
void SET_PIN_OUTPUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//微秒级延时函数(向下)
void Delay_us(uint16_t us)
{
uint16_t dif=10000;
uint16_t us_con=10000-us;
__HAL_TIM_SET_COUNTER(&htim1,10000);//设置计数值为 10000
HAL_TIM_Base_Start(&htim1);//启动定时器
while(dif>us_con)
{
dif=__HAL_TIM_GET_COUNTER(&htim1);//获取定时器的计数值
}
HAL_TIM_Base_Stop(&htim1);//停止定时器
}
//电平读取函数
uint8_t DHT_read_byte(void)
{
uint8_t read_byte=0;//存放 8bit 的高低电平数据
uint8_t temp;//存放读取到的高低电平
uint8_t res=0;
uint8_t i;
for(i=0;i<8;i++)
{
//等待高电平到来
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0&&res<100)
{
Delay_us(1); //1US 读取一次
res++; //防止卡死
}
res=0;
Delay_us(40);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1)
{
temp=1;
}
else temp=0;
//等待低电平到来,开启下一次读取或读取结束
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1&&res<100)
{
Delay_us(1); //1US 读取一次
res++; //防止卡死
}
res=0;
read_byte<<=1;//左移一位,空出末尾
read_byte |= temp;
}
return read_byte;
}
//DHT11 读取温湿度程序
uint8_t DHT_reade(void)
{
uint8_t res=0;
uint8_t i;
//首先发送 18ms 低电平
SET_PIN_OUTPUT();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_Delay(18);
//拉高 20us 高电平等待
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
Delay_us(20);
//32 向 DHT11 发送请求完成,之后等待接收消息
//IO 变为输入模式
SET_PIN_INPUT();
Delay_us(20);
//开始检测
//如果检测到低电平,说明 DHT11 有响应
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0)
{
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0&&res<100)
{
Delay_us(1); //1US 读取一次
res++; //防止卡死
}
res=0;
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1&&res<100)
{
Delay_us(1); //1US 读取一次
res++; //防止卡死
}
res=0;
//反转电平过后,DHT11 开始传输数据
for(i=0;i<5;i++)
{
Data[i]=DHT_read_byte();
}
Delay_us(50);
}
//校验
uint32_t sum=Data[0]+Data[1]+Data[2]+Data[3];
if((sum)==Data[4])
{
return 1;
}
else return 0;
}
I2C.c文件:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file i2c.c
* @brief This file provides code for the configuration
* of the I2C instances.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
I2C_HandleTypeDef hi2c1;
/* I2C1 init function */
void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C1_CLK_DISABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
/* USER CODE BEGIN I2C1_MspDeInit 1 */
/* USER CODE END I2C1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
xm.lua文件:
gpio.mode(4,gpio.OUTPUT,gpio.PULLUP)
local mytimer = tmr.create()
wifi.setmode(wifi.STATION)
station_cfg={}
station_cfg.ssid="HY"
station_cfg.pwd="20252050"
station_cfg.auto=false
wifi.sta.config(station_cfg)
wifi.sta.connect()
payload="{\"temperature\": 26,\"light\": 2000,\"switch\": true}"
m= mqtt.Client("1234567",120,"4m3fazf8zygrj176","09XgoObvkj")
m:on("message",function(client,topic,message)
print("主题是"..topic.."消息是"..message)
t = sjson.decode(message)
if t.command == true then
gpio.write(4,gpio.LOW)
print(t.command)
else if t.command == false then
gpio.write(4,gpio.HIGH)
print(t.command)
end
end
end)
function value ()
s = softuart.setup(9600,4,5)
s:on("data",15,function(data)
print(data)
local input = data
local pos1 = string.find(input, "L:")
local result1 = string.sub(input, pos1 + 2, pos1 + 4)
print(result1)
local pos2= string.find(input, "T:")
local result2 = string.sub(input, pos2 + 2, pos2 + 3)
print(result2)
local pos3 = string.find(input, "H:")
local result3= string.sub(input, pos3 + 2, pos3 + 4)
print(result3)
ok, payload = pcall(sjson.encode, {Light=result1,Temperature=result2,Humidty=result3})
if ok then
print(payload)
else
print("failed to encode!")
end
m:publish("attributes",payload,0,0,
function(client)
print("发布成功"..payload)
end)
--tmr.delay(2000000)
end )
end
function MY_MQTT ()
m:connect("sh-1-mqtt.iot-api.com",1883,
function (client)
print("已连接")
value()
m:subscribe("attributes/push",0,
function(client)
print("订阅成功"..payload)
end)
end)
end
mytimer:register(1000,tmr.ALARM_AUTO,
function()
if wifi.sta.getip() == nil then
print("正在连接")
else
print("连接成功 IP是"..wifi.sta.getip())
mytimer:stop()
MY_MQTT ()
end
end)
mytimer:start()