一、系統方案 手機APP通過ESP8266 WIFI模塊與51單片機通信控制LED燈、蜂鳴器的開關。下位機由單片機、ESP8266模塊和LED燈組成,上位機由Android手機APP承擔。我們在APP上發送LED燈、蜂鳴器的開關控制指令,ESP8266將收到的數據發送給單片機,從而實現對LED燈、蜂鳴器進行開關控制。 設計好的實物是這個樣子: 二、硬件設計
ESP8266模塊作為一個透傳模塊使用,RXD、TXD分別連接51單片機的TXD和RXD,VCC接3.3V電壓,GND接地,只需要連接這些管腳,ESP8266模塊就可以正常工作了。在單片機P16口上連接蜂鳴器、P26、P27連接兩個3mm的LED燈,我們的目的是通過手機APP上的開關控制著LED燈的亮滅以及蜂鳴器打開與關閉。
原理圖如下: 三、單片機軟件設計 硬件的連接不復雜,接下來主要是單片機和手機APP代碼的編寫。 單片機代碼主要是串口初始化、串口中斷和ESP8266的初始化。首先是串口初始化: TMOD=0x20; //定時器1工作在方式2 TH1 = 0xfd; //波特率9600 TL1 = 0xfd; SM0=0; //串口工作在方式1 SM1=1; EA = 1; //開總中斷 REN = 1; //使能串口 TR1 = 1; //定時器1開始計時 然后是ESP8266初始化:
delayms(1000); //延時 sendString("AT+CWMODE=2\r\n"); //設置ESP8266工作在AP模式下 delayms(1000); sendString("AT+CIPMUX=1\r\n"); //允許多連接 delayms(1000); sendString("AT+CIPSERVER=1,8080\r\n"); //建立服務器 delayms(1000); ES = 1; //esp8266初始化之后開串口中斷 貼上51單片機負責串口發送的兩個函數:
//發送一個字節 void sendChar(uchar a) { SBUF = a; while(TI==0); TI=0; } //發送字符串 void sendString(uchar *s) { while(*s!='\0') { sendChar(*s); s++; }
}
在串口中斷中處理接收到的數據: 1:打開蜂鳴器 2:關閉蜂鳴器 3:打開紅燈 4:關閉紅燈 5:打開綠燈 6:關閉綠燈 esp8266在收到數據并轉發給單片機時的數據格式:+IPD,<client號>,<收到的字符長度>:收到的字符,比如+IPD,0,5:hello,其中+PID是固定的;0代表的是TCP客戶端編號,esp8266最多支持5個客戶端同時連接,也就是說客戶端編號是0到4,在本設計中由于只有一個客戶端與esp8266相連,所以客戶端編號是0;5代表收到的字符長度;hello是收到的字符。在本例中esp8266發送給單片機的數據是+IPD,0,1:1,我們把接收到的字符串緩存到字符數組中,所以在處理收到的數據邏輯中,首先判斷是否是以'+'開始的,否則視作無效數據,然后判斷數組中的第十個數據,因為第十個數據才是手機APP發送過來的數據。 void uart() interrupt 4 { if(RI == 1) { RI = 0; //清除串口接收標志位 receiveTable=SBUF; if(receiveTable[0]=='+') { i++; } else { i=0; } if(i==10) { i=0; switch(receiveTable[9]) { case '1': BEEP=0; break; case '2': BEEP=1; break; case '3': RedLED=0; break; case '4': RedLED=1; break; case '5': GreenLED=0; break; case '6': GreenLED=1; break; } }
} }
四、Android APP軟件設計 Android APP是借助Android Studio來開發的,界面比較簡單,通過編輯框輸入esp8266的IP地址和端口號,esp8266默認的IP地址是192.168.4.1,端口號是8080,這些都可以通過AT指令進行修改。布局頁面的xml代碼我們就不貼了,熟悉Android開發的讀者很快就能根據截圖編寫出來,放上一個APP界面的截圖:
我們主要看一下邏輯代碼部分: 首先是控件的初始化和按鈕點擊事件回調的綁定 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtnConnect = (Button) findViewById(R.id.btn_connect); mEtIP = (EditText) findViewById(R.id.et_ip); mEtPort = (EditText) findViewById(R.id.et_port); mBtnRedOn = (Button) findViewById(R.id.btn_red_on); mBtnRedOff = (Button) findViewById(R.id.btn_red_off); mBtnYellowOn = (Button) findViewById(R.id.btn_yellow_on); mBtnYellowOff = (Button) findViewById(R.id.btn_yellow_off); mBtnBlueOn = (Button) findViewById(R.id.btn_blue_on); mBtnBlueOff = (Button) findViewById(R.id.btn_blue_off); mBtnConnect.setOnClickListener(this); mBtnRedOn.setOnClickListener(this); mBtnRedOff.setOnClickListener(this); mBtnYellowOn.setOnClickListener(this); mBtnYellowOff.setOnClickListener(this); mBtnBlueOn.setOnClickListener(this); mBtnBlueOff.setOnClickListener(this); } 按鈕的點擊回調方法: public void onClick(View v) { switch (v.getId()) { case R.id.btn_connect: //連接 if (mSocket == null || !mSocket.isConnected()) { String ip = mEtIP.getText().toString(); int port = Integer.valueOf(mEtPort.getText().toString()); mConnectThread = new ConnectThread(ip, port); mConnectThread.start(); } if (mSocket != null && mSocket.isConnected()) { try { mSocket.close(); mBtnConnect.setText("連接"); } catch (IOException e) { e.printStackTrace(); } }
break; case R.id.btn_red_on: if (out != null) { out.print("1"); out.flush(); } break; case R.id.btn_red_off: if (out != null) { out.print("2"); out.flush(); } break; case R.id.btn_yellow_on: if (out != null) { out.print("3"); out.flush(); } break; case R.id.btn_yellow_off: if (out != null) { out.print("4"); out.flush(); } break; case R.id.btn_blue_on: if (out != null) { out.print("5"); out.flush(); } break; case R.id.btn_blue_off: if (out != null) { out.print("6"); out.flush(); } break; } }
負責連接esp8266的線程:
private class ConnectThread extends Thread { private String ip; private int port; public ConnectThread(String ip, int port) { this.ip = ip; this.port = port; }
@Override public void run() { try { mSocket = new Socket(ip, port); out = new PrintStream(mSocket.getOutputStream()); runOnUiThread(new Runnable() { @Override public void run() { mBtnConnect.setText("斷開"); } }); new HeartBeatThread().start(); } catch (IOException e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "連接失敗", Toast.LENGTH_SHORT).show(); } }); } } }
|