1.简介
基于STM32的便携式取暖器是一种集成了现代微控制器技术和取暖功能的智能设备。以STM32微控制器为核心,该微控制器具有高性能、低功耗和易于编程的特点。此外,取暖器还配备了温度传感器(如DS18B20)、显示屏(如LCD1602或OLED)、加热元件、控制按键以及可能的无线通信模块(如Wi-Fi或蓝牙)等关键组件。通过STM32微控制器实时读取温度传感器的数据,精确监测环境温度。用户可以通过控制面板或远程APP设定目标温度,当环境温度低于设定值时,取暖器自动启动加热功能;当环境温度达到或超过设定值时,取暖器自动停止加热,实现智能温控。取暖器配备有显示屏,用于显示当前温度、设定温度以及工作状态等信息。用户可以通过控制面板上的按键进行温度设定、开关机等操作。部分高端型号还支持通过蓝牙或Wi-Fi连接智能手机APP,实现远程控制和监控。采用轻便的材质和结构设计,方便用户携带和移动。同时,其内置的电池或可充电电源系统使得取暖器可以在无电源插座的环境下使用,提高了使用的便捷性。
2.发展前景
随着生活水平的提高,消费者对取暖设备的需求日益多样化。便携式取暖器因其小巧、轻便、易于携带的特点,满足了人们在不同场景下对取暖的需求。特别是在户外露营、家庭旅行、办公室取暖等场景中,便携式取暖器具有广泛的应用前景。
根据市场调研数据,取暖设备行业的市场规模在过去几年中呈现出快速增长的趋势。预计未来几年,随着消费者对取暖设备需求的不断增加和技术的持续创新,市场规模将继续扩大。越来越多的企业进入取暖器市场,市场竞争日益激烈。这要求取暖器企业不断提升产品质量、创新技术和服务水平,以满足消费者的需求和期望。智能化和绿色化是未来取暖器行业的发展趋势。基于STM32的便携式取暖器通过集成智能控制技术和采用高效节能技术,符合这一发展趋势,具有广阔的市场前景。
未来几年,便携式取暖器行业有望继续保持增长态势。随着技术的不断进步和市场的不断扩大,行业的竞争格局也将发生深刻变化。一方面,国际知名品牌和地区性品牌之间的竞争将更加激烈;另一方面,新兴技术和创新模式也将不断涌现,为行业带来新的发展机遇。
3.硬件选择
主控MCU:STM32F103C8T6
温度监测:DHT11
发热片:PTC加热器电发热片
显示屏幕:EPD墨水屏
其它:海凌科语音识别模块、电容式触摸按钮
4.功能实现
- 初始化各个外围设备,设计系统启动界面;
- 海凌科语音模块驱动,上电播报特定语音词条;
- 配置WIFI工作模式为STA,连接网络,实现网络校时;连接腾讯物联网平台,实现设备远程控制;
- 驱动DHT11温湿度模块,实时采集当前温湿度信息,并实时上报至微信小程序,设计温湿度显示界面;
- 驱动取暖器片,通过PWM调节取暖器档位。
- 通过语音控制取暖器开关和档位调节;实现语音完成界面切换;
- 通过按键调节取暖器档位和页面切换;
- 实习微信小程序控制取暖器开关和档位控制;
5.运行效果
系统上电,启动界面。
时间显示界面。
系统上电,进行网络校时,显示当前实时时间。
温湿度显示界面
进入系统后实时采集温湿度数据,可通过按键和语音实现温湿度界面显示。
基于物联网平台的智能取暖器设计硬件介绍
基于物联平台的智能取暖器设计功能展示
6.系统整体设计
本次系统总体包含软件和硬件两部分组成,其中硬件部分组成部分如下:
- 主控制器STM32F103C8T6,该芯片是ST公司开发的一款32位基于ARM Cortex-M3内核MCU,属于M3系列。这款单片机拥有64KB的闪存和20KB的SRAM,工作频率72MHz,具有丰富的外围接口设备。芯片的内部资源丰富(3个串口,4个定时器,2个12位ADC共10通道,1个CAN,2个I2C、I2S、SPI,1个2.0USB Slave)。能很好的满足本设计要求。STM32F103C8T6系统的总体结构分为Armsfirm和Matrixbus开发出来的Cortex M3、DMA、AHB、APB1、APB2和ST公司优化的外围设备。
- 海凌科语音识别模块,持多种语言:支持中文和英文识别,但每个模块只能烧录一种语言,不可中英文同时使用。用户可以根据应用使用场景自定义唤醒词、免唤醒应答词和命令词。HLK-V20支持最多5个唤醒词、10条免唤醒应答词(包含5个唤醒词)和150条语音指令。
- EPD墨水屏,墨水屏依靠反射外界环境光实现画面显示,无需背光,因此没有蓝光危害和频闪,对眼睛更加友好,长时间阅读也不易感到视觉疲劳。在静态画面显示时,墨水屏不耗电,因此具有极低的能耗特点,既环保又节能。提供高清晰度、高对比度的显示效果,文字清晰可见,视觉体验自然舒适。墨水屏薄膜本身是柔性的,可以贴覆在柔性的塑料基板上,构成可弯折的电子纸显示屏。
- PTC加热器电发热片PTC加热器利用PTC陶瓷材料的正温度系数特性,即电阻随温度升高而增加,通过电流激发PTC陶瓷发热元件产生热量。同时,内置的风扇将热空气吹出,形成热风,从而加速热量的传递和扩散,达到取暖的效果。
- DHT11温湿度模块,DHT11采用单总线数字信号传输和湿度电容传感技术。它由湿度感应器和温度感应器组成,可以测量环境中的温度和湿度。使用一个负温度系数(NTC)热敏电阻来测量温度。当温度上升时,其电阻值下降;当温度下降时,其电阻值上升。DHT11通过测量热敏电阻的电阻值变化来计算环境的温度。使用一种薄膜电容湿度传感材料来测量湿度。薄膜电容湿度传感材料的电容值随着湿度的增加而增加。DHT11通过测量湿度传感材料的电容值变化来计算环境的湿度。
- 电容式触摸按键,PT8042 是一款电容式触摸控制 ASIC,支持双通道触摸输入和双路同步开关输出,可引脚配置同步输出的有效电平。PT8042 实现触摸同步开关控制。适用于雾化器、车载用品、电子玩具、消费类电子产品等领域,具有低功耗、高抗干扰、宽工作电压范围、高穿透力的突出优势。
软件部分系统设计框图如下:
以STM32F103C8作为主控MCU。系统上电初始化各个外围接口设备,设计屏幕初化页面,将WIFI设置为STA模式,连接网络,获取网络时间进行时间校准。网络教室成功后开始连接腾讯物联网平台,实现设备远程控制,并实时上报当前环境的温湿度数据,在微信小程序腾讯连连上实时显示温度湿度数据,并可实现在小程序上控制取暖器加热档位。进入主程序后可通过语音控制取暖器开关和档位调节,或者通过红外遥控进行控制;可通过语音实现温湿度界面和时间界面切换,也可以通过电容式按键实现界面切换和取暖器档位调节。
7.软件设计
7.1 EPD墨水屏
墨水屏接口电路如下图所示,使用SPI驱动。
- SPI接口配置
SPI的时序要求包括时钟极性(CPOL)和时钟相位(CPHA)的设置。时钟极性决定了时钟信号在空闲状态时的电平(高电平或低电平),时钟相位决定了数据采样的时机(在时钟信号的第一个跳变沿或第二个跳变沿进行采样)。根据不同的设置,SPI有四种不同的操作模式(Mode 0、Mode 1、Mode 2、Mode 3)。本次采用SPI模式0实现对屏幕驱动。关于SPI详细介绍参考:STM32硬件SPI配置
/*
硬件接口:
PA4 --CS片选
PA5 --SCL时钟
PA7 --SDA主机输出
PB1-- RES复位脚
PA12-- DC数据命令选择
PB7--BUSY高电平为忙
*/
void EPD_GPIOInit(void)
{
RCC->APB2ENR|=0x3<<2;//开PA、PB时钟
GPIOA->CRL&=0x0F00FFFF;
GPIOA->CRL|=0xB0B30000;//复用推挽输出
GPIOB->CRL&=0x0FFFFF0F;
GPIOB->CRL|=0x80000030;//RES
GPIOA->CRH&=0xFFF0FFFF;
GPIOA->CRH|=0x00030000;//DC
//配置SPI1硬件
RCC->APB2ENR|=1<<12;//SPI1
RCC->APB2RSTR|=1<<12;//复位时钟
RCC->APB2RSTR&=~(1<<12);//取消复位
SPI1->CR1|=1<<14;//只发模式
SPI1->CR1|=1<<9;//软件从设备管理
SPI1->CR1|=1<<2;//配置为主设备
SPI1->CR2|=1<<2;//SS输出使能
SPI1->CR1|=1<<6;//开启SPI
}
- SPI底层读写一字节
/*SPI发送一字节函数*/
inline static void SPI1_SendDat(u8 dat)
{
while(SPI1->SR&1<<7){}//等待上一次数据发生完成
SPI1->DR=dat;
}
void EPD_WR_Bus(u8 dat)
{
SPI1_SendDat(dat);
}
- EPD屏幕写数据和写寄存
片选CS拉低选择设备,数据命令选择线DC拉低则发送命令,拉高则发送数据,每次发送一字节数据。代码实现如下所示。
void EPD_WR_REG(u8 reg)
{
EPD_CS=0;
EPD_DC=0;
EPD_WR_Bus(reg);
EPD_CS=1;
}
void EPD_WR_DATA8(u8 dat)
{
EPD_CS=0;
EPD_DC=1;
EPD_WR_Bus(dat);
EPD_DC=1;
EPD_CS=1;
}
- EPD初始化流程
/*******************************************************************
函数说明:初始化函数
入口参数:无
说明:调整E-Paper默认显示方向
*******************************************************************/
void EPD_Init(void)
{
EPD_GPIOInit();//引脚初始化
Delay_Ms(100);
EPD_RES=0;
Delay_Ms(10);
EPD_RES=1;
Delay_Ms(10);
EPD_READBUSY();
EPD_WR_REG(0x12); //软件复位
EPD_READBUSY(); //等待空闲
//清屏
EPD_Clear(WHITE);
EPD_Refresh(1);//刷白色
EPD_READBUSY();//等待清屏完成
// EPD_Refresh(0);//红色
// EPD_READBUSY();//等待清屏完成
}
- EPD画点函数
本次墨水屏尺寸为1.54寸,分辨率为152*152,颜色为黑白红三色。采用逐行扫描方式,每8个像素点为一个字节,因此定义一个二维数组缓冲区EPD_GRAM[152][19];,其中[152]表示152行,[19]表示每行的152像素,每8像素为1字节。
/*建立屏幕缓冲区*/
static u8 EPD_GRAM[152][19];//黑白色
void EPD_DrawPoint(u8 x,u8 y,u8 c)
{
u8 line_remain=x%8;
u8 line_size=x/8;//计算在哪个位置
if(BLACK == c)
EPD_GRAM[EPD_H-y-1][line_size]&=~(0x80>>line_remain);
else
EPD_GRAM[EPD_H-y-1][line_size]|=(0x80>>line_remain);
}
- EPD清屏和刷新函数
由于画点函数采用缓冲区方式写入,因此清屏函数需要对缓冲区进行处理。最后将缓冲区数据刷新到屏幕上。
/*清屏*/
void EPD_Clear(u8 color)
{
u8 i,j;
for(i=0;i<EPD_H;i++)
{
for(j=0;j<19;j++)
{
EPD_GRAM[i][j]=color;
}
}
}
/*
更新显示
刷新选择:stat=0 刷黑白
stat=1 刷红色
*/
void EPD_Refresh(u8 stat)
{
u8 i,j;
if(stat==1)
{
EPD_WR_REG(0x24);//写入黑白
for(i=0;i<EPD_H;i++)
{
for(j=0;j<19;j++)
{
EPD_WR_DATA8(EPD_GRAM[i][j]);
}
}
}
else
{
EPD_WR_REG(0x26);//写入红色
for(i=0;i<EPD_H;i++)
{
for(j=0;j<19;j++)
{
EPD_WR_DATA8(~EPD_GRAM[i][j]);
}
}
}
EPD_WR_REG(0x20);//更新显示
//EPD_READBUSY();
}
- 汉字显示和字符显示
字符显示和汉字显示采用逐行式,高位在前。汉字点阵数据保存在W25Q64中。
/*
显示字符
形参:x,y --显示位置
size --字体高度
cha --显示字符
color --显示,1表示显示,0表示不显示
*/
void EPD_ShowCha(u8 x,u8 y,u8 size,u8 cha,u8 color)
{
u16 csize=size/2*(size/8+(size%8?1:0));
u16 i,j;
u8 temp;
u8 y0=y;
for(i=0;i<csize;i++)
{
if(size==16)temp=asc2_1608[cha-' '][i];
else if(size==24)temp=asc2_2412[cha-' '][i];
else if(size==48)
{
if(cha == ' ')
{
temp=asc2_4824[13][i];
}
else temp=asc2_4824[cha-'.'][i];
}
for(j=0;j<8;j++)
{
if(temp&0x80)EPD_DrawPoint(x,y0,0);
else EPD_DrawPoint(x,y0,1);
y0++;
temp<<=1;
}
if((y0-y)>=size)
{
y0=y;
x++;
}
}
}
/*汉字显示*/
static void LCD_DisplayFont(u16 x,u16 y,u16 size,u8 *font,u8 color)
{
u8 *p=NULL;
u8 H,L;
u32 addr=0;//汉字偏移地址
u16 font_size=size*size/8;//汉字点阵大小(宽度保证为8的倍数)
H=*font;//汉字高字节
L=*(font+1);//汉字的低字节
if(L<0x7F)L-=0x40;
else L-=0x41;
H-=0x81;
addr=(190*H+L)*font_size;//汉字所在点阵中的偏移地址
p=malloc(font_size);
if(p==NULL)
{
//printf("申请空间失败\r\n");
return ;
}
if(size==16)W25Q64_ReadData(GBK_16_ADDR+addr,p,font_size);//从W25Q64中读取汉字点阵数据
else if(size==24)W25Q64_ReadData(GBK_24_ADDR+addr,p,font_size);//从W25Q64中读取汉字点阵数据
else return ;
u16 i,j;
u8 temp;
u8 x0=x;
for(i=0;i<font_size;i++)
{
temp=p[i];
for(j=0;j<8;j++)
{
if(temp&0x80)EPD_DrawPoint(x0,y,0);
else EPD_DrawPoint(x0,y,1);
x0++;
temp<<=1;
}
if(x0-x==size)
{
x0=x;
y++;
}
}
free(p);//释放空间
}
- 字符串显示
/*显示字符串*/
void EPD_ShowStr(u8 x,u8 y,u8 size,u8 *str,u8 color)
{
while(*str!='\0')
{
if(*str>0x80)
{
if(x+size/2>EPD_W)
{
x=0;
y+=EPD_H;
}
LCD_DisplayFont(x,y,size,str,color);
x+=size;
str+=2;
}
else if(*str>=' ' && *str <='~')
{
if(x+size/2>EPD_W)
{
x=0;
y+=EPD_H;
}
EPD_ShowCha(x,y,size,*str,color);
x+=size/2;
str++;
}
else str++;
}
}
7.2 取暖器驱动
风扇陶瓷PTC加热器利用PTC陶瓷材料的正温度系数特性,即电阻随温度升高而增加,通过电流激发PTC陶瓷发热元件产生热量。同时,内置的风扇将热空气吹出,形成热风,从而加速热量的传递和扩散,达到取暖的效果。其硬件接口电路如下:
取暖器采用双MOS管驱动,采用PWM调节取暖器档位。驱动引脚为PB0,工作电压为12V。
使用TIM3通道1输出PWM,设置工作频率20KHZ,通过条件CH1占空比实现取暖器档位调节。
/*
TIM3 PWM配置
配置通道:TIM3_CH3 --PB0
形参:psc--分频器
arr --重装载值
ccrx --占空比
*/
void TIM4CH3_PWM_Init(u16 psc,u16 arr,u16 ccrx)
{
//1.配置引脚
RCC->APB2ENR|=1<<3;
GPIOB->CRL&=0xFFFFFFF0;
GPIOB->CRL|=0x0000000B;
//2.配置基本功能
RCC->APB1ENR|=1<<1;//TIM3
RCC->APB1RSTR|=1<<1;
RCC->APB1RSTR&=~(1<<1);
TIM3->CNT=0;//计数器
TIM3->PSC=(psc-1);//分频器
TIM3->ARR=arr;//重装载值
TIM3->CR1|=1<<7;//自动重装载预装载使能
//3.配置PWM模式
TIM3->CCMR2&=~(0x3<<0);//CH3配置为输出模式
TIM3->CCMR2|=1<<2;//输出比较快速使能
TIM3->CCMR2|=1<<3;//输出比较预装载
TIM3->CCMR2|=0x6<<4;//配置为PWM模式1,CNT<CCR为有效电平
TIM3->CCER&=~(1<<9);//高电平有效
TIM3->CCR3=ccrx;//占空比
TIM3->CCER|=1<<8;//CH3通道使能
TIM3->CR1|=1<<0;//使能TIM4
}
8.腾讯云连接
腾讯物联网平台通过提供安全、稳定、高效的连接服务,帮助开发者低成本、快速地实现“设备-设备”、“设备-用户应用”、“设备-云服务”之间可靠、高并发的数据通信。平台支持各类物联网设备接入,提供设备管理、数据通信、数据处理等功能,助力企业构建智能物联网应用。
腾讯物联网平台广泛应用于车联网、智慧能源、智能家居、工业设备、智慧交通/城市等领域。例如,在车联网领域,可以采集分析司机的驾驶习惯,实时监测车辆状态,为司机提供驾驶建议;在智能家居领域,可以实现设备的智能化控制,提升用户体验。
1. 搜索物联网平台,登录物联网平台。
1. 进入物联网控制台。
2. 创建项目
3. 创建产品
4. 设置物模型
5. 配置APP
关于腾讯云详细配置请参考文档:腾讯云配置
9.系统主函数
#include "stm32f10x.h"
#include "beep.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart1.h"
#include "infrared.h"
#include "timer.h"
#include "dht11.h"
#include "w25q64.h"
#include <stdio.h>
#include <string.h>
#include "EPD.h"
#include "rtc.h"
#include "esp8266.h"
#include "aliyun_mqtt.h"
#include <stdlib.h>
u8 rtc_time_flag=0;
u8 RTCtime_Update(u8* buff);//时间校准
u8 ESP8266_StringAnalysis(const u8*str,const char*str_flag,char *data);//JSON数据提取
#define DeviceName "qnq_ctl"//设备名
#define ProductID "KXGLK7ERVC"//产品ID
#define DeviceSceret "d1azAlVokj/K/BBf3E9ZfQ=="//设备秘钥
#define WIFI_NAME "rfid_wifi"//WIFI名
#define WIFI_PASSWORD "12345678"//wifi密码
//服务器IP:{PRODUCT_ID}.iotcloud.tencentdevices.com ---PRODUCT_ID对应产品ID
#define SERVER_IP "KXGLK7ERVC.iotcloud.tencentdevices.com"//服务器IP
#define SERVER_PORT 1883 //端口号
//客户端ID:{产品ID}{设备名}
#define ClientID "KXGLK7ERVCqnq_ctl"
//用户名和密码可使用密码生成工具完成
#define Username "KXGLK7ERVCqnq_ctl;12010126;71e59;1739808000"
#define Password "546cda45b6bb1d9f05c2f08d8fe4b7ea08e446fb4c27ef60ea946a821cca1e21;hmacsha256"//密文
//订阅主题:$thing/down/property/{ProductID}/{DeviceName} ---{ProductID}产品ID,{DeviceName}设备名
#define SET_TOPIC "$thing/down/property/KXGLK7ERVC/qnq_ctl"//订阅
//发布主题:$thing/up/property/{ProductID}/{DeviceName}
#define POST_TOPIC "$thing/up/property/KXGLK7ERVC/qnq_ctl"//发布
char mqtt_tx_buffer[512];
int main()
{
Beep_Init();//蜂鸣器器初始化
LED_Init();//LED
Key_Init();
USARTx_Init(USART1,115200);
USARTx_Init(USART2,115200);
USARTx_Init(USART3,115200);
EPD_Init();//墨水屏初始化
InfraredDecode_Init();
u16 ccr=0;
TIM4CH3_PWM_Init(1,3600,0);
if(DHT11_Init())
{
printf("DHT11初始化失败\r\n");
}
W25Q64_Init();
printf("ID=%#x\n",W25Q64_ReadID());
EPD_ShowStr(36,10,16,"智能取暖器",0);//字符显示
EPD_ShowImage(46,46,60,60,image_60_60);//图片显示
EPD_ShowStr(28,120,16,"北京万邦易嵌",0);//字符显示
EPD_Refresh(0);//写红色
RTC_Init();
u8 key_val=0;
u16 time=0;
u8 temp[2],humidity[2];
u8 buffer[200];
u8 key_cnt=0;
u32 time_temp=100000;
u16 heart_time=0;
u16 mqtt_Publishtime=10000;
/*
连接心知天气服务器
*/
printf("连接nowapi服务器。。。\r\n");
while(1)
{
u8 ret=Esp8266_STA_TCPclinet_Init((u8*)WIFI_NAME,(u8*)WIFI_PASSWORD,"api.k780.com",80);
printf("ret=%d\r\n",ret);
if(ret==0)break;
Delay_Ms(1000);
}
printf("服务器连接成功\r\n");
int cnt=0;
int stat=0;
if(cnt<5)
{
USARTx_SendStr(USART3,(uint8_t *)"GET http://api.k780.com/?app=life.time&appkey=25273&sign=eae95a712a66e7a97dfd39534e24ffb1&format=json\n");
cnt=0;
stat=0;
while(1)
{
if(usart3_flag && usart3_cnt)
{
usart3_flag=0;
usart3_rx_buf[usart3_cnt]='\0';
printf("usart3:%s,%d\r\n",usart3_rx_buf,usart3_cnt);
RTCtime_Update(usart3_rx_buf);
break;
}
cnt++;
Delay_Ms(1);
if(cnt>=500)
{
stat++;
cnt=0;
USARTx_SendStr(USART3,(uint8_t *)"GET http://api.k780.com/?app=life.time&appkey=25273&sign=eae95a712a66e7a97dfd39534e24ffb1&format=json\n");
}
if(stat>=2)
{
cnt=2;
break;
}
}
}
//连接阿里云
printf("连接腾讯云......\r\n");
while(1)
{
stat=Esp8266_STA_TCPclinet_Init((u8 *)WIFI_NAME,(u8 *)WIFI_PASSWORD,(u8 *)SERVER_IP,SERVER_PORT);
if(stat==0)break;
Delay_Ms(500);
printf("stat=%d\r\n",stat);
}
printf("服务器连接成功\r\n");
while(1)
{
MQTT_Init();
stat=MQTT_Connect(ClientID,Username,Password);
if(stat==0)break;
Delay_Ms(500);
printf("正在连接....\r\n");
}
printf("连接成功\r\n");
stat=MQTT_SubscribeTopic(SET_TOPIC,0,1);
if(stat)printf("订阅失败\r\n");
else printf("订阅成功\r\n");
u8 idex=0;
u16 i=0;
key_cnt=1;//配置成功,则直接显示时间
EPD_Clear(WHITE);
rtc_time_flag=1;
while(1)
{
key_val=Key_GetValue(0);
if(key_val==1)
{
BEEP=1;
Delay_Ms(50);
BEEP=0;
ccr+=500;
if(ccr>3600)ccr=0;
TIM3->CCR3=ccr;//占空比
printf("ccr=%d\n",ccr);
}
else if(key_val==2)
{
BEEP=1;
Delay_Ms(50);
BEEP=0;
key_cnt++;
if(key_cnt>2)key_cnt=1;
EPD_Clear(WHITE);
time_temp=100000;
rtc_time_flag=0;
}
if(decode_flag)
{
BEEP=1;
Delay_Ms(50);
BEEP=0;
decode_flag=0;
printf("解码成功:%#x %#x %#x %#x\r\n",infreared_decode[0],infreared_decode[1],infreared_decode[2],infreared_decode[3]);
if(infreared_decode[2]==0x45)//打开取暖器
{
if(TIM3->CCR3!=0)
{
TIM3->CCR3=0;
}
}
else if(infreared_decode[2]==0x43)//增大档位
{
ccr+=500;
if(ccr>3600)ccr=3600;
TIM3->CCR3=ccr;
}
else if(infreared_decode[2]==0x40)//减小档位
{
if(ccr>1000)ccr-=500;
TIM3->CCR3=ccr;
}
}
if(usart1_flag)
{
usart1_buffer[usart1_cnt]='\0';//字符串结束标志符
printf("rx1=%s,%d\r\n",usart1_buffer,usart1_cnt);
if(strcmp((char *)usart1_buffer,"BEEP_ON")==0)
{
BEEP=1;//开蜂鸣器
}
else if(strcmp((char *)usart1_buffer,"BEEP_OFF")==0)
{
BEEP=0;//关蜂鸣器
}
usart1_flag=0;
usart1_cnt=0;
}
if(usart2_flag)
{
if(usart2_cnt==3)
{
if(usart2_buffer[0]==0x77 && usart2_buffer[2]==0x0a)
{
switch(usart2_buffer[1])
{
case 1://开灯
LED=0;
break;
case 7://关灯
LED=1;
break;
case 2://打开取暖器
TIM3->CCR3=1000;
break;
case 8://关闭取暖器
TIM3->CCR3=0;
break;
case 9://取暖器设置为中档
TIM3->CCR3=2000;
break;
case 0xa://取暖器设置为中档
TIM3->CCR3=3600;
break;
case 5://显示时间
key_cnt=1;//配置成功,则直接显示时间
EPD_Clear(WHITE);
rtc_time_flag=1;
break;
case 6://显示温湿度
key_cnt=2;//配置成功,则直接显示时间
rtc_time_flag=0;
time_temp=100000;
EPD_Clear(WHITE);
break;
}
}
}
// printf("rx2=%s,%d\n",usart2_buffer,usart2_cnt);
usart2_flag=0;
usart2_cnt=0;
}
if(key_cnt==1)//显示时间
{
rtc_time_flag=1;
}
else if(key_cnt==2)//显示温湿度
{
if(time_temp>=100000)//100秒显示一次
{
EPD_ShowStr(36,10,16,"环境温湿度",1);//字符显示
snprintf((char *)buffer,sizeof(buffer),"温度:%d.%d ℃",temp[0],temp[1]);
EPD_ShowStr(20,60,16,buffer,1);//字符显示
snprintf((char *)buffer,sizeof(buffer),"湿度:%d %%",humidity[0]);
EPD_ShowStr(20,80,16,buffer,1);//字符显示
EPD_Refresh(0);
time_temp=0;
}
}
if(usart3_flag)
{
usart3_rx_buf[usart3_cnt]='\0';//字符串结束标志符
idex=0;
for(i=0;i<usart3_cnt;i++)
{
//printf("%c",usart3_rx_buff[i]);
if(usart3_rx_buf[i]!='\0') buffer[idex++]=usart3_rx_buf[i];
}
buffer[idex]='\0';
/*
rx3=0?'$thing/down/property/KXGLK7ERVC/qnq_ctl{"method":"control","clientToken":"v2179483179GEMsK::B%TFbiGWX","params":{"qnq_ctl":3}}
*/
//printf("rx3=%s\n",buffer);
char *p=NULL;
p=strstr((char *)buffer,"{\"qnq_ctl\":");
if(p)
{
p+=strlen("{\"qnq_ctl\":");
printf("*p=%c\n",*p);
if(*p=='0')//关闭
{
TIM3->CCR3=0;
}
else if(*p=='1')//低
{
TIM3->CCR3=1000;
}
else if(*p=='2')//中
{
TIM3->CCR3=2000;
}
else if(*p=='3')//高
{
TIM3->CCR3=3200;
}
}
usart3_flag=0;
usart3_cnt=0;
}
if(key_cnt==2)time_temp++;
time++;
heart_time++;
mqtt_Publishtime++;
Delay_Ms(1);
if(time>=1000)
{
time=0;
DHT11_Read_Data(temp,humidity);//读取温湿度
printf("温度:%d.%d℃ 湿度:%d %%\r\n",temp[0],temp[1],humidity[0]);
}
if(heart_time>=20000)//20s上报一次心跳包
{
heart_time=0;
MQTT_SentHeart();//发送心跳包
}
if(mqtt_Publishtime>=10000)
{
mqtt_Publishtime=0;
sprintf(mqtt_tx_buffer,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"current_temp\":%d.%d,\"current_humidity\":%d}}",temp[0],temp[1],humidity[0]);//温度
//sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"LED1\":1,\"temp\":%.2f,\"L\":356}}",temp);//温度
MQTT_PublishData(POST_TOPIC,mqtt_tx_buffer,0);
}
}
}
/*
字符数据解析
形参:str --要解析的原始内容
str_flag --解析的标志符
data --保存解析的内容
返回值:成功返回0,失败返回其它值
ESP8266_StringAnalysis(str,"\"timestamp_ms\"",data);
*/
u8 ESP8266_StringAnalysis(const u8*str,const char*str_flag,char *data)
{
if(str==NULL || str_flag==NULL || data==NULL)return 1;
char *p=strstr((char *)str,str_flag);
if(p==NULL)return 2;//查找标志符失败
p+=strlen(str_flag);
p+=2;//将指针指向要获取的内容首位置
char *temp=data;
while(*p!='"' && *p!='\0' && *p!='}')
{
*temp++=*p++;
}
*temp='\0';
return 0;//解析成功
}
u8 RTCtime_Update(u8* buff)
{
//usart3:{"success":"1","result":{"timestamp":"1683613881","datetime_1":"2023-05-09 14:31:21","datetime_2":"2023骞5鏈9鏃14鏃1鍒1绉,"week_1":"2","week_2":"鏄熸湡浜,"week_3":"鍛ㄤ簩","week_4":"Tuesday"}},206
u8 data[100];
if(ESP8266_StringAnalysis(buff,(const char*)"\"timestamp\"",(char *)data))return 1;
printf("data=%s\r\n",data);
u32 time_sec=atoi((char *)data)+8*60*60;
/*3.配置RTC寄存器*/
RTC->CRH&=~(1<<0);//关闭秒中断
u8 stat=0;
while(!(RTC->CRL&1<<5))//等待上一次写操作完成
{
stat++;
Delay_Ms(1);
if(stat>=255)break;
}
if(stat>=255)
{
printf("RTC初始化失败,无法进入配置模式\r\n");
}
RTC->CRL|=1<<4;//进入配置模式
//写入秒时间
RTC->CNTH=(time_sec>>16);//写入高16位
RTC->CNTL=time_sec;//写入低16位
//退出配置模式
RTC->CRL&=~(1<<4);//清除配置模式
stat=0;
while(!(RTC->CRL&1<<5))//等待写操作完成
{
stat++;
Delay_Ms(1);
if(stat>=255)
{
printf("RTC初始化失败,退出配置模式失败\r\n");
}
}
RTC->CRH|=1<<0;//开启秒中断
STM32_SetNVICPriority(3,3,RTC_IRQn);//设置优先级
usart3_cnt=0;
usart3_flag=0;
printf("网络校时完成\r\n");
return 0;
}
10.腾讯云微信小程序运行效果
单片机实时采集温湿度数据并上报到微信小程序,在微信小程序上实时显示当前的温湿度数据,并可通过微信小程序控制取暖器开关和档位调节。