厨浴 发表于 2025-6-4 19:04:24

基于STM32(Freertos)&ESP01S的红外空调网络控制器 -ESP01S 软件部分

1.概述
本文基于ESP01S 硬件,Arduino 开发环境,Blinker库及手机控制APP,完成与STM32的通信,为手机APP提供按键文字数据接口。
2.ESO01S 驱动代码
#define BLINKER_WIFI
#include <Blinker.h>
#include <NTPClient.h>//用于获取网络时间
#include <WiFiUdp.h>
// 定义时区(东八区)
#define TIME_ZONE 8 * 3600
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", TIME_ZONE);
char auth[] = "1d7475c3d0df";
char ssid[] = "ziroom605";
char pswd[] = "4001001111";

#define Temp_add "temp-add"
#define temp_sub "temp-sub"
#define IR_mode "IR-mode"
#define sysdebug "sysdebug"
#define Humi_mode "Humi-mode"
#define SYS_ONOFF "onoff"

BlinkerButton Button1(Temp_add);/*定义按键类型的一个按键对象Button1 初始化BUTTON_1*/
BlinkerButton Button2(temp_sub);/*定义按键类型的一个按键对象Button2 初始化BUTTON_2*/
BlinkerButton Button3(IR_mode);/*定义按键类型的一个按键对象Button3 初始化BUTTON_3*/
BlinkerButton Button4(sysdebug);/*定义按键类型的一个按键对象Button4 初始化BUTTON_4*/
BlinkerButton Button5(Humi_mode);/*定义按键类型的一个按键对象Button5 初始化BUTTON_5*/
BlinkerButton Button6(SYS_ONOFF);/*定义按键类型的一个按键对象Button6 初始化BUTTON_6*/
BlinkerNumber Number1("num-temp"); /*空调温度显示数字初始化*/
BlinkerNumber Number2("num-irmode");/*空调模式显示数字初始化*/
BlinkerNumber Number3("num-Humimode");/*加湿器模式显示数字初始化*/
BlinkerNumber Number4("s-temp"); /*传感器温度数字初始化*/
BlinkerNumber Number5("s-humi");/*传感器湿度数字初始化*/
BlinkerText   IRstate("IR-state"); /*空调模式字符接口初始化*/
BlinkerText   Humistate("Humi-state");/*加湿器模式字符接口初始化*/
//用以接收数据的结构体定义
#pragma pack(push, 1) // 确保结构体紧凑排列
typedef struct {
    uint8_t start_flag;// 起始字节 0xB3
    uint8_t temp_IR;       // 第二个字节 IR
    uint8_t mode_IR;       // 第三个字节 Humi
    uint8_t mode_Humi;       // 第4个字节 Humi
    float   data1;       // 5-8字节 float temp
    float   data2;       // 9-12字节 float humi
} SerialData;
#pragma pack(pop)
//用以发送数据结构体
#pragma pack(push, 1)
typedef struct {
    uint8_t start_flag;// 固定0x47
    uint8_t hour;      // 网络时间小时(24制)
    uint8_t minute;      // 分钟
    uint8_t second;      // 秒
    uint8_t cmd0;      // 命令字节温度
    uint8_t cmd1;      // 命令字节模式
    uint8_t cmd2;      // 加湿器模式
    uint8_t cmd3;      // 总开关标志 0 为关 高4为F时自动
} SendPacket;
#pragma pack(pop)
//接收数据的结构体变量初始化
SerialData sensorData={0xB3,26,0,2,0,0};
//发送数据的结构体变量初始化
SendPacket SendData={0x47,0,0,0,26,0,2,0x00};//初始化发送数据,26度,自动模式,关闭加湿器
//定义接收数据的函数状态机
enum ParserState { WAIT_HEADER, PARSE_DATA };
//初始化接收数据的状态机
ParserState state = WAIT_HEADER;
//定义缓冲区以接收数据
uint8_t buffer;
uint8_t dataIndex = 0;
uint8_t i=0;
static uint8_t curtemp=sensorData.temp_IR;//初始化控制状态
static uint8_t curHumimode=sensorData.mode_Humi;//初始化控制状态
/*
功能:用以在手机APP上显示空调状态字符
参数:模式,从0-4
*/
void IRmode_show(uint8_t text_num)
{
switch(text_num)
{
    case 0: IRstate.print("自动");break;
    case 1: IRstate.print("制冷");break;
    case 2: IRstate.print("除湿");break;
    case 3: IRstate.print("加热");break;
    case 4: IRstate.print("送风");break;
    default:IRstate.print("Error");break;
}
}
/*
功能:用以在手机APP上显示加湿器状态字符
参数:模式,从0-4
*/
void Humimode_show(uint8_t text_num)
{
switch(text_num)
{
    case 0: Humistate.print("OFF");break;
    case 1: Humistate.print("Low");break;
    case 2: Humistate.print("High");break;
    default:Humistate.print("Error");break;
}
}
/*
功能:空调温度加
参数:无
*/
void button1_callback(const String & state)//控制加空调温度,低5位温度
{
    if(SendData.cmd3==0x00)
    {
    if (state == BLINKER_CMD_BUTTON_TAP)
    {
      BLINKER_LOG("CurIRTemp %d\n",curtemp);
      Button1.icon("fas fa-plus");
      Button1.color("#FFB71D");
      Button1.text("ADD TEMP");
      if(curtemp<=16||curtemp>=31)
      {curtemp=26;}
      SendData.cmd0=++curtemp;
      Number1.print(curtemp); // 直接支持数值类型
      Number1.unit("°C");
      sendTimeCommand();   
    }
    }
}
/*
功能:空调温度减
参数:无
*/
void button2_callback(const String & state)//控制减空调温度,低5位温度
{
      if(SendData.cmd3==0x00)
    {
    if (state == BLINKER_CMD_BUTTON_TAP)
    {
      BLINKER_LOG("CurIRTemp %d\n",curtemp);
      Button2.icon("fas fa-window-minimize");
      Button2.color("#4CC7FF");
      Button2.text("SUB TEMP");
      if(curtemp<=16||curtemp>=31)
      {curtemp=26;}
      SendData.cmd0=--curtemp;
      Number1.print(curtemp); // 直接支持数值类型
      Number1.unit("°C");
      sendTimeCommand();   
    }
    }
}
/*
功能:空调模式切换
参数:无
*/
void button3_callback(const String & state)
{
    uint8_t static curtempmode=sensorData.mode_IR;
    if(SendData.cmd3==0x00)
    {
    if (state == BLINKER_CMD_BUTTON_TAP)
    {
      BLINKER_LOG("CurIRmode %d\n",curtempmode);
      Button3.icon("fas fa-spinner");
      Button3.color("#B0DC58");
      Button3.text("IR Mode");
      curtempmode=curtempmode+1;
      if(curtempmode==5)
      curtempmode=0;
      IRmode_show(curtempmode);
      SendData.cmd1=curtempmode;
      Number2.print(curtempmode);
      sendTimeCommand();   
    }
    }
}
/*
功能:debug 按键,实际不使用
参数:无
*/
void button4_callback(const String & state)//DEBUG KEY
{
    if (state == BLINKER_CMD_BUTTON_TAP)
    {
      BLINKER_LOG("i=",i);
      BLINKER_LOG("value=",buffer);
      //BLINKER_LOG("TEMP=",sensorData.data1);
      //BLINKER_LOG("Humi=",sensorData.data2);
      Button4.icon("fa fa-minus");
      Button4.color("#05FFF");
      Button4.text("debug++");
      i++;
      if(i==12)
      {
      BLINKER_LOG("TEMP=",sensorData.data1);
      BLINKER_LOG("Humi=",sensorData.data2);
      i=0;
      }
    }
}
/*
功能:加湿器模式切换
参数:无
*/
void button5_callback(const String & state)
{   
      if(SendData.cmd3==0x00)
    {
    if (state == BLINKER_CMD_BUTTON_TAP)
    {
      BLINKER_LOG("CurHumimode %d\n",curHumimode);
      Button5.icon("fab fa-gg-circle");
      Button5.color("#B0DC58");
      Button5.text("HUMI Mode");
      curHumimode++;
      if(curHumimode==3)
      curHumimode=0;
      Humimode_show(curHumimode);
      SendData.cmd2=curHumimode;
      Number3.print(curHumimode);
      sendTimeCommand();   
    }
    }
}
/*
功能:控制器总开关
参数:无
*/
void button6_callback(const String & state)
{   
      BLINKER_LOG("ON_OFF_Sta\n",state);
      if (state=="on")
      {
      Button6.print("on");
      Button6.icon("fas fa-power-on");
      Button6.color("#98F5FF");
      SendData.cmd3=0x00;
      }
      else if(state=="off")
      {
      Button6.print("off");
      Button6.icon("fas fa-power-off");
      Button6.color("#F5F5F5");
      SendData.cmd3=0x0F;
      }
      sendTimeCommand();   
}
// 发送数据函数
void sendTimeCommand(void)
{
    SendData.start_flag = 0x47;
    SendData.hour = timeClient.getHours();
    SendData.minute =timeClient.getMinutes();
    SendData.second =timeClient.getSeconds();
    SendData.cmd0 = SendData.cmd0;//温度17-31
    SendData.cmd1 = SendData.cmd1;//模式0-4 自动,制冷,除湿,加热,送风
    SendData.cmd2 = SendData.cmd2;//加湿器模式 0-2关 低 高
    SendData.cmd3 = SendData.cmd3;//总开关
    // 通过串口发送二进制数据
    Serial.write((uint8_t*)&SendData, sizeof(SendPacket));
}
/*
功能:解析4字节的float数据
参数:无
*/
float parse_float(const uint8_t* bytes)
{
    union {
      float value;
      uint8_t bytes;
    } converter;

    if (1)
    {
      // 接收端为小端,直接复制字节
      memcpy(converter.bytes, bytes, 4);
    } else {
      // 接收端为大端,反转字节顺序
      converter.bytes = bytes;
      converter.bytes = bytes;
      converter.bytes = bytes;
      converter.bytes = bytes;
    }
    return converter.value;
}
/*
功能:处理串口接收程序接收到的数据,进行校验
参数:无
*/
void processData(void)
{
uint32_t temp0=0;
uint32_t humi0=0;
sensorData.start_flag=buffer;
sensorData.temp_IR=buffer;
sensorData.mode_IR=buffer;
sensorData.mode_Humi=buffer;
// 解析第一个float(buffer到buffer)
sensorData.data1=parse_float(&buffer);
sensorData.data2=parse_float(&buffer);
}
/*
功能:串口数据接收程序
参数:无
*/
void Uart_Data_Recesive(void)
{
while (Serial.available() > 0) {
      uint8_t incomingByte = Serial.read();
      
      switch (state)
      {
            case WAIT_HEADER:
                if (incomingByte == 0xB3)
                {
                  buffer = incomingByte;
                  dataIndex = 1;
                  state = PARSE_DATA;
                }
                break;
               
            case PARSE_DATA:
                if (dataIndex < 12)
                {
                  buffer = incomingByte;
                  dataIndex++;
                  
                  if (dataIndex == 12) {
                        // 完整数据包接收完成
                        memcpy(&sensorData, buffer, sizeof(SerialData));
                        
                        // 验证起始字节
                        if (sensorData.start_flag == 0xB3)
                        {
                            // 数据解析成功,这里添加处理逻辑
                            processData();
                        }
                        
                        // 重置状态机
                        state = WAIT_HEADER;
                        dataIndex = 0;
                  }
                }
                break;
      }
    }
}
/*
功能:ESP01S 初始化
参数:无
*/
void setup()
{
    Serial.begin(9600);
    Serial1.begin(9600);
    Blinker.begin(auth, ssid, pswd);
    timeClient.begin();// 初始化NTP客户端
    timeClient.update(); // 首次时间同步
    BLINKER_DEBUG.stream(Serial1);
    Blinker.println("System initialized");
    Number1.unit("°C"); // 设置单位

    Button1.attach(button1_callback);
    Button2.attach(button2_callback);
    Button3.attach(button3_callback);
    Button4.attach(button4_callback);
    Button5.attach(button5_callback);
    Button6.attach(button6_callback);
}
/*
功能:ESP01S 循环执行函数
参数:无
*/
void loop()
{
    timeClient.update();
    Uart_Data_Recesive();
    Blinker.run(); // 保持Blinker连接
}3.手机APP界面

项目软硬件源文件:
通过网盘分享的文件:基于STM32(Freertos)&ESP01S的红外空调网络控制器
链接: https://pan.baidu.com/s/1v1wjqlfK64kvp4HNg9b2ew 提取码: vzx5
本文及项目文件仅用于学习交流,严禁用于商业用途,转载引用请注明出处。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 基于STM32(Freertos)&ESP01S的红外空调网络控制器 -ESP01S 软件部分