程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(1)

Android Studio设计APP实现与51单片机通过WIFI模块(ESP8266-01S)通讯控制LED灯亮灭的设计源码【详解】

发布于2022-06-25 18:33     阅读(516)     评论(0)     点赞(13)     收藏(3)


目录

一、前言

二、效果展示

1、APP界面展示

 2、C51硬件展示

三、Android Studio APP源代码

1、AndroidManifest.xml

1、请求联网:

2、开放明文传输:

2、MainActivity.java

3、Layout页面布局文件 activity_main.xml

四、Keil C51单片机源码

五、WIFI模块(ESP8266-01S)注意事项

六、后述     

一、前言

        本文将详细介绍如何利用Android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,本人也是新手刚入门,找了很多资料,但都不得要领,最后终于靠着摸索学习实现了手机与C51模块的WIFI通讯,特来与大家分享,希望对各位能有所帮助。废话不多说,先看效果。

二、效果展示

1、APP界面展示

36df57fcdb6a4eb8ae422fcc8ae46535.gif

 2、C51硬件展示

4fb11a2edbd246d394959b9921674597.gif

 

        可以看到,该APP基本实现了手机与C51单片机之间的WIFI通讯,手机端可以发送和接收数据,可以选择直接给WIFI发送数据,也可以将发送的数据的发送代码固化为按键,比如我上面的四个LED按键其实底层代码就是按下分别发送“1”、“2”、“3”、“4”来控制四个灯的亮灭。本app只是用来实验手机与C51单片机之间的WIFI通讯,目前来说算是成功了,后续可以通过修改调用该程序实现更复杂的内容,目前我也在朝着这个方向努力`(*>﹏<*)′

 

三、Android Studio APP源代码

1、AndroidManifest.xml

首先需要联网别忘了给 Android 添加网络连接权限:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. package="com.example.tcp_led">
  5. <uses-permission android:name="android.permission.INTERNET"/> //需要对WiFi进行操作,所以需要设置网络权限
  6. <application
  7. android:usesCleartextTraffic="false" //开放明文传输
  8. android:allowBackup="true"
  9. android:icon="@drawable/bh"
  10. android:label="@string/app_name"
  11. android:roundIcon="@drawable/bh_round"
  12. android:supportsRtl="true"
  13. android:theme="@style/Theme.TCP_LED"
  14. tools:ignore="UnusedAttribute">
  15. <activity
  16. android:name=".MainActivity"
  17. android:exported="true">
  18. <intent-filter>
  19. <action android:name="android.intent.action.MAIN" />
  20. <category android:name="android.intent.category.LAUNCHER" />
  21. </intent-filter>
  22. </activity>
  23. </application>
  24. </manifest>

1、请求联网:

 <uses-permission android:name="android.permission.INTERNET"/>

2、开放明文传输:

android:usesCleartextTraffic="false"

2、MainActivity.java

  1. package com.example.tcp_led;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.Button;
  6. import android.widget.EditText;
  7. import android.widget.TextView;
  8. import android.widget.Toast;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.OutputStream;
  12. import java.net.Socket;
  13. import java.net.UnknownHostException;
  14. public class MainActivity extends AppCompatActivity {
  15. String a;
  16. int b;
  17. connectthread lianjie;
  18. TextView receive;
  19. Socket socket=null;
  20. Button connect;
  21. @Override
  22. protected void onCreate(Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. setContentView(R.layout.activity_main);
  25. EditText ip=findViewById(R.id.mEtIP);
  26. EditText port=findViewById(R.id.mEtPort);
  27. EditText out=findViewById(R.id.mEtOut);
  28. receive=findViewById(R.id.receive);
  29. connect=findViewById(R.id.mBt1);
  30. Button send=findViewById(R.id.mBt7);
  31. Button LED1=findViewById(R.id.mBt3);
  32. Button LED2=findViewById(R.id.mBt4);
  33. Button LED3=findViewById(R.id.mBt5);
  34. Button LED4=findViewById(R.id.mBt6);
  35. Button Clear=findViewById(R.id.mBt8);
  36. // 连接 按键底层代码
  37. connect.setOnClickListener(new View.OnClickListener() {
  38. @Override
  39. public void onClick(View v) {
  40. a=ip.getText().toString();
  41. String c=port.getText().toString();
  42. if("".equals(a)||"".equals(c)){
  43. Toast.makeText(MainActivity.this,"请输入ip和端口号",Toast.LENGTH_SHORT).show();
  44. receive.append("请输入ip和端口号" + "\r\n");
  45. }
  46. else{b=Integer.parseInt(c);
  47. lianjie=new connectthread();
  48. lianjie.start();}
  49. }
  50. });
  51. // 发送数据 按键底层代码
  52. send.setOnClickListener(new View.OnClickListener() {
  53. @Override
  54. public void onClick(View v) {
  55. //子线程中进行网络操作
  56. new Thread(new Runnable() {
  57. @Override
  58. public void run() {
  59. if(socket!=null){
  60. try {
  61. String text=out.getText().toString();
  62. lianjie.outputStream.write(text.getBytes());
  63. } catch (IOException e) {
  64. // TODO Auto-generated catch block
  65. e.printStackTrace();
  66. }
  67. }else{
  68. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  69. {
  70. public void run()
  71. {
  72. // TODO Auto-generated method stub
  73. Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
  74. receive.append("请先建立连接" + "\r\n");
  75. }
  76. });
  77. }
  78. }
  79. }).start();
  80. }
  81. });
  82. // LED1 按键底层代码 其实就是发送数据按键代码基础上修改的,后面三个按键都是
  83. LED1.setOnClickListener(new View.OnClickListener() {
  84. @Override
  85. public void onClick(View v) {
  86. //子线程中进行网络操作
  87. new Thread(new Runnable() {
  88. @Override
  89. public void run() {
  90. if(socket!=null){
  91. try {
  92. String text="1";
  93. lianjie.outputStream.write(text.getBytes());
  94. } catch (IOException e) {
  95. // TODO Auto-generated catch block
  96. e.printStackTrace();
  97. }
  98. }else{
  99. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  100. {
  101. public void run()
  102. {
  103. // TODO Auto-generated method stub
  104. Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
  105. receive.append("请先建立连接" + "\r\n");
  106. }
  107. });
  108. }
  109. }
  110. }).start();
  111. }
  112. });
  113. // LED2 按键底层代码
  114. LED2.setOnClickListener(new View.OnClickListener() {
  115. @Override
  116. public void onClick(View v) {
  117. //子线程中进行网络操作
  118. new Thread(new Runnable() {
  119. @Override
  120. public void run() {
  121. if(socket!=null){
  122. try {
  123. String text="2";
  124. lianjie.outputStream.write(text.getBytes());
  125. } catch (IOException e) {
  126. // TODO Auto-generated catch block
  127. e.printStackTrace();
  128. }
  129. }else{
  130. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  131. {
  132. public void run()
  133. {
  134. // TODO Auto-generated method stub
  135. Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
  136. receive.append("请先建立连接" + "\r\n");
  137. }
  138. });
  139. }
  140. }
  141. }).start();
  142. }
  143. });
  144. // LED3 按键底层代码
  145. LED3.setOnClickListener(new View.OnClickListener() {
  146. @Override
  147. public void onClick(View v) {
  148. //子线程中进行网络操作
  149. new Thread(new Runnable() {
  150. @Override
  151. public void run() {
  152. if(socket!=null){
  153. try {
  154. String text="3";
  155. lianjie.outputStream.write(text.getBytes());
  156. } catch (IOException e) {
  157. // TODO Auto-generated catch block
  158. e.printStackTrace();
  159. }
  160. }else{
  161. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  162. {
  163. public void run()
  164. {
  165. // TODO Auto-generated method stub
  166. Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
  167. receive.append("请先建立连接" + "\r\n");
  168. }
  169. });
  170. }
  171. }
  172. }).start();
  173. }
  174. });
  175. // LED4 按键底层代码
  176. LED4.setOnClickListener(new View.OnClickListener() {
  177. @Override
  178. public void onClick(View v) {
  179. //子线程中进行网络操作
  180. new Thread(new Runnable() {
  181. @Override
  182. public void run() {
  183. if(socket!=null){
  184. try {
  185. String text="4";
  186. lianjie.outputStream.write(text.getBytes());
  187. } catch (IOException e) {
  188. // TODO Auto-generated catch block
  189. e.printStackTrace();
  190. }
  191. }else{
  192. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  193. {
  194. public void run()
  195. {
  196. // TODO Auto-generated method stub
  197. Toast.makeText(MainActivity.this,"请先建立连接",Toast.LENGTH_SHORT).show();
  198. receive.append("请先建立连接" + "\r\n");
  199. }
  200. });
  201. }
  202. }
  203. }).start();
  204. }
  205. });
  206. Clear.setOnClickListener(new View.OnClickListener() {
  207. @Override
  208. public void onClick(View view) {
  209. receive.setText("");
  210. }
  211. });
  212. // onCreate
  213. }
  214. //子线程中进行网络相关操作
  215. // 联网子线程
  216. class connectthread extends Thread {
  217. OutputStream outputStream=null;
  218. InputStream inputStream=null;
  219. @SuppressWarnings("InfiniteLoopStatement")
  220. @Override
  221. public void run() {
  222. //连接
  223. try {
  224. socket=new Socket(a, b);
  225. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  226. {
  227. public void run()
  228. {
  229. // TODO Auto-generated method stub
  230. Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
  231. receive.append("连接成功" + "\r\n");
  232. }
  233. });
  234. } catch (UnknownHostException e) {
  235. // TODO Auto-generated catch block
  236. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  237. {
  238. public void run()
  239. {
  240. // TODO Auto-generated method stub
  241. Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
  242. receive.append("连接失败" + "\r\n");
  243. }
  244. });
  245. e.printStackTrace();
  246. }catch (IOException e) {
  247. e.printStackTrace();
  248. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  249. {
  250. public void run()
  251. {
  252. // TODO Auto-generated method stub
  253. Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
  254. receive.append("连接失败" + "\r\n");
  255. }
  256. });
  257. }
  258. if(socket!=null){
  259. //获取输出流对象
  260. try {
  261. outputStream=socket.getOutputStream();
  262. outputStream.write(123);
  263. } catch (IOException e) {
  264. e.printStackTrace();
  265. }
  266. try{
  267. do {
  268. final byte[] buffer = new byte[1024];//创建接收缓冲区
  269. inputStream = socket.getInputStream();
  270. final int len = inputStream.read(buffer);//数据读出来,并且返回数据的长度
  271. runOnUiThread(new Runnable()//不允许其他线程直接操作组件,用提供的此方法可以
  272. {
  273. public void run() {
  274. // TODO Auto-generated method stub
  275. receive.append(new String(buffer, 0, len) + "\r\n");
  276. }
  277. });
  278. } while (true);
  279. }
  280. catch (IOException ignored) {
  281. }
  282. }
  283. }
  284. }
  285. // MainActivity
  286. }

3、Layout页面布局文件 activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity"
  8. android:background="#f1f3f4">
  9. <LinearLayout
  10. android:layout_width="match_parent"
  11. android:layout_height="wrap_content"
  12. android:orientation="vertical">
  13. <TextView
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:text="TCP客户端"
  17. android:textSize="50dp"
  18. android:background="#ffffff"
  19. android:gravity="center"
  20. />
  21. <EditText
  22. android:id="@+id/mEtIP"
  23. android:layout_width="300dp"
  24. android:layout_height="wrap_content"
  25. android:inputType="textWebEditText"
  26. android:hint="请输入服务器IP"
  27. android:drawableStart="@drawable/ic_tree"
  28. android:drawablePadding="20dp"
  29. android:layout_gravity="center"
  30. android:textSize="20sp"
  31. android:autofillHints="" />
  32. <!--端口 -->
  33. <EditText
  34. android:id="@+id/mEtPort"
  35. android:layout_width="300dp"
  36. android:layout_height="wrap_content"
  37. android:inputType="date"
  38. android:hint="请输入服务器端口"
  39. android:drawableStart="@drawable/ic_tree"
  40. android:drawablePadding="20dp"
  41. android:layout_gravity="center"
  42. android:textSize="20sp"
  43. android:autofillHints="" />
  44. <!--发送 -->
  45. <EditText
  46. android:id="@+id/mEtOut"
  47. android:layout_width="300dp"
  48. android:layout_height="wrap_content"
  49. android:inputType="date"
  50. android:hint="请输入发送数据"
  51. android:drawableStart="@drawable/ic_tree"
  52. android:drawablePadding="20dp"
  53. android:layout_gravity="center"
  54. android:textSize="20sp"
  55. android:autofillHints="" />
  56. <LinearLayout
  57. android:layout_width="match_parent"
  58. android:layout_height="wrap_content"
  59. android:orientation="horizontal"
  60. android:gravity="center">
  61. <Button
  62. android:id="@+id/mBt1"
  63. android:layout_width="wrap_content"
  64. android:layout_height="wrap_content"
  65. android:text="连接"
  66. tools:ignore="UsingOnClickInXml" />
  67. <Button
  68. android:id="@+id/mBt7"
  69. android:layout_width="wrap_content"
  70. android:layout_height="wrap_content"
  71. android:text="发送数据"
  72. tools:ignore="UsingOnClickInXml" />
  73. <Button
  74. android:id="@+id/mBt8"
  75. android:layout_width="wrap_content"
  76. android:layout_height="wrap_content"
  77. android:text="清除"
  78. tools:ignore="UsingOnClickInXml" />
  79. </LinearLayout>
  80. <LinearLayout
  81. android:layout_width="match_parent"
  82. android:layout_height="wrap_content"
  83. android:orientation="horizontal"
  84. android:gravity="center">
  85. <Button
  86. android:id="@+id/mBt3"
  87. android:layout_width="wrap_content"
  88. android:layout_height="wrap_content"
  89. android:text="LED1"
  90. tools:ignore="UsingOnClickInXml" />
  91. <Button
  92. android:id="@+id/mBt4"
  93. android:layout_width="wrap_content"
  94. android:layout_height="wrap_content"
  95. android:text="LED2"
  96. tools:ignore="UsingOnClickInXml" />
  97. <Button
  98. android:id="@+id/mBt5"
  99. android:layout_width="wrap_content"
  100. android:layout_height="wrap_content"
  101. android:text="LED3"
  102. tools:ignore="UsingOnClickInXml" />
  103. <Button
  104. android:id="@+id/mBt6"
  105. android:layout_width="wrap_content"
  106. android:layout_height="wrap_content"
  107. android:text="LED4"
  108. tools:ignore="UsingOnClickInXml" />
  109. </LinearLayout>
  110. <TextView
  111. android:id="@+id/receive"
  112. android:layout_width="wrap_content"
  113. android:layout_height="wrap_content" />
  114. </LinearLayout>
  115. </LinearLayout>

布局预览:

ac40dc883e7944d186c14943b6515612.png

        如此app上位机端操作就基本大功告成了,接下来就是下位机C51方面的程序了。 

四、Keil C51单片机源码

  1. #include "reg51.h"
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. sbit SW1=P1^0; //S1按键
  5. sbit LED1=P1^1;
  6. sbit LED2=P1^2;
  7. sbit LED3=P1^3;
  8. sbit LED4=P1^4;
  9. //ESP8266 EN、vcc脚接 vcc 3.3 GND 接地,必须和51共地
  10. //ESP8266 TX 接P3^0, RX 接P3^1
  11. bit flag=0;
  12. uchar SendBuf[9]="LED1 ON! ";
  13. uchar RecBuf[15];
  14. uchar RecNum=0;
  15. void delay_10us(uint us); //延时
  16. void delay(uint n); //延时
  17. void UART_Init();
  18. void UART_SendByte(uchar dat);
  19. void ESP8266_SendCmd(uchar *pbuf);
  20. void ESP8266_SendData(uchar *pbuf);
  21. void ESP8266_ModeInit(void); //WIFI模块初始化
  22. void UART_Irq( ); // 接收信号
  23. void delay_10us(uint us)
  24. {
  25. while(us--);
  26. }
  27. void delay(uint n)
  28. {
  29. uint i,j;
  30. for(i=0;i<n;i++)
  31. for(j=0;j<100;j++);
  32. }
  33. void UART_Init()
  34. {
  35. SCON=0X50; //串口:工作方式1
  36. TMOD=0X20; //定时器:工作方式2
  37. TH1=0xFD; //波特率:9600
  38. TL1=0xFD;
  39. ES=0; //禁止串口中断
  40. EA=1; //使能总中断
  41. TR1=1; //启动计数器
  42. }
  43. void UART_SendByte(uchar dat)
  44. {
  45. ES=0; //禁止串口中断
  46. SBUF=dat; //串口发送
  47. while(TI==0); //等待发送结束
  48. TI=0; //发送标志位清零
  49. ES=1; //使能串口中断
  50. }
  51. void ESP8266_SendCmd(uchar *pbuf)
  52. {
  53. while(*pbuf!='\0') //遇到空格跳出循环
  54. {
  55. UART_SendByte(*pbuf);
  56. delay_10us(5);
  57. pbuf++;
  58. }
  59. delay_10us(5);
  60. UART_SendByte('\r'); //回车
  61. delay_10us(5);
  62. UART_SendByte('\n'); //换行
  63. delay(1000);
  64. }
  65. void ESP8266_SendData(uchar *pbuf)
  66. {
  67. uchar i=0;
  68. ESP8266_SendCmd("AT+CIPSEND=0,9"); //发送数据:AT+CIPSEND=<id>,<length>
  69. for(i=0;i<=8;i++)
  70. {
  71. UART_SendByte(*pbuf);
  72. delay_10us(5);
  73. pbuf++;
  74. }
  75. }
  76. void ESP8266_ModeInit(void) //WIFI模块初始化
  77. {
  78. ESP8266_SendCmd("AT+CWMODE=3"); //设置路由器模式 1:Station,,2:AP,3:Station+AP
  79. ESP8266_SendCmd("AT+CWSAP=\"百行\",\"12345678\",11,0"); //设置WIFI热点名称及密码
  80. ESP8266_SendCmd("AT+CIPAP=\"192.168.4.2\""); //设置AP的IP地址
  81. ESP8266_SendCmd("AT+RST"); //重新启动wifi模块
  82. ESP8266_SendCmd("AT+CIPMUX=1"); //开启多连接模式
  83. ESP8266_SendCmd("AT+CIPSERVER=1,8080"); //启动TCP/IP 端口为8080
  84. }
  85. void main()
  86. {
  87. P1=0x01;
  88. while(SW1); //等待S1键按下
  89. LED1=LED2=LED3=LED4=1;
  90. UART_Init(); //串口初始化
  91. ESP8266_ModeInit();
  92. ES=1; //允许串口中断
  93. while(1)
  94. {
  95. if(flag==1)
  96. {
  97. flag = 0;
  98. ESP8266_SendData(SendBuf);
  99. }
  100. delay(10);
  101. }
  102. }
  103. void UART_Irq( ) interrupt 4 // 接收信号
  104. {
  105. if(RI)
  106. {
  107. RI=0;
  108. RecBuf[RecNum]=SBUF; //接收到网络数据:+IPD,0<id>,1<数据长度>:F<接收的数据>
  109. if(RecBuf[0]=='+')
  110. RecNum++;
  111. else
  112. RecNum=0;
  113. if(RecNum==10)
  114. {
  115. RecNum=0;
  116. if(RecBuf[0]=='+'&&RecBuf[1]=='I'&&RecBuf[2]=='P'&&RecBuf[3]=='D')
  117. {
  118. switch(RecBuf[9])
  119. {
  120. case '1': P1 = 0xfD;break;
  121. case '2': P1 = 0xfB;break;
  122. case '3': P1 = 0xf7;break;
  123. case '4': P1 = 0xef;break;
  124. default:P1 = 0xe0;
  125. }
  126. SendBuf[3] = RecBuf[9];
  127. flag = 1;
  128. }
  129. }
  130. }
  131. }

五、WIFI模块(ESP8266-01S)注意事项

        相比于编写代码,硬件方面就简单多了,就是有一些需要格外注意的事项,也是我在实践中遇到的问题,现在分享给大家。

d6b66b16c77141bca296837fe0db63d5.png

ESP8266-01S WIFI模块接线
                    TXRXD(P3^0)
                    RXTXD(P3^1)
                    EN3.3V
                    VCC3.3V
                    GNDGND

        这里需要特别注意在TX和RX中,TX代表WIFI模块发送数据,应该和单片机串行数据接收端RXD相连接,RX代表WIFI模块接受数据,应该和单片机串行数据发送端TXD相连接。EN、VCC必须接3.3V电源,另外WIFI模块工作时会发热,属于正常情况。GND接地需要特别注意,WIFI模块必须和51单片机共地,否则单片机将无法正常读取数据。其他引脚悬空就可以了,也就是说WIFI模块只需和51连接三根线即可,两根串行数据线,一根共地线。

六、后述
      

         以上就是今天要讲的内容,本文简单介绍了如何利用Android Studio设计 APP 实现与C51单片机通过WIFI模块通讯控制LED灯亮灭,由于本人也是刚开始学习,本文还有很多不足的地方,目前我的程序也还在开发中,后续我会随时更新文章中不足的部分,欢迎各位有需要的订阅我的这个专栏获取最新内容。

代码已开源:(其实以上就是全部内容了)

Github 源码资源免费下载https://github.com/SHUGEX/TCP_LED

CSDN 源码资源积分下载https://download.csdn.net/download/weixin_45694843/85238966

 

 

 

原文链接:https://blog.csdn.net/weixin_45694843/article/details/124486464



所属网站分类: 技术文章 > 博客

作者:java战神

链接:http://www.javaheidong.com/blog/article/465154/6f7b96649a6b442d5757/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

13 0
收藏该文
已收藏

评论内容:(最多支持255个字符)