소규모 사물 인터넷 실험을 통해 stm32 실험 보드와 Android 스튜디오에서 작성한 APP를 동시에 mqtt 서버에 연결하여 실험 보드 상태를 원격으로 제어할 수 있습니다.

목차

I. 소개

2. 실험 도구

1. Wildfire F103 개발 보드

 2.MQTT 프록시 도구 mqtt.fx

 3. 안드로이드 앱 코드 

1. 프로젝트 수립

2. Java jar 패키지 가져오기

3. 레이아웃 파일 Activity_main

4.주요 활동

5. 네트워크 권한 구성

6. 앱 테스트

 7. APK 설치 패키지 내보내기

 4. STM32 실험 보드 코드

1. 주요 기능

2.esp8266

 3.원넷

 4.간단한 요약

5. 테스트

1. 앱과 mqtt 간의 연결 상태 테스트

2. 앱과 실험 보드를 mqtt 서버에 동시에 연결하여 원격 제어를 수행합니다.

 6. 요약


I. 소개

이것은 실제로 사물 인터넷에 대한 간단한 작은 실험입니다. 기본 원리를 이해하는 것이 중요합니다. 이해하지 못하면 어디서부터 시작해야 할지 모릅니다. 이 실험은 APP와 STM32 실험보드를 네트워크에 연결하고 동시에 mqtt 서버에 연결하여 앱이 실험보드의 상태를 원격으로 제어할 수 있도록 하는 것입니다. 이 실험을 통해 다음이 가능해졌습니다.

  1. LED 조명의 STM32 제어를 실현하여 7가지 색상을 표시합니다.
  2. 부저음을 제어하고 정지시키려면 STM32를 구현해 보세요.
  3. NTC 센서를 통해 온도를 측정하려면 STM32를 구현하십시오.
  4. 직렬 포트 디버깅 지원을 통해 STM32 온도 디스플레이를 구현합니다.
  5. WIFI 라우터에 연결하기 위해 ESP8266을 제어하기 위해 STM32를 구현하십시오.
  6. MQTT 서버에 성공적으로 연결하려면 STM32를 구현하세요.
  7. MQTT 온도 주제를 성공적으로 게시하려면 STM32를 구현하세요.
  8. MQTT 제어 주제에 대한 STM32의 성공적인 구독 구현
  9. 휴대폰 앱에서 온도 표시를 실현하세요.
  10. LED 조명을 제어하여 다양한 색상을 표시하는 모바일 앱 실현

우선 앱을 개발합니다. 앱은 다양한 언어로 작성할 수 있습니다. 여기서는 안드로이드 언어를 사용하고 있습니다(안드로이드 스튜디오에서는 기본 지식이 탄탄하지 않으면 작성하기가 더 어렵습니다. 안드로이드 코드는 그냥 냄새나고 길어요. 프론트엔드를 배우신 분들은 HBuilder.Write)를 사용하여 관련 컨트롤을 추가하고 앱에 클릭 이벤트를 추가하시면 됩니다.​ 

그리고 keil5를 이용해 실험보드 코드를 작성해 보세요. 마이크로컨트롤러에 대한 깊은 지식이 없다면, 너무 어렵기 때문에 아래에 언급한 방법에 따라 해당 내용을 변경하는 것이 좋습니다!

2. 실험 도구

이는 제가 사용하는 실험 도구를 의미하며, 유연하고 변경이 가능하며 꼭 나와 똑같을 필요는 없습니다.

1. Wildfire F103 개발 보드

이 보드는 임베디드 개발 초보자에게 완벽합니다.

 2.MQTT 시각화 도구 mqtt.fx

 3. 안드로이드 앱 코드 

1. 프로젝트 수립

왼쪽 상단에서 파일을 클릭한 다음 새 프로젝트를 클릭하여 새 프로젝트를 만듭니다.

 언어로 Java를 선택하세요. 잘못된 것을 선택하지 마세요.

2. Java jar 패키지 가져오기

링크:Baidu Cloud Disk 추출 코드를 입력하세요

 방법은 Baidu에 직접가는 것인데 온라인 튜토리얼은 매우 자세합니다.

3. 레이아웃 파일 Activity_main

<?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:orientation="vertical"
    tools:context=".MainActivity"
    android:background="@drawable/cxk"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="10dp">
        <TextView
            android:id="@+id/m_temp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="当前温度:"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:layout_marginLeft="25dp"/>
        <TextView
            android:id="@+id/temp_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textSize="20sp"
            android:textColor="@color/black"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="25dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MQTT连接状态:"
            android:textColor="@color/black"
            android:textSize="20sp" />
        <TextView
            android:id="@+id/m_mqtt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="@color/black"
            android:textSize="20sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="25dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="实验板状态:"
            android:textColor="@color/black"
            android:textSize="20sp" />
        <TextView
            android:id="@+id/Light_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="@color/橙红色"
            android:textSize="20sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="460dp"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="392dp"
            android:layout_marginTop="60dp"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="30dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="灯按钮"
                    android:textSize="20sp" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="5dp">

                <Button
                    android:id="@+id/off"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="关灯" />

                <Button
                    android:id="@+id/red"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="红灯" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="5dp">

                <Button
                    android:id="@+id/lv"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="绿灯" />

                <Button
                    android:id="@+id/blue"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="蓝灯" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="5dp">

                <Button
                    android:id="@+id/red_blue"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="紫灯" />

                <Button
                    android:id="@+id/red_lv"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="黄灯" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="5dp">

                <Button
                    android:id="@+id/lv_blue"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="青灯" />

                <Button
                    android:id="@+id/red_lv_blue"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="橙灯" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="150dp"
                android:layout_height="30dp"
                android:layout_marginTop="5dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="蜂鸣器开关按钮"
                    android:textSize="20sp" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_marginTop="5dp">

                <Button
                    android:id="@+id/fmq_on"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="开启" />

                <Button
                    android:id="@+id/fmq_off"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:text="关闭" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="2dp"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        >
        <TextView
            android:id="@+id/New"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginTop="5dp"
            android:textColor="@color/紫罗兰"
            android:textSize="30dp"
            />
    </LinearLayout>

</LinearLayout>

레이아웃 파일 렌더링:

 그만 얘기해, 난 이쿤이야! ! ! ! ! ! 사실 농구선수들을 내보내고 싶었어요.

레이아웃 파일에서 theme.xml 모듈 코드를 변경하지 않으면 아래 그림과 같이 이 버튼의 색상이 보라색만 될 수 있으므로 가족 구성원의 재능 개발에 영향을 미치게 되므로 최소한 검은색 작업복을 입어야 합니다.

따라서 프로젝트 아래의 값으로 theme.xml을 열어야 합니다.

 parent="Theme.MaterialComponents.DayNight.DarkActionBar"의 마지막 DarkActionBar를 NoActionBar.Bridge, 즉 parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge"로 교체합니다.

 이렇게 하면 버튼의 배경색을 마음대로 수정할 수 있습니다!

마지막으로 보너스로 일반적으로 사용되는 여러 색상에 대한 코드를 알려드리겠습니다. 이 코드를 값 파일 아래의 colors.xml에 복사하세요.

코드는 아래와 같이 표시됩니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="粉色">#FFC0CB</color>
    <color name="紫罗兰">#EE82EE</color>
    <color name="靛青">#4B0082</color>
    <color name="矢车菊的蓝色">#6495ED</color>
    <color name="适中的蓝色">#0000CD</color>
    <color name="深蓝色">#00008B</color>
    <color name="石板灰">#708090</color>
    <color name="青色">#00FFFF</color>
    <color name="猩红">#DC143C</color>
    <color name="军校蓝">#5F9EA0</color>
    <color name="蓝色">#0000FF</color>
    <color name="水绿色">#00FFFF</color>
    <color name="绿玉">#7FFFAA</color>
    <color name="绿色">#00FF00</color>
    <color name="黄色">#FFFF00</color>
    <color name="橙红色">#FF4500</color>
    <color name="棕色">#A52A2A</color>
</resources>

4.주요 활동

코드는 다음과 같습니다: Mainactivity 의 모든 코드입니다. 모두 복사하지 않는 것이 좋습니다. 그렇지 않으면 오류가 발생합니다. 다음 방법에 따라 천천히 입력하십시오. 작성하고 나면 거의 이해되었다는 느낌이 듭니다. 이유 제가 올리는 이유는 다음 방법이 좀 지저분해서 코드를 다 보내주세요.

package com.example.option;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.Html;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {
    public static MqttClient mMqClint;
    private ScheduledExecutorService scheduler;
    private MqttClient client;
    private Handler handler;
    private TextView temp_show;
    private TextView mqtt_show;
    private TextView led_show;
    private TextView textView;
    private String host = "tcp://mqtt.qzyuehua.cn";     // TCP协议
    private String userName = "daluo";
    private String passWord = "daluo1";
    private String mqtt_id = "daluo2";
    private String mqtt_sub_topic = "123456/stm32";
    private String mqtt_pub_topic = "123456/app";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Mqtt_init();
        startReconnect();
        temp_show = findViewById(R.id.temp_tv);
        mqtt_show = findViewById(R.id.m_mqtt);
        led_show =findViewById(R.id.Light_status);
        textView = (TextView)this.findViewById(R.id.New);
        String html = "全民制作人们,大家好,我是练习时长两年半的个人练习生蔡徐坤,喜欢唱、跳、rap、篮球,\n" +
                "                music!";
        CharSequence charSequence = Html.fromHtml(html);
        textView.setText(charSequence);
        textView.setMovementMethod(LinkMovementMethod.getInstance());
        textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        textView.setSingleLine(true);
        textView.setSelected(true);
        textView.setFocusable(true);
        textView.setFocusableInTouchMode(true);
        Button button_off = (Button) findViewById(R.id.off);
        button_off.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "关灯", Toast.LENGTH_SHORT).show();
                publishmessageplus(mqtt_pub_topic, "L0");
                led_show.setText("已关闭LED灯");
            }
        });
        Button button_red = (Button) findViewById(R.id.red);
        button_red.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "红灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L1");
                led_show.setText("红灯");
            }
        });
        Button button_lv = (Button) findViewById(R.id.lv);
        button_lv.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "绿灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L2");
                led_show.setText("绿灯");
            }
        });
        Button button_blue = (Button) findViewById(R.id.blue);
        button_blue.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "蓝灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L3");
                led_show.setText("蓝灯");
            }
        });
        Button button_red_blue = (Button) findViewById(R.id.red_blue);
        button_red_blue.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "紫灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L4");
                led_show.setText("紫灯");
            }
        });
        Button button_red_lv = (Button) findViewById(R.id.red_lv);
        button_red_lv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "黄灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L5");
                led_show.setText("黄灯");
            }
        });
        Button button_lv_blue = (Button) findViewById(R.id.lv_blue);
        button_lv_blue.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "青灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L6");
                led_show.setText("青灯");
            }
        });
        Button button_red_lv_blue = (Button) findViewById(R.id.red_lv_blue);
        button_red_lv_blue.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "橙灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L7");
                led_show.setText("橙灯");
            }
        });
        Button fmq_ON = (Button) findViewById(R.id.fmq_on);
        fmq_ON.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "打开蜂鸣器", Toast.LENGTH_SHORT).show();
                publishmessageplus(mqtt_pub_topic, "L8");
                led_show.setText("蜂鸣器已打开");
            }
        });
        Button fmq_OFF = (Button) findViewById(R.id.fmq_off);
        fmq_OFF.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "关闭蜂鸣器", Toast.LENGTH_SHORT).show();
                publishmessageplus(mqtt_pub_topic, "L9");
                led_show.setText("蜂鸣器已关闭");
            }
        });
        handler = new Handler(Looper.myLooper()) {
            @SuppressLint("SetTextI18n")
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1: //开机校验更新回传
                        break;
                    case 2:  // 反馈回传
                        break;
                    case 3:  //MQTT 收到消息回传   UTF8Buffer msg=new UTF8Buffer(object.toString());
                        System.out.println(msg.obj.toString());   // 显示MQTT数据
                        break;
                    case 30:  //连接失败
                        //Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).
                                //show();
                        mqtt_show.setText("连接失败!");
                        break;
                    case 31:   //连接成功
                        Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).
                                show();
                        mqtt_show.setText("连接成功!");
                        try {
                            client.subscribe(mqtt_sub_topic, 1);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        break;
                }
            }
        };
    }
    //mqtt初始化
    private void Mqtt_init() {
        try {
            client = new MqttClient(host, mqtt_id,
                    new MemoryPersistence());
            //MQTT的连接设置
            MqttConnectOptions options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
            // 这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(false);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,
            // 但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("connectionLost----------");
                }
                @Override
                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                    System.out.println("deliveryComplete---------"
                            + iMqttDeliveryToken.isComplete());
                }
                @Override
                public void messageArrived(String topicName, MqttMessage mqttMessage)
                        throws Exception {
                    final String payload = new String(mqttMessage.getPayload());
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            temp_show.setText(payload+"℃");
                        }
                    });
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //MQTT连接函数
    private void startReconnect() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable(){
            @Override
            public void run() {
                if (!client.isConnected()) {
                    Mqtt_connect();
                }
            }
        },0*1000,10*1000, TimeUnit.MICROSECONDS);
    }

    //MQTT重新连接函数
    private void Mqtt_connect() {
        new Thread(new Runnable(){

            @Override
            public void run() {
                try {
                    if(!(client.isConnected()) )  //如果还未连接
                    {
                        MqttConnectOptions options = null;
                        client.connect(options);
                        Message msg = new Message();
                        msg.what = 31;
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Message msg = new Message();
                    msg.what = 30;
                    handler.sendMessage(msg);
                }
            }
        }).start();
    }
    //mqtt初始化
    //订阅函数
    private void publishmessageplus(String topic,String message2)
    {
        if (client == null || !client.isConnected()) {
            return;
        }
        MqttMessage message = new MqttMessage();
        message.setPayload(message2.getBytes());
        try {
            client.publish(topic,message);
        } catch (MqttException e) {

            e.printStackTrace();
        }
    }
    private void Delay(){
        if(mqtt_pub_topic!="L0"){
            publishmessageplus(mqtt_pub_topic,"L0");
        }

    }
}

Mainactivity는 주로 다음과 같은 방법으로 구성됩니다.

 OnCreate는 레이아웃 페이지 버튼의 콜백 메소드를 주로 구현하는데, 여기서도 실수하기 쉽기 때문에 직접 입력하는 것이 좋습니다.

(1) 먼저 사용해야 할 변수를 작성하고, 코드는 다음과 같습니다.

    public static MqttClient mMqClint;
    private MqttClient client;
    private ScheduledExecutorService scheduler;
    private Handler handler;
    private TextView temp_show;
    private TextView mqtt_show;
    private TextView led_show;
    private TextView textView;

그러면 오류가 보고될 것입니다.커서를 빨간색 영역으로 이동하고 "Ait+Enter"를 눌러 패키지를 안내합니다.

 

 (2) mqtt 구성 코드는 다음과 같습니다.

    private String host = "tcp://mqtt.qzyuehua.cn";     // TCP协议,没有的话也可以用我这个
    private String userName = "admin"; 
    private String passWord = "123456"; 
    private String mqtt_id = "230722";
    private String mqtt_sub_topic = "123456/stm32";  //发送方
    private String mqtt_pub_topic = "123456/app";    //接收方

TCP 프로토콜은 선생님이 알려주신 것을 사용하셔도 되고, 가지고 계신다면 수정하셔도 됩니다. userName과 passWord는 mqtt.fx 디버깅에 사용되지만, 실험을 할 때는 전혀 사용하지 않으므로 적어주셔도 되고 안 쓰셔도 됩니다. 나머지 3개는 매우 중요하며 특히 송신자와 수신자는 실험보드의 코드와 동일해야 합니다.

(3)생성 시

먼저 다음 코드를 OnCreate에 복사합니다. 코드는 다음과 같습니다.

        Mqtt_init();
        startReconnect();
        temp_show = findViewById(R.id.temp_tv);
        mqtt_show = findViewById(R.id.m_mqtt);
        led_show =findViewById(R.id.Light_status);
        textView = (TextView)this.findViewById(R.id.New);
        String html = "全民制作人们,大家好,我是练习时长两年半的个人练习生蔡徐坤,喜欢唱、跳、rap、篮球\n" + "music!";
        CharSequence charSequence = Html.fromHtml(html);
        textView.setText(charSequence);
        textView.setMovementMethod(LinkMovementMethod.getInstance());
        textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        textView.setSingleLine(true);
        textView.setSelected(true);
        textView.setFocusable(true);
        textView.setFocusableInTouchMode(true);
        

그런 다음 두 가지 방법을 추가해야 하는 두 곳이 있습니다.

 위와 같이 빨간색 코드에 커서를 놓고 "AIT+Enter"를 길게 눌러 두 가지 방법을 추가합니다.

 레이아웃 파일을 클릭하는 버튼을 작성하려면 해당 변경 사항이 있을 것이며 이러한 버튼의 클릭 이벤트를 작성해야 합니다. 내 레이아웃 페이지에는 버튼이 많기 때문에 해당 클릭 이벤트도 많이 있습니다. 이해하고 결합하는 것을 기억하세요 레이아웃 파일의 각 버튼 ID를 사용하면 특정 클릭 이벤트에 해당하는 버튼을 이해할 수 있으며 가족 구성원이 자유롭게 플레이하는 것도 편리합니다.

먼저 다음 코드를 복사하여 붙여넣으세요.

        Button button_off = (Button) findViewById(R.id.off);
        button_off.setOnClickListener(new View.OnClickListener()

 그런 다음 오류가 보고된 위치에 커서를 놓고 "AIT+Enter"를 눌러 메서드를 추가합니다.

 

 그런 다음 다음 코드를 복사하여 onClick에 붙여넣습니다.

Toast.makeText(MainActivity.this, "关灯", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L0");
led_show.setText("已关闭LED灯");

소등 버튼의 클릭 이벤트입니다. 주로 작성 방법을 알려드리기 위해 작성합니다. 전부 복사하면 에러가 발생하므로 메소드를 수동으로 생성해야 합니다. 여기서 "publishmessageplus"는 오류를 보고합니다. 이는 이 방법이 확립되지 않았기 때문입니다. 이 방법은 맨 아래에 있으므로 여기에 기록되지 않습니다. 무시하고 적어도 됩니다. 아래에Publishmessageplus를 적으면 오류가 발생합니다. 보고되지 않습니다.

다른 버튼의 클릭 이벤트도 이와 동일하게 작성되어 있으므로 자세한 설명은 생략하겠습니다.코드는 다음과 같습니다.

 Button button_red = (Button) findViewById(R.id.red);
        button_red.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "红灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L1");
                led_show.setText("红灯");
            }
        });
        Button button_lv = (Button) findViewById(R.id.lv);
        button_lv.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "绿灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L2");
                led_show.setText("绿灯");
            }
        });
        Button button_blue = (Button) findViewById(R.id.blue);
        button_blue.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "蓝灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L3");
                led_show.setText("蓝灯");
            }
        });
        Button button_red_blue = (Button) findViewById(R.id.red_blue);
        button_red_blue.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "紫灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L4");
                led_show.setText("紫灯");
            }
        });
        Button button_red_lv = (Button) findViewById(R.id.red_lv);
        button_red_lv.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "黄灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L5");
                led_show.setText("黄灯");
            }
        });
        Button button_lv_blue = (Button) findViewById(R.id.lv_blue);
        button_lv_blue.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "青灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L6");
                led_show.setText("青灯");
            }
        });
        Button button_red_lv_blue = (Button) findViewById(R.id.red_lv_blue);
        button_red_lv_blue.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "橙灯", Toast.LENGTH_SHORT).show();
                Delay();
                publishmessageplus(mqtt_pub_topic, "L7");
                led_show.setText("橙灯");
            }
        });
        Button fmq_ON = (Button) findViewById(R.id.fmq_on);
        fmq_ON.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "打开蜂鸣器", Toast.LENGTH_SHORT).show();
                publishmessageplus(mqtt_pub_topic, "L8");
                led_show.setText("蜂鸣器已打开");
            }
        });
        Button fmq_OFF = (Button) findViewById(R.id.fmq_off);
        fmq_OFF.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "关闭蜂鸣器", Toast.LENGTH_SHORT).show();
                publishmessageplus(mqtt_pub_topic, "L9");
                led_show.setText("蜂鸣器已关闭");
            }
        });
        handler = new Handler(Looper.myLooper()) {
            @SuppressLint("SetTextI18n")
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1: //开机校验更新回传
                        break;
                    case 2:  // 反馈回传
                        break;
                    case 3:  //MQTT 收到消息回传   UTF8Buffer msg=new UTF8Buffer(object.toString());
                        System.out.println(msg.obj.toString());   // 显示MQTT数据
                        break;
                    case 30:  //连接失败
                        //Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).
                                //show();
                        mqtt_show.setText("连接失败!");
                        break;
                    case 31:   //连接成功
                        Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).
                                show();
                        mqtt_show.setText("连接成功!");
                        try {
                            client.subscribe(mqtt_sub_topic, 1);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        break;
                }
            }
        };

이러한 코드는 모두 공개 클래스 MainActivity가 AppCompatActivity를 확장하는 것이 아니라 OnCreate()에 작성된다는 점을 기억하세요.

(4)Mqtt_init 메소드

코드는 아래와 같이 표시됩니다.

//mqtt初始化
private void Mqtt_init() {
        try {
            client = new MqttClient(host, mqtt_id,
                    new MemoryPersistence());
            //MQTT的连接设置
            MqttConnectOptions options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
            // 这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(false);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,
            // 但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("connectionLost----------");
                }
                @Override
                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                    System.out.println("deliveryComplete---------"
                            + iMqttDeliveryToken.isComplete());
                }
                @Override
                public void messageArrived(String topicName, MqttMessage mqttMessage)
                        throws Exception {
                    final String payload = new String(mqttMessage.getPayload());
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            temp_show.setText(payload+"℃");
                        }
                    });
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

(5) startReconnect 방법

코드는 아래와 같이 표시됩니다.

//MQTT连接函数
private void startReconnect() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable(){
            @Override
            public void run() {
                if (!client.isConnected()) {
                    Mqtt_connect();
                }
            }
        },0*1000,10*1000, TimeUnit.MICROSECONDS);
    }

(6) Mqtt_connect

코드는 아래와 같이 표시됩니다.

//MQTT重新连接函数
    private void Mqtt_connect() {
        new Thread(new Runnable(){

            @Override
            public void run() {
                try {
                    if(!(client.isConnected()) )  //如果还未连接
                    {
                        MqttConnectOptions options = null;
                        client.connect(options);
                        Message msg = new Message();
                        msg.what = 31;
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Message msg = new Message();
                    msg.what = 30;
                    handler.sendMessage(msg);
                }
            }
        }).start();
    }

(6)publishmessageplus 메소드

코드는 아래와 같이 표시됩니다.

//订阅函数
    private void publishmessageplus(String topic,String message2)
    {
        if (client == null || !client.isConnected()) {
            return;
        }
        MqttMessage message = new MqttMessage();
        message.setPayload(message2.getBytes());
        try {
            client.publish(topic,message);
        } catch (MqttException e) {

            e.printStackTrace();
        }
    }

(7) Delay() 메소드

이 방법은 이번에 조명을 켤 때 지난번에 켜졌던 조명을 끄는 방법인데, 꺼지지 않으면 색이 섞이게 됩니다. 두 번째로 파란색 표시등을 누르면 빨간색 표시등이 자동으로 꺼지지 않으므로 표시등의 현재 상태는 빨간색 + 파란색이므로 다른 표시등을 켜려면 매번 표시등 끄기 버튼을 눌러야 합니다. 그렇지 않으면 색상이 혼합됩니다. 그래서 각 색상의 조명 명령 앞에 light-off 명령을 추가했습니다. 조명을 켜려면 먼저 light-off 명령을 실행하십시오. 사실 이 방법은 매우 나쁜 방법입니다. 사용해보면 알게 될 것입니다. 컬러 조명 버튼을 누를 때마다 전송해야 하는 두 가지 명령이 있습니다. stm32 실험 보드가 좋지 않으면 첫 번째 조명 끄기 명령인 하나의 명령만 수신하므로 눌러야 합니다. 그러니 가족분들이 직접 바꿀 수 있는 좋은 방법이 있다면 댓글로 적어주시고 주변에 공유해주세요.

코드는 아래와 같이 표시됩니다.

    private void Delay(){
        if(mqtt_pub_topic!="L0"){
            publishmessageplus(mqtt_pub_topic,"L0");
        }

    }

5. 네트워크 권한 구성

네트워킹 권한을 설정하는 것은 매우 중요합니다. 이 코드 문자열을 작성해야 한다는 점을 기억해야 합니다. 이는 APP가 mqtt 서버에 성공적으로 연결할 수 있는지 여부를 결정하는 열쇠입니다.

단계:

(1) 매니페스트 파일을 엽니다.

 (2) 이 코드 문자열을 매니페스트에 붙여넣습니다. 코드는 다음과 같습니다.

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--允许程序打开网络套接字-->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--允许程序获取网络状态-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

6. 앱 테스트

이 시점에서 APP의 모든 코드가 작성되었으며 오류가 보고되지 않으면 테스트를 실행할 수 있으며 작업이 성공했음을 증명하는 다음 인터페이스가 나타납니다.

 7. APK 설치 패키지 내보내기

휴대폰에 앱을 설치하려면 apk 패키지를 내보내야 합니다.

단계:

(1) 메뉴 표시줄에서 Build를 클릭한 다음 Build Bundle/apk를 선택하고 마지막으로 Build APK(s)를 클릭합니다.

 그러면 오른쪽 하단에 프롬프트가 나타나고 위치를 클릭하여 파일의 저장 주소를 엽니다.

 파일 관리 페이지 진입 후, apk 설치 패키지를 휴대폰으로 전송하여 설치해 주세요.

 4. STM32 실험 보드 코드

stm32 코드가 너무 복잡해서 전체 코드를 잘 이해하지 못해서 그냥 wildfire 실험 템플릿을 가져와서 수정하고 사용할 사용자 파일을 다 가져와서 keil5 코드 전체를 직접 패키징해서 넣었습니다. 바이두 넷디스크 인사이드에서 직접 다운받아서 keil5에서 열 수 있습니다. 아래에서는 사용해야 할 몇 곳과 변경할 수 있는 곳, 특정 코드 블록이 하는 일과 하는 일을 소개하겠습니다. 누구나 사용하기에도 편리합니다.

링크: https://pan.baidu.com/s/1J5rJXD4bAuc6kYcv961fmg?pwd=rps1 
추출 코드: rps1

네트워크 디스크에는 4개의 파일이 있습니다! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !

첫 번째 파일에는 다양한 산불 실험 사례가 포함되어 있습니다. STM32를 배우고 싶은 학생들은 이 파일을 열어서 사용해 볼 수 있습니다. 지금 이야기하고 있는 것은네 번째 파일입니다. 아래에는 사용된 코드를 하나씩 소개합니다.stm32의 실험용 보드 코드입니다. 다운로드 후 압축을 풀고 keil5 MDK에서 직접 열어서 사용하시면 됩니다.,

1. 주요 기능

메인 기능에서 바꿀 만한 부분은 제가 동그라미 친 영역입니다. 발신자와 수신자입니다. 이 영역은 앱의 영역과 일치해야 합니다. 다른 영역에도 관심이 있으시면 천천히 살펴보시고 공부해 보시기 바랍니다. .

 

2.esp8266

이 기능은 주로 모바일 핫스팟과 mqtt 서버를 실험보드에 연결하는 데 사용됩니다! ! ! ! ! ! !

사물 인터넷을 구현하려면 STM32 실험 클래스와 APP가 동시에 인터넷에 연결되어야 하므로 실험 보드는 자체 휴대폰 핫스팟이나 인터넷 액세스가 가능한 기타 네트워크에 연결되어야 합니다. 첫 번째 정의에서 "WIFI 이름"을 휴대폰의 핫스팟 이름으로 변경하고 "WIFI 비밀번호"를 핫스팟 비밀번호로 변경합니다. 시간이 되면 코드를 STM32 실험 보드에 쓰면 자동으로 연결됩니다. 모바일 핫스팟.

 3.원넷

이 기능은 주로 APP에서 보낸 지시사항을 수신한 후 그에 따라 실험 보드로 전송하여 그에 따라 응답하는 역할을 담당합니다.위의 Android APP를 작성하면 각 버튼의 클릭 이벤트에 L0, L1, L2가 포함되어 있음을 알 수 있습니다. 잠깐, 여기에 해당합니다. L0은 ​​세 가지 원색에 해당합니다. 등은 모두 꺼졌습니다. 세 가지 원색 조명의 서로 다른 개방 방식의 조합으로 또 다른 네 개의 조명이 형성됩니다. 새로운 지침이 있으면 추가할 수 있습니다. 이 기능은 주로 앱 수신을 담당하며, 측면에서 보내는 지침입니다.

 4.간단한 요약

5. 테스트

1. 앱과 mqtt 간의 연결 상태 테스트

(1) mqtt.fx를 설치하고 엽니다.

 열면 다음 인터페이스가 표시됩니다. 게시는 발신자이고 구독은 구독자입니다. 다른 사용법을 알고 싶다면 Baidu에 직접 갈 수 있습니다. 자세한 내용은 설명하고 싶지 않습니다. 여기서는 이번 실험에 사용된 내용입니다. 처음에는 조금 헷갈릴 수도 있지만, 오랫동안 사용해보면 이것이 실제로는 APP가 mqtt 서버에 접속할 수 있는지 테스트하고, 명령어가 mqtt 서버로 전송되는지 확인하기 위한 것임을 자연스럽게 이해하게 될 것입니다. .

(2) mqtt.fx의 매개변수 구성

설정을 클릭하여 구성 페이지로 들어갑니다.

 구성은 다음과 같습니다.

 확인 후 메인 페이지로 돌아가서 연결을 클릭하여 연결하세요.

 성공적으로 연결되었음을 나타내는 녹색 표시등이 오른쪽 상단에 나타납니다.

 게시 옵션 상자 아래에 "123456/stm32"를 입력한 다음 아래 빈 상자에 온도를 입력하여 앱으로 전송하여 표시합니다.

아래 그림과 같이 온도 주제를 35 값으로 보냈는데, 앱이 이를 구독한 것을 확인할 수 있습니다.​ 

Sublime에 123456/app을 입력하고 앱의 간편버튼을 클릭합니다. 123456/app도 앱에서 보내는 안내를 구독했습니다. 이 단계에서 앱이 완성되었음을 증명합니다.

2. 앱과 실험 보드를 mqtt 서버에 동시에 연결하여 원격 제어를 수행합니다.

이 글은 기숙사에서 작성하고 실험판이 없어 보여드릴 사진이 없는 점 양해 부탁드립니다.

단계:

(1) Keil의 실험 보드에 코드를 작성하고 앱과 직렬 포트 디버깅 도우미(네트워크 디스크의 두 번째 파일)를 엽니다. 포트를 선택하고 직렬 포트 디버깅을 엽니다. 연결하려면 WIFI를 켜는 것을 잊지 마세요. 실험.

 다음 인터페이스가 나타나면서 연결이 성공했음을 증명합니다! ! ! ! !

 첫 번째 IoT 실험을 시작해 보세요! ! ! ! !

 비디오 분석:

영상분석

 6. 요약

본 실험은 개발된 앱과 F103 실험보드를 mqtt IP 프로토콜을 통해 mqtt 서버에 동시에 연결하여 원격 제어를 구현하는 것으로, 먼저 앱이 mqtt 서버에 명령을 보내고, mqtt 서버가 이를 수신한 후 이를 전송합니다. 실험판에서도 mqtt를 사용합니다. 서버는 온도를 APP에 보내고, 그 동안 mqtt는 중개자 역할을 합니다. 저의 직업적 발전 방향은 주로 Java 방향이라 하드웨어에 대해서는 잘 모릅니다. 이번 실험 역시 막연하게 진행되었습니다. 이해가 되지 않는 부분이 있으면 댓글란에 질문을 남겨주시면 됩니다. 보면 답장을 해주겠지만 감히 모든 문제가 해결될 수 있다고 장담할 수는 없습니다. 결국 저도 중고 검객입니다. 또한 CSDN 작성자에게도 감사의 말씀을 전하고 싶습니다.

내 앱의 코드 대부분은 그의 코드를 기반으로 하고 있습니다. 내가 작성한 내용을 이해할 수 없다면 그의 코드를 확인해 보세요. 그는 더 자세히 작성하고 더 명확하게 설명합니다.

추천

출처blog.csdn.net/qq_52428298/article/details/131882099