草庐IT

智能家居—基于STM32的温湿度控制系统(WIFI模块)

Autism_Huang 2023-10-30 原文

基于App控制的STM32温湿度控制系统(WIFI模块)

ESP8266WIFI模块

在这个项目中我选用的正点原子的WIFI模块(ATK-ESP8266),这个模块采用串口(LVTTL)与MCU(或其他串口设备)通信,内置了TCP/IP的协议栈,可以实现串口与WIFI直接的转换,通过ATK-SEP8266模块,传统的串口设备只是需要简单的串口配置,即可通过网络(WIFI)传输自己的数据。

模块使用说明

其实挺简单的,拿出你的模块看,VCC就接3.3V或者5V,GND就接GND啦,然后WIFI模块与串口设备TX接RX,RX接TX,RST的复位是低电平有效。IO-0适用于固件烧写的,低电平就是烧写模式,高电平时运行模式(默认态)

RST和IO-0一般是不用接的(一般使用只用接前4个就好了)!

常用AT指令

指令描述
AT+CWMODE选择 WIFI 应用模式
AT+CWJAP加入 AP
AT+CWLAP列出当前可用 AP
AT+CWQAP退出与 AP 的连接
AT+CWSAP设置 AP 模式下的参数
AT+CWLIF查看已接入设备的 IP
AT+CWDHCP设置 DHCP 开关
AT+CWAUTOCONN设置 STA 开机自动连接到 wifi
AT+CIPSTAMAC设置 STA 的 MAC 地址
AT+CIPAPMAC设置 AP 的 MAC 地址
AT+CIPSTA设置 STA 的 IP 地址
AT+CIPAP设置 AP 的 IP 地址
AT+CWSTARTSMART启动智能连接
AT+CWSTOPSMART停止智能连接
AT+WPS设置 WPS 功能
AT+MDNS设置 MDNS 功能
AT+CWHOSTNAME设置 ATK-ESP-01 Station 的主机名字

具体AT指令的使用还是得去看下模块的用户手册,这里就不做过多的赘述了。

DHT11温湿度传感器

简介

参数Value
工作电压3.3V~5V
湿度测量范围20%~95%
温度测量范围0°~50°

传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。(如下图所示)

模块数据的发送流程


首先主机发送开始信号,即:拉低数据线,保持t1(至少18ms)时间,然后拉高数据线t2(20-40us)时间,然后读取DHT11的响应,正常的话,DHT11会拉低数据线,保持t3(40-50us)时间,作为响应信号,然后DHT11拉高数据线,保持t4(40-50us)时间后,开始输出数据。

代码实现

/*更改IO模式的封装函数*/
void DHT11_PIN_MODE(uint8_t mode)                        
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(mode==Intput)
  {
		GPIO_InitStruct.Pin = DHT11_DATA_Pin;
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(DHT11_DATA_GPIO_Port, &GPIO_InitStruct);
		
   }else
   {
    
		GPIO_InitStruct.Pin = DHT11_DATA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_DATA_GPIO_Port, &GPIO_InitStruct);
		 
    }
}

static uint8_t DHT11_ReadByte ( void )
{
  DHT11_PIN_MODE(Intput);
  uint8_t i, temp=0;
  for(i=0;i<8;i++)   
	{         
		/*每bit以50us低电平标置开始,轮询直到从机发出的50us低电平结束*/  
    while(Read_DHT11_DATA()==GPIO_PIN_RESET);
    /*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
    *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时                 */
    HAL_Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可                     
    if(Read_DHT11_DATA()==GPIO_PIN_SET)/* x us后仍为高电平表示数据“1” */
    {
     /* 等待数据1的高电平结束 */
			while(Read_DHT11_DATA()==GPIO_PIN_SET){}
      temp|=(uint8_t)(0x01<<(7-i));  //把第7-i位置1,MSB先行
     }else         // x us后为低电平表示数据“0”
     {                           
      temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
      }
   }
      return temp;
}

uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
	if(Frame_Flag.dht11flag++ >= 1000 )
		Frame_Flag.dht11flag = 0;	
  	uint8_t temp;
  	uint16_t humi_temp;
  	/*输出模式*/
  	DHT11_PIN_MODE(Output);
  	/*主机拉低*/
  	DHT11_DATA_RESET();
  	/*延时18ms*/
  	Delay_ms(18);
  	/*总线拉高 主机延时30us*/
  	DHT11_DATA_SET();
  	HAL_Delay_us(30);   //延时30us
  	/*主机设为输入 判断从机响应信号*/
  	DHT11_PIN_MODE(Intput);
  	/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   
  	if(Read_DHT11_DATA()==GPIO_PIN_RESET)     
  	{
		/*轮询直到从机发出 的80us 低电平 响应信号结束*/  
		while(Read_DHT11_DATA()==GPIO_PIN_RESET);
		/*轮询直到从机发出的 80us 高电平 标置信号结束*/
		while(Read_DHT11_DATA()==GPIO_PIN_SET);
		/*开始接收数据*/   
		DHT11_Data->humi_high8Bit= DHT11_ReadByte();
		DHT11_Data->humi_low8bit = DHT11_ReadByte();
		DHT11_Data->temp_high8bit= DHT11_ReadByte();
		DHT11_Data->temp_low8bit = DHT11_ReadByte();
		DHT11_Data->check_sum    = DHT11_ReadByte();
		/*读取结束,引脚改为输出模式*/
		DHT11_PIN_MODE(Output);
		/*主机拉高*/
		DHT11_DATA_SET();
		/* 对数据进行处理 */                
		humi_temp=DHT11_Data->humi_high8Bit*100+DHT11_Data->humi_low8bit;
		DHT11_Data->humidity =(float)humi_temp/100;
		humi_temp=DHT11_Data->temp_high8bit*100+DHT11_Data->temp_low8bit;
		DHT11_Data->temperature=(float)humi_temp/100;   
		/*检查读取的数据是否正确*/
		temp = DHT11_Data->humi_high8Bit + DHT11_Data->humi_low8bit +
		DHT11_Data->temp_high8bit+ DHT11_Data->temp_low8bit;
		if(DHT11_Data->check_sum==temp)
		{
			return SUCCESS;
		}else
		{
			return ERROR;
		}
	}else
	{
		return ERROR;
	}
}

这里需要说明的是,如果用的是FreeRTOS的话就需要开多一个定时器用来进行μs级别的计时,同时不能放在任务中跑,这样任务很容易阻塞导致系统的暂停运行。但是实际上测量温度可以通过开关中断的方式进行读取,将读取速率放在一个任务里面也可以,主要是检测的时候用的us级的上拉下拉要注意下。

μs级的延时配置

这里选用的TIM6用来做计时器

HAL库配置

由于TIM6是挂载在APB1上的,所以要APB1的值

因为我APB1Timer clocks是90MHz
所以89+1/90=1MHz,也就是1μs计数一次。

代码实现

void HAL_Delay_us(uint16_t us)
{
//	uint16_t startCount = __HAL_TIM_GET_COUNTER(&htim6);
//	
//	while((__HAL_TIM_GET_COUNTER(&htim6) - startCount) <= us);
	uint16_t differ = 0xffff-us-5;
	HAL_TIM_Base_Start(&htim6);
	__HAL_TIM_SetCounter(&htim6,differ);
	
	while(differ < 0xffff-5)
	{
		differ = __HAL_TIM_GetCounter(&htim6);
	}
	HAL_TIM_Base_Stop(&htim6);
	
}

项目总框架

讲完这个项目所用的两个外设了,现在来说一下整个项目的总体设计思路。

总框架图


如上图所示,首先我们利用AT指令初始化WIFI模块,然后WIFI模块等待APP建立TCP连接。建立完连接之后,便利用TCP间客户机与服务机之间的通信进行数据的传输。DHT11模块接收到温湿度信号后发送脉冲给单片机的IO口,IO口读取电平后将其转化成数字,再由单片机的串口发送到WIFI模块回显在APP上面。

单片机控制流程图


单片机首先初始化板上的资源(IO口、串口、WIFI模块),然后开启了串口中断,DMA传输,以及创建控制任务。开启了串口中断后就开始接收数据。如果没有接收到数据,则返回重新接收,如果有,就把数据存进缓冲区,存进缓冲区之后,程序会对缓冲区的数据进行解包处理后存进结构体对应的成员变量内,然后通过读取温度与湿度的成员变量,通过串口发送给WIFI模块,APP对数据进行回显。

APP控制流程图


在打开APP的时候,在界面中输入服务器IP地址和端口号,点击CONNECT按钮就会跟服务器建立TCP连接。然后在控制界面有开灯、关灯、播放音乐的按钮,点击可以触发对应的事件然后向WIFI模块发送信息。WIFI模块收到信息之后通过AT指令会发送数据给APP,APP处理之后可以回显到界面上。

项目代码实现

WIFI模块

首先需要利用单片机给WIFI模块通过串口传输发送以下AT指令进行初始化:

char rst[] = "AT+RESTORE\r\n";//WIFI模块重置
char cipmode[] = "AT+CIPMODE=0\r\n";//退出透传模式(因为WIFI模块在AP模式下是不需要透传的)
char mux[] = "AT+CIPMUX=1\r\n";//设置多连接
char server[] = "AT+CIPSERVER=1\r\n";//设置服务器模式

当APP(从机)与WIFI模块(主机建立连接后)需要发送如下指令:

char cipsend[] = "AT+CIPSEND=0,30\r\n";//其中的0代表连接号,30代表需要发送的数据 根据自己需求定

STM32单片机(主机)

初始化WIFI模块

	/*给大延时是为了等待模块反应*/
	HAL_UART_Transmit(&huart7,(uint8_t *)rst,strlen(rst),0xFFFF);
	HAL_Delay(5000);
	memset(ReceiveBuff,'\0',PackSize);
	HAL_Delay(1000);
	HAL_UART_Transmit(&huart7,(uint8_t *)cipmode,strlen(cipmode),0xFFFF);
	HAL_Delay(2000);
	memset(ReceiveBuff,'\0',PackSize);
	HAL_Delay(1000);
	HAL_UART_Transmit(&huart7,(uint8_t *)mux,strlen(mux),0xFFFF);
	HAL_Delay(2000);
	memset(ReceiveBuff,'\0',PackSize);
	HAL_Delay(1000);
	HAL_UART_Transmit(&huart7,(uint8_t *)server,strlen(server),0xFFFF);
	HAL_Delay(2000);
	memset(ReceiveBuff,'\0',PackSize);

控制任务

void Control_Task(void *argument)
{
	portTickType xLastWakeTime;
  xLastWakeTime = xTaskGetTickCount();

		switch(data_wifi.control_light)
	{
		case 'W':
			LIGHT_CLOSE();
			Send_PackCage.light_status = 'n';
			break;
		case 'Q':
			LIGHT_ON();
			Send_PackCage.light_status = 'y';
			break;
		default:
			break;
	}
		switch(data_wifi.control_music)
	{
		case 'A':
			LittleStar_InitMusic();
			Send_PackCage.music_status = 'l';
			break;
		case 'S':
			HappySong_InitMusic();
			Send_PackCage.music_status = 'h';
			break;
		case 'D':
			SuperMario_InitMusic();
			Send_PackCage.music_status = 's';
		break;
		case '#':
			musicflag = 1;
		break;
		default:
			HAL_TIM_PWM_Stop(&htim12, TIM_CHANNEL_1);
			Send_PackCage.music_status = 'n';
			break;
				
	}
		if(Frame_Flag.controlflag++ >= 1000 )
			Frame_Flag.controlflag = 0;	
		
		
    vTaskDelayUntil(&xLastWakeTime, 50 / portTICK_RATE_MS);
  }	
}

DHT11数据发送给WIFI模块

		if(Count_Data.dht11_count >= TASK_DHT11)
		{
			DHT11_Read_TempAndHumidity(&DHT11_Data);
			sprintf(str,"%.2f",DHT11_Data.temperature);
			strcat(str,fuhao);//这里利用一个符号可以在App的逻辑代码中对字符串进行分割
			sprintf(humi,"%f",DHT11_Data.humidity);
			strcat(str,humi);
			if(Init_FLAG == 1)
			{
				HAL_UART_Transmit(&huart7,(uint8_t *)cipsend,strlen(cipsend),0xFFFF);
				HAL_Delay(200);
				HAL_UART_Transmit(&huart7,(uint8_t *)str,strlen(str),0xFFFF);
			}
			Count_Data.dht11_count = 0;
		}

APP的编写

布局文件

内容偏长,需要的可以复制,不需要的直接跳过就好了

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        android:background="@drawable/wolf"
    />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Smart Home Center"
        android:textStyle="bold"
        android:textColor="@color/white"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:paddingLeft="50dp">

        <TextView
            android:id="@+id/textip"
            android:layout_width="70dp"
            android:layout_height="40dp"
            android:text="设备IP:"
            android:gravity="center"
            android:textColor="@color/white" />

        <EditText
            android:id="@+id/ip"
            android:layout_width="250dp"
            android:layout_height="40dp"
            android:layout_toRightOf="@+id/textip"
            android:gravity="center"
            android:maxLines="1"
            android:textColor="@color/white" />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:paddingLeft="50dp">

        <TextView
            android:layout_width="70dp"
            android:layout_height="40dp"
            android:text="Port:"
            android:id="@+id/textport"
            android:gravity="center"
            android:textColor="@color/white"
            android:inputType="number"
            />

        <EditText
            android:id="@+id/port"
            android:layout_width="250dp"
            android:layout_height="40dp"
            android:layout_toRightOf="@+id/textport"
            android:maxLines="1"
            android:textColor="@color/white" />

    </RelativeLayout>

    <Button
        android:layout_width="150dp"
        android:layout_height="40dp"
        android:background="#00B8D4"
        android:layout_gravity="center"
        android:textColor="@color/white"
        android:textStyle="bold"
        android:text="Connect"
        android:onClick="Connect"
        />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:paddingLeft="50dp">

        <TextView
            android:id="@+id/textTem"
            android:layout_width="180dp"
            android:layout_height="20dp"
            android:text="Home Of Temperature:"
            android:textColor="@color/white"
            android:textSize="15sp"
            />

        <TextView
            android:id="@+id/temperature"
            android:layout_width="60dp"
            android:layout_height="20dp"
            android:layout_toRightOf="@+id/textTem"
            android:textColor="@color/white"
            android:textSize="15sp" />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:paddingLeft="50dp">

        <TextView
            android:id="@+id/texthumi"
            android:layout_width="180dp"
            android:layout_height="20dp"
            android:text="Home Of Humidity:"
            android:textColor="@color/white"
            android:textSize="15sp" />

        <TextView
            android:id="@+id/humidity"
            android:layout_width="35dp"
            android:layout_height="20dp"
            android:layout_toRightOf="@+id/texthumi"
            android:textColor="@color/white"
            android:textSize="15sp" />
        <TextView
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:id="@+id/fuhao"
            android:layout_toRightOf="@id/humidity"
            android:textColor="@color/white"
            android:textSize="15sp"/>

    </RelativeLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Device_Control"
        android:textColor="@color/white"
        android:layout_marginTop="10dp"
        android:textSize="20sp"
        android:layout_gravity="center"
        android:textStyle="bold"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="                   —————————————————————————"
        android:textColor="@color/white"
        android:layout_marginTop="5dp"
        />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        >

        <Button
            android:id="@+id/online"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:background="#0AD9F6"
            android:text="JudgeOnline"
            android:textColor="@color/white"
            android:textSize="12dp"
            android:textStyle="italic" />

        <TextView
            android:id="@+id/status"
            android:layout_width="200dp"
            android:layout_height="50dp"
            android:layout_toRightOf="@+id/online"
            android:gravity="center"
            android:text="Wait"
            android:textColor="@color/white"
            android:textSize="20dp" />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"

        >


        <Button
            android:id="@+id/lighton"
            android:layout_width="150dp"
            android:layout_height="50dp"
            android:background="#0AD9F6"
            android:text="LIGHTON"
            android:textColor="@color/white"
            android:textStyle="italic" />

        <Button
            android:id="@+id/lightclose"
            android:layout_width="150dp"
            android:layout_height="50dp"
            android:layout_toRightOf="@+id/lighton"
            android:layout_marginLeft="20dp"
            android:background="#0AD9F6"
            android:gravity="center"
            android:text="LIGHTCLOSE"
            android:textColor="@color/white" />

    </RelativeLayout>


    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="15dp"
        android:layout_gravity="center"
        >

        <Button
            android:id="@+id/music1"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:background="#0AD9F6"
            android:text="MUSIC1"
            android:textColor="@color/white"
            android:textStyle="italic" />
        <Button
            android:id="@+id/music2"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:layout_toRightOf="@id/music1"
            android:layout_marginLeft="10dp"
            android:background="#0AD9F6"
            android:text="MUSIC2"
            android:textColor="@color/white"
            android:textStyle="italic" />
        <Button
            android:id="@+id/music3"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:layout_toRightOf="@id/music2"
            android:layout_marginLeft="10dp"
            android:background="#0AD9F6"
            android:text="MUSIC3"
            android:textColor="@color/white"
            android:textStyle="italic" />

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginTop="15dp"
        android:layout_gravity="center"
        >

        <TextView
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="No Music"
            android:textColor="@color/white"
            android:textSize="20sp"
            android:id="@+id/musicname"
            />

        <Button
            android:layout_width="100dp"
            android:layout_height="20dp"
            android:layout_alignBottom="@+id/musicname"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="-12dp"
            android:id="@+id/shutdown"
            />


    </RelativeLayout>


</LinearLayout>

效果图

小黄鸭除外😿!!

逻辑代码

package com.example.smart_homeapp;

import androidx.appcompat.app.AppCompatActivity;

import android.icu.util.Output;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ThreadLocalRandom;

public class MainActivity extends AppCompatActivity {

    Client_Thread client;

    Socket ClientSocket;
    InputStream is;
    OutputStream os;

    EditText et_ip,et_port;
    TextView tv_online,tv_music,tv_temperature,tv_humidity,tv_fuhao;
    Button btn_online,btn_lighton,btn_lightclose,btn_music1,btn_music2,btn_music3,btn_sd;

    ButtonListener buttonListener;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Viewinit();
        Listenerinit();


    }

    public void Viewinit(){
        et_ip = (EditText) findViewById(R.id.ip);
        et_port = (EditText)findViewById(R.id.port);

        tv_online = (TextView) findViewById(R.id.status);
        tv_music = (TextView)findViewById(R.id.musicname);
        tv_temperature = (TextView)findViewById(R.id.temperature);
        tv_humidity = (TextView)findViewById(R.id.humidity);
        tv_fuhao = (TextView)findViewById(R.id.fuhao);

        btn_online = (Button) findViewById(R.id.online);

        btn_lighton = (Button) findViewById(R.id.lighton);
        btn_lightclose = (Button) findViewById(R.id.lightclose);

        btn_music1 = (Button) findViewById(R.id.music1);
        btn_music2 = (Button) findViewById(R.id.music2);
        btn_music3 = (Button) findViewById(R.id.music3);

        btn_sd = (Button) findViewById(R.id.shutdown);
    }

    public void Connect(View view) {

        String ip = et_ip.getText().toString();
        int port = Integer.parseInt(et_port.getText().toString());
        Toast.makeText(MainActivity.this,"Wait a second...",Toast.LENGTH_LONG).show();
        client = new Client_Thread(ip,port);
        client.start();
        Toast.makeText(MainActivity.this, "Connect Successfully", Toast.LENGTH_SHORT).show();
    }
//灯 - music - judge
    class ButtonListener implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.online:
                    send("##C");
                    tv_online.setText("Already done");
                    Toast.makeText(MainActivity.this, "Please..Wait...", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.lighton:
                    send("Q##");
                    Toast.makeText(MainActivity.this, "The Light is openned", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.lightclose:
                    send("W##");
                    Toast.makeText(MainActivity.this, "The Light is closed", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.music1:
                    send("#A#");
                    Toast.makeText(MainActivity.this, "Little_Start Music Begin", Toast.LENGTH_SHORT).show();
                    tv_music.setText("Little_Start");
                    break;
                case R.id.music2:
                    send("#S#");
                    Toast.makeText(MainActivity.this, "Happy_Song Music Begin ", Toast.LENGTH_SHORT).show();
                    tv_music.setText("Happy_Song");
                    break;
                case R.id.music3:
                    send("#D#");
                    Toast.makeText(MainActivity.this, "Mario_Song Music Begin", Toast.LENGTH_SHORT).show();
                    tv_music.setText("Mario_Song");
                    break;
                case R.id.shutdown:
                    send("###");
                    Toast.makeText(MainActivity.this, "Shut down All!!", Toast.LENGTH_SHORT).show();
                    tv_music.setText("No Music");
            }
        }
    }


    public void Listenerinit(){

        buttonListener = new ButtonListener();

        btn_online.setOnClickListener(buttonListener);

        btn_lighton.setOnClickListener(buttonListener);
        btn_lightclose.setOnClickListener(buttonListener);

        btn_music1.setOnClickListener(buttonListener);
        btn_music2.setOnClickListener(buttonListener);
        btn_music3.setOnClickListener(buttonListener);

        btn_sd.setOnClickListener(buttonListener);

    }


    public void send(String msg){
        new SendThread(msg).start();
    }

    class SendThread extends Thread{

        String msg;

        public SendThread(String msg){
            this.msg = msg;
        }


        @Override
        public void run() {
            try {
                if(os == null)
                {
                    //Toast.makeText(MainActivity.this,"TCP has no Connected",Toast.LENGTH_LONG).show();
                    return;
                }
                os.write(msg.getBytes());
                os.flush();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    String str;
    class Client_Thread extends Thread{
        String ip;
        int port;
        public Client_Thread(String ip,int port){
            this.ip = ip;
            this.port = port;
        }
        public void run() {
            try {
                ClientSocket = new Socket(ip,port);
                is = ClientSocket.getInputStream();
                os = ClientSocket.getOutputStream();
                while(true){
                    final byte[] buf = new byte[1024];
                    final int len = is.read(buf);
                    str = new String(buf,0,len);

//                    runOnUiThread(new Runnable() {
//                        public void run() {
//                            tv_temperature.setText(str);
                            tv_humidity.setText(str);
//                        }
//                    });
                    runOnUiThread(()->{

                        String[] strs = str.split(",");
                        tv_temperature.setText(strs[0]+"°");
                        tv_humidity.setText(strs[1]);
                        tv_fuhao.setText("%");
                        Log.e("TAG",str);

                    });

                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}




这里创建了两个线程,一个是客户端线程,用来接收服务器发来的数据,一个是发送线程,用来发送APP点击触发的事件需要发送的信息。在客户端线层中用了split来进行分隔接受回来的数据。类似于去除帧头帧尾。

BUG记录

WIFI模块的发送

这个真的很坑!如果你用WIFI模块作为服务器的话,也就是说WIFI模块被设置成AP模式的话,那么就得先把WIFI模块的透传模式关了,不然的话CIPSEND发送一直都是返回ERROR的。
解决方法:按照我上图的初始化逻辑就好了,至于CIPSEND,看个人需求放不同的位置就好了。

开任务之后main.c里的while不跑了

md这个问题就很灵性,由于在任务里面没有us级的延时(可能有,但是我不知道),但是处理DHT11模块返回来的数据需要用us级的延时等待脉冲的产生再进行置位。因为潜意识里在任务里面除了用osDelay外其他的Delay类似于HAL_Delay这些会对任务造成阻塞然后程序就死掉了。
出现问题的原因:一般来说开启调度器之后while的确是不跑的,所以把调度器注释掉就好了,跑轮询不跑任务。
解决方法:
摆烂法:跑裸机,把main.c里的任务创建注释了然后全部把代码放在while里面利用delay计时跑个假的任务处理。(虽然是在摆烂,但是确实能解决ddl带来的焦虑)
认真解决法:可以用32的硬件__NOP来进行us级的计时,像我用的F427,我的时钟频率在168M,那么我一个NOP其实就是6ns左右,也就是1/168us,那我们就可以根据这个汇编指令一个空指令NOP来进行us级的计时对DHT11上拉下拉进行读取电平数据。

有关智能家居—基于STM32的温湿度控制系统(WIFI模块)的更多相关文章

  1. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  2. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  3. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  4. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  5. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  6. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

  7. ruby - 如何使用 Ruby 基于字母数字字符串生成颜色? - 2

    我想要像“嘿那里”这样的东西变成,例如,#316583。我希望将任意长度的字符串“归结”为十六进制颜色。我不知道从哪里开始。我在想,每个字符串的MD5散列都是不同的-但如何将该散列转换为十六进制颜色数字? 最佳答案 你可以只取几位前几位:require'digest/md5'color=Digest::MD5.hexdigest('Mytext')[0..5] 关于ruby-如何使用Ruby基于字母数字字符串生成颜色?,我们在StackOverflow上找到一个类似的问题:

  8. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  9. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

  10. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

随机推荐