用简单的实例来讲解一下ESP8266的开发流程。
首先准备一个ESP8266的开发板,见下图:
这个开发板还是比较简单、方便、便宜的。使用了一个USB转串口的CH340芯片。串口端连接ESP8266的串口,USB端可通过数据线直接连接到电脑的USB端口,作为程序的下载线。
其次准备一个发光二极管,焊接两段杜邦线后,发光二极管的正端插入开发板的D0插针上,负端插入开发板的G插针上,见下图:
硬件就是这么简单,接下来就是软件了!
编程软件准备:
1、nodemcu-flasher-master.zip,用于刷固件。
2、ESPlorer.zip,用于编程。使用lua语言,一个轻量级、简单易学的编程语言。
3、Android Studio,用于手机端的软件编写。
先来刷固件,固件可通过固件获取这个页面获得。操作比较简单,填写自己的Email地址,选择需要的模块,最后点击下边的start your build按钮。随后就可以在你的邮箱中接收到固件文件了。所谓固件类似于操作系统加一些扩展的程序。
接下来,将nodemcu-flasher-master.zip解压到一个文件夹,打开目录下的ESP8266Flasher.exe程序文件。
在Config(配置菜单)中选择自己通过邮件得到的固件文件,如下图:
在Operation(操作菜单)中选择连接开发板的串口(USB转串口),最后点击Flash(刷入),将固件刷入到开发板中,如下图:
固件刷好后,可以编程了!
将ESPlorer.zip解压到一个文件夹,双击文件夹下的ESPlorer.bat文件,打开编程界面,如下图:
在右侧窗口上端列表框中选择连接开发板的串口(USB转串口),然后点击Open按钮,就可将编程软件与开发板在线连接(如果不能连接,尝试修改Open按钮右侧的波特率选择)。
右侧窗口中的Reload按钮,可以加载开发板上的用户程序。
左侧窗口即为源代码的编写窗口。
在左侧代码窗口中填写如下代码:
led =0 --定义管脚
gpio.mode(led, gpio.OUTPUT) --设置管脚模式为输出for var=0,10 dogpio.write(led,1) --点亮ledtmr.delay(1000000) --延时1秒gpio.write(led,0) --熄灭ledtmr.delay(1000000)
end
点击Save(保存)按钮,在随后弹出的文件名对话框中,将文件命名为init.lua。编程软件会自动将这段程序上载到开发板中,这时候你可以看到发光二极管已经开始闪烁,并在10次后熄灭。点击右侧的Reload(加载)按钮,可以看到按钮下方增加了一个名字为init.lua的按钮,可以点击它,从新运行你刚才编写的程序,见下图:
上边的这段程序是由lua语言编写的小程序,这并不是最终的程序,只是用来测试我们的开发板,可以运行自己的小程序了。后边我们还要更改,因为我们的目的是用手机控制led的亮灭和闪烁。
接下来打开Android Studio软件,创建一个新项目,项目命名为client。
打开窗口左侧目录下的app/mainifests下的AndroidMainfest.xml文件,添加以下两段代码:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
以上代码用于添加手机权限,结果如下图:
打开窗口左侧目录下的app/res/layout下的activity_main.xmll文件,然后进入到Design(可视化)界面,创建下图所示界面:
也可切换到Text(代码)界面,看到如下代码:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"tools:context=".MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="48dp"android:orientation="horizontal"><TextViewandroid:id="@+id/textView"android:layout_width="match_parent"android:layout_height="46dp"android:background="#FFFFFF"android:gravity="center"android:text="客户端"android:textSize="24sp"tools:background="#00B0FF" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#00E5FF"android:orientation="vertical"android:padding="15dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="服务端IP:"android:textSize="24sp" /><EditTextandroid:id="@+id/et_ip"android:layout_width="220dp"android:layout_height="wrap_content"android:ems="10"android:inputType="textPersonName"android:text="192.168.1.111"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="71dp"android:layout_weight="1"android:orientation="horizontal"><TextViewandroid:id="@+id/textView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="服务端端口:"android:textSize="24sp" /><EditTextandroid:id="@+id/et_port"android:layout_width="220dp"android:layout_height="wrap_content"android:ems="10"android:inputType="textPersonName"android:text="8888"android:textSize="24sp" /></LinearLayout><Buttonandroid:id="@+id/btn_connect"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="未连接"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="256dp"android:background="#00B0FF"android:orientation="vertical"android:padding="15dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="30dp"android:background="#00E5FF"android:orientation="horizontal"><TextViewandroid:id="@+id/textView4"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="占空比:"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="60dp"android:orientation="horizontal"><EditTextandroid:id="@+id/et_duty"android:layout_width="125dp"android:layout_height="wrap_content"android:ems="10"android:inputType="textPersonName"android:textSize="24sp" /><SeekBarandroid:id="@+id/sb_duty"style="@android:style/Widget.Material.SeekBar.Discrete"android:layout_width="match_parent"android:layout_height="44dp"android:max="1023"android:progress="1" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="30dp"android:orientation="horizontal"><TextViewandroid:id="@+id/textView6"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:background="#00E5FF"android:text="频率:"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="60dp"android:orientation="horizontal"><EditTextandroid:id="@+id/et_frq"android:layout_width="125dp"android:layout_height="wrap_content"android:ems="10"android:inputType="textPersonName"android:textSize="24sp" /><SeekBarandroid:id="@+id/sb_frq"style="@android:style/Widget.Material.SeekBar.Discrete"android:layout_width="match_parent"android:layout_height="44dp"android:max="100"android:progress="1" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="52dp"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_open"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="开"android:textSize="24sp" /><Buttonandroid:id="@+id/btn_close"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="关"android:textSize="24sp" /></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:background="#1DE9B6"android:orientation="vertical"android:padding="15dp"><TextViewandroid:id="@+id/textView5"android:layout_width="wrap_content"android:layout_height="30dp"android:gravity="center_vertical"android:text="服务端发回消息:"android:textSize="24sp" /><TextViewandroid:id="@+id/tv_recive"android:layout_width="match_parent"android:layout_height="46dp"android:background="#FFFFFF"android:textSize="24sp" /></LinearLayout></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
打开窗口左侧目录下的app/java/包名/MainActivity.java文件,输入如下代码:
package com.example.client;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {private Button btn_connect;private Button btn_open;private Button btn_close;private EditText et_ip;private EditText et_port;private EditText et_duty;private EditText et_frq;private TextView tv_recive;private SeekBar sb_duty;private SeekBar sb_frq;Handler handler;// 定义与服务器通信的子线程ClientThread clientthread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_connect=(Button)findViewById(R.id.btn_connect);btn_open=(Button)findViewById(R.id.btn_open);btn_close=(Button)findViewById(R.id.btn_close);et_ip=(EditText)findViewById(R.id.et_ip);et_port=(EditText)findViewById(R.id.et_port);tv_recive=(TextView)findViewById(R.id.tv_recive);sb_duty=(SeekBar)findViewById((R.id.sb_duty));et_duty=(EditText)findViewById(R.id.et_duty);sb_frq=(SeekBar)findViewById(R.id.sb_frq);et_frq=(EditText)findViewById(R.id.et_frq);//连接服务器btn_connect.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//获取ip和端口String ip=et_ip.getText().toString();String tmp=et_port.getText().toString();int port=Integer.parseInt(tmp);clientthread=new ClientThread(handler,ip,port); //定义客户端线程,传入handler,ip,portnew Thread(clientthread).start();}});//占空比滑条sb_duty.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {et_duty.setText(String.valueOf(progress));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {try{Message msg=new Message();msg.what=0x345;msg.obj="duty"+et_duty.getText().toString();clientthread.revHandler.sendMessage(msg);Log.d("发送数据",et_duty.getText().toString());}catch(Exception e){e.printStackTrace();}}});//频率滑条sb_frq.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {et_frq.setText(String.valueOf(progress));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {try{Message msg=new Message();msg.what=0x345;msg.obj="frq"+et_frq.getText().toString();clientthread.revHandler.sendMessage(msg);Log.d("发送数据",et_frq.getText().toString());}catch(Exception e){e.printStackTrace();}}});//开灯btn_open.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try{Message msg=new Message();msg.what=0x345; //消息号msg.obj="open"; //消息内容clientthread.revHandler.sendMessage(msg);Log.d("指令","开");}catch(Exception e){e.printStackTrace();}}});//关灯btn_close.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try{Message msg=new Message();msg.what=0x345;msg.obj="close";clientthread.revHandler.sendMessage(msg);Log.d("指令","关");}catch(Exception e){e.printStackTrace();}}});//处理接收到的数据handler=new Handler(){@Overridepublic void handleMessage(Message msg){Log.d("7777777",msg.obj.toString());if(msg.what==0x123){ //消息号tv_recive.setText(msg.obj.toString()); //消息内容if(msg.obj.toString().equals("connection ok")){ //判断字符串是否相等btn_connect.setBackgroundColor(Color.parseColor("#4CAF50"));btn_connect.setText("已连接");}}}};}
}
代码中的关键部分已经做了注释,这里就不多解释了。运行一下,结果如下图:
这就是我们的操作界面,接下来我们把重点转移到服务器端(ESP8266)程序的编写了。