Web控制51单片机的各个功能模块(按钮控制电机的启停)
按下 "ON" 按钮打开功能模块,按下 "OFF" 按钮关闭功能模块
Keil:
/* 串口通信: 1、由PC机通过串行口向单片机发送数据,这个数据是存放在单片机的接收缓冲器SBUF中的; 2、单片机将串行口中的数据存放在一个临时变量中; 3、单片机将存放在临时变量中的数据发送到发送缓冲器SBUF中,在PC机上显示。 */ #include <reg52.h> #define u16 unsigned int #define u8 unsigned char // 电机开关管脚 sbit moto = P1^0; u16 k; // 串行口通信初始化函数 void StartInit() { /* 1、确定T1的工作方式(编程TMOD寄存器):因为串行口中断是由定时器T1决定的, 所以,低四位全部为0,高四位中,GATE=0,C/T非=0,选择工作方式1(8位的自动重装载),即M1M0=10 所以是:00100000,转成十六进制数是:0x20 */ TMOD=0x20; /* 2、计算T1的初值,装载TH1、TL1:使用工具生成,设置参数,定时器方式:方式2;晶振频率:12Mhz; 波特率:4800;SMOD:波特率倍增位,1,即增加1倍;计算结果是:F3H 所以TH1=0xF3,TL1=0xF3,自动重装载 */ TH1=0xF3; TL1=0xF3; /* PCON:与串行口工作相关的参数,只有一位SMOD(最高位),在串行口方式1、方式2、方式3时, 波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0, 这里波特率提高一倍,所以SMOD=1,即10000000,转成十六进制数字是:0x80 */ PCON=0x80; /* 4、启动T1(编程TCON中的TR1位):TR1=1时,定时器T1才开始启动 */ TR1=1; /* 5、确定串行口控制(编程SCON寄存器):选择工作方式1(10位异步收发器,8位数据,1位起始位,1位停止位), 所以SM0=0,SM1=1;不需要RB8控制RI的激活(就是为了简单),设置SM2=0(SM2是多机通信控制位); REN,允许串行接收位,启动串行口接收数据,REN=1; TB8,RB8,TI,RI均为0(看资料),所以是:01010000,转成十六进制数是:0x50 */ SCON=0x50; /* 6、中断位的开启,总中断允许位EA=1;串行口中断允许位ES=1 */ EA=1; ES=1; } // ========================================= 电机模块 // 延迟函数,1ms void delay1ms(void) //误差 0us { unsigned char a,b,c; for(c=1;c>0;c--) for(b=142;b>0;b--) for(a=2;a>0;a--); } // 电机启动Xs void motoOnXs(u16 x) { u16 j = 1000*x; while(j>0) { moto = 1; delay1ms(); j--; } } // 电机停止Xs void motoOffXs(u16 x) { moto = 0; for(k=0; k<1000*x; k++) { delay1ms(); } } // 电机模块 void motoFun() { // 电机停止2s,启动5s为一个周期不断循环 while(1) { u16 flag; if(flag % 2 == 0) { // 电机停止2s motoOffXs(1.5); } else { // 电机启动5s motoOnXs(1); } // 改变变量的值 flag++; } } // 主函数 void main() { StartInit(); // 串行口通信初始化 while(1); // 等待数据的发送和接收 } // 发送或接收完一帧数据引起中断,串行口中断函数 void Start() interrupt 4 { u8 receiveData; // 用一个变量存放数据 receiveData=SBUF; // 从单片机的接收缓冲器中获取数据 RI=0; // 当数据接收完成后,由内部硬件将RI置1,所以这里需要把RI置0,等待下一次继续接收数据 SBUF=receiveData; // 把变量中的数据放到发送缓冲器中,向PC机发送数据 while(!TI); // 当数据发送完成后(即串行口在发送停止位时,由内部硬件将TI置1,所以数据发送完成时TI=1) TI=0; // 数据发送完成时,要将TI置0,等待下一次继续发送数据 // 其他子功能模块 if(receiveData=='1') { motoFun(); } }
JavaWEB:
下载RXTX-2.2-win-x64,目录:
(1)如果只是Java程序,只需要把rxtxParallel.dll和rxtxSerial.dll拷贝到jdk和jre的bin目录下,然后在Java工程中添加 RXTXcomm.jar 即可
(2)如果是WEB程序,要把rxtxParallel.dll和rxtxSerial.dll拷贝到tomcat安装目录下的bin目录下,然后在Java工程中添加 RXTXcomm.jar 即可
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Web控制51单片机的各个功能模块之案例测试</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> // 开启 function goON() { var parameterId = document.getElementById("parameterId"); parameterId.value = "on"; document.forms[0].submit(); } // 关闭 function goOFF() { var parameterId = document.getElementById("parameterId"); parameterId.value = "off"; document.forms[0].submit(); } </script> </head> <body> <h2>========= Web控制51单片机的各个功能模块之案例测试 =========</h2> 说明:按下 "ON" 按钮打开功能模块,按下 "OFF" 按钮关闭功能模块 <br><br> <form name="myForm" action="operator" method="post" style="margin-left: 200px;"> <input type="hidden" name="parameter" id="parameterId"/> <input type="hidden" name="on" value="1" readonly="readonly"/> <input type="button" value="ON" onclick="goON();"/> <input type="hidden" name="off" value="0" readonly="readonly"/> <input type="button" value="OFF" onclick="goOFF();"/> </form> </body> </html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>operator</servlet-name> <servlet-class>com.lvshitech.java51.server.MyServer</servlet-class> </servlet> <servlet-mapping> <servlet-name>operator</servlet-name> <url-pattern>/operator</url-pattern> </servlet-mapping> </web-app>
MyServer.java:
package com.lvshitech.java51.server; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.lvshitech.java51.tool.Tools; @SuppressWarnings("serial") public class MyServer extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取参数 String parameter = req.getParameter("parameter"); String on = req.getParameter("on"); String off = req.getParameter("off"); req.getRequestDispatcher("index.jsp").forward(req, resp); if(null==parameter || "".equals(parameter)) { System.out.println("接收到的参数为空!"); } else { if("on".equals(parameter)) { try { Tools.action(on); } catch (Exception e) { e.printStackTrace(); } } else { try { Tools.action(off); } catch (Exception e) { e.printStackTrace(); } } } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }
Tools.java:
package com.lvshitech.java51.tool; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; public class Tools { /*类方法 不可改变 不接受继承 * 扫描获取可用的串口 * 将可用串口添加至list并保存至list */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static final ArrayList<String> uartPortUseAblefind() { //获取当前所有可用串口 //由CommPortIdentifier类提供方法 Enumeration<CommPortIdentifier> portList=CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList=new ArrayList(); //添加并返回ArrayList while(portList.hasMoreElements()) { String portName=portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /* * 串口常见设置 * 1)打开串口 * 2)设置波特率 根据单板机的需求可以设置为57600 ... * 3)判断端口设备是否为串口设备 * 4)端口是否占用 * 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup() * 6)return:返回一个SerialPort一个实例对象,若判定该com口是串口则进行参数配置 * 若不是则返回SerialPort对象为null */ public static final SerialPort portParameterOpen(String portName,int baudrate) { SerialPort serialPort=null; try { //通过端口名识别串口 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打开端口并设置端口名字 serialPort和超时时间 2000ms CommPort commPort=portIdentifier.open(portName,1000); //进一步判断comm端口是否是串口 instanceof if(commPort instanceof SerialPort) { System.out.println("该COM端口是串口!串口名称是:" + portName); //进一步强制类型转换 serialPort=(SerialPort)commPort; //设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够 //8位数据位 //1位停止位 //无奇偶校验 serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); //串口配制完成 log System.out.println("串口参数设置已完成,波特率为"+baudrate+",数据位8bits,停止位1位,无奇偶校验"); } else { //不是串口 System.out.println("该com端口不是串口,请检查设备!"); //将com端口设置为null 默认是null不需要操作 } } catch (NoSuchPortException e) { e.printStackTrace(); } catch (PortInUseException e) { e.printStackTrace(); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); } return serialPort; } /* * 串口数据发送以及数据传输作为一个类 * 该类做主要实现对数据包的传输至下单板机 */ /* * 上位机往单板机通过串口发送数据 * 串口对象 seriesPort * 数据帧:dataPackage * 发送的标志:数据未发送成功抛出一个异常 */ public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage) { OutputStream out=null; try { out=serialPort.getOutputStream(); out.write(dataPackage); out.flush(); } catch (IOException e) { e.printStackTrace(); } finally { //关闭输出流 if(out!=null) { try { out.close(); out=null; //System.out.println("数据已发送完毕!"); } catch (IOException e) { e.printStackTrace(); } } } } /* * 上位机接收数据 * 串口对象seriesPort * 接收数据buffer * 返回一个byte数组 */ public static byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort) { byte[] receiveDataPackage=null; InputStream in=null; try { in=serialPort.getInputStream(); // 获取data buffer数据长度 int bufferLength=in.available(); while(bufferLength!=0) { receiveDataPackage=new byte[bufferLength]; in.read(receiveDataPackage); bufferLength=in.available(); } } catch (IOException e) { e.printStackTrace(); } return receiveDataPackage; } public static void action(String parameter) throws Exception { // 打开串口 SerialPort serialPort = portParameterOpen("COM3", 4800); // 要发送的数据 String dataSend = parameter; int i=1; //while(true) { // 发送数据到单片机 byte []datByte = dataSend.getBytes(); uartSendDatatoSerialPort(serialPort, datByte); System.out.println("-------------------------------------------------------"); System.out.println((i++) + ". 发送到串口的数据:" + dataSend); // 休眠500ms,等待单片机反应 Thread.sleep(500); // 从单片机接收到的数据 byte[] dat = uartReceiveDatafromSingleChipMachine(serialPort); if(dat != null && dat.length > 0) { String dataReceive = new String(dat, "GB2312"); System.out.println((i++) + ". 从串口接收的数据:" + dataReceive); } else { System.out.println("接收到的数据为空!"); } //} } }
运行,现象:
打开单片机,接上电机线,电机会不断转动,启动WEB工程,点击“ON”按钮,电机会转1秒,停1.5秒,这样不断循环下去
================================================ 控制电机的启停
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Web控制51单片机的各个功能模块之案例测试</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> // 开启 function goON() { var parameterId = document.getElementById("parameterId"); parameterId.value = "on"; document.forms[0].submit(); } // 关闭 function goOFF() { var parameterId = document.getElementById("parameterId"); parameterId.value = "off"; document.forms[0].submit(); } </script> </head> <body> <h2>========= Web控制51单片机的各个功能模块之案例测试 =========</h2> 说明:按下“电机启动”按钮电机开始转动,按下“电机停止”按钮电机停止转动 <br><br> <form name="myForm" action="operator" method="post" style="margin-left: 200px;"> <input type="hidden" name="parameter" id="parameterId"/> <input type="hidden" name="on" value="1" readonly="readonly"/> <input type="button" value="电机启动" onclick="goON();" style="font-size: 20px;"/> <input type="hidden" name="off" value="0" readonly="readonly"/> <input type="button" value="电机停止" onclick="goOFF();" style="font-size: 20px;"/> </form> </body> </html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>operator</servlet-name> <servlet-class>com.lvshitech.java51.server.MyServer</servlet-class> </servlet> <servlet-mapping> <servlet-name>operator</servlet-name> <url-pattern>/operator</url-pattern> </servlet-mapping> </web-app>
MyServer.java:
package com.lvshitech.java51.server; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.lvshitech.java51.tool.Tools; @SuppressWarnings("serial") public class MyServer extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取参数 String parameter = req.getParameter("parameter"); String on = req.getParameter("on"); String off = req.getParameter("off"); try { if(null==parameter || "".equals(parameter)) { System.out.println("接收到的参数为空!"); } else { if("on".equals(parameter)) { Tools.action(on); } else { Tools.action(off); } } } catch (Exception e) { e.printStackTrace(); } finally { Tools.closePort(); } req.getRequestDispatcher("index.jsp").forward(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }
Tools.java:
package com.lvshitech.java51.tool; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; public class Tools { public static SerialPort serialPort=null; /*类方法 不可改变 不接受继承 * 扫描获取可用的串口 * 将可用串口添加至list并保存至list */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static final ArrayList<String> uartPortUseAblefind() { //获取当前所有可用串口 //由CommPortIdentifier类提供方法 Enumeration<CommPortIdentifier> portList=CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList=new ArrayList(); //添加并返回ArrayList while(portList.hasMoreElements()) { String portName=portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /* * 串口常见设置 * 1)打开串口 * 2)设置波特率 根据单板机的需求可以设置为57600 ... * 3)判断端口设备是否为串口设备 * 4)端口是否占用 * 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup() * 6)return:返回一个SerialPort一个实例对象,若判定该com口是串口则进行参数配置 * 若不是则返回SerialPort对象为null */ public static final SerialPort portParameterOpen(String portName,int baudrate) { try { //通过端口名识别串口 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打开端口并设置端口名字 serialPort和超时时间 2000ms CommPort commPort=portIdentifier.open(portName,1000); //进一步判断comm端口是否是串口 instanceof if(commPort instanceof SerialPort) { System.out.println("该COM端口是串口!串口名称是:" + portName); //进一步强制类型转换 serialPort=(SerialPort)commPort; //设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够 //8位数据位 //1位停止位 //无奇偶校验 serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); //串口配制完成 log System.out.println("串口参数设置已完成,波特率为"+baudrate+",数据位8bits,停止位1位,无奇偶校验"); } else { //不是串口 System.out.println("该com端口不是串口,请检查设备!"); //将com端口设置为null 默认是null不需要操作 } } catch (NoSuchPortException e) { e.printStackTrace(); } catch (PortInUseException e) { e.printStackTrace(); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); } return serialPort; } /* * 串口数据发送以及数据传输作为一个类 * 该类做主要实现对数据包的传输至下单板机 */ /* * 上位机往单板机通过串口发送数据 * 串口对象 seriesPort * 数据帧:dataPackage * 发送的标志:数据未发送成功抛出一个异常 */ public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage) { OutputStream out=null; try { out=serialPort.getOutputStream(); out.write(dataPackage); out.flush(); } catch (IOException e) { e.printStackTrace(); } finally { //关闭输出流 if(out!=null) { try { out.close(); out=null; //System.out.println("数据已发送完毕!"); } catch (IOException e) { e.printStackTrace(); } } } } /* * 上位机接收数据 * 串口对象seriesPort * 接收数据buffer * 返回一个byte数组 */ public static byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort) { byte[] receiveDataPackage=null; InputStream in=null; try { in=serialPort.getInputStream(); // 获取data buffer数据长度 int bufferLength=in.available(); while(bufferLength!=0) { receiveDataPackage=new byte[bufferLength]; in.read(receiveDataPackage); bufferLength=in.available(); } } catch (IOException e) { e.printStackTrace(); } return receiveDataPackage; } public static void action(String parameter) throws Exception { // 打开串口 SerialPort serialPort = portParameterOpen("COM3", 4800); // 要发送的数据 String dataSend = parameter; int i=1; //while(true) { // 发送数据到单片机 byte []datByte = dataSend.getBytes(); uartSendDatatoSerialPort(serialPort, datByte); System.out.println("-------------------------------------------------------"); System.out.println((i++) + ". 发送到串口的数据:" + dataSend); // 休眠500ms,等待单片机反应 Thread.sleep(500); // 从单片机接收到的数据 byte[] dat = uartReceiveDatafromSingleChipMachine(serialPort); if(dat != null && dat.length > 0) { String dataReceive = new String(dat, "GB2312"); System.out.println((i++) + ". 从串口接收的数据:" + dataReceive); } else { System.out.println("接收到的数据为空!"); } //} } /** * 关闭串口 * @param serialport 待关闭的串口对象 */ public static void closePort() { if (serialPort != null) { serialPort.close(); serialPort = null; } } }
单片机程序keil:
/* 串口通信: 1、由PC机通过串行口向单片机发送数据,这个数据是存放在单片机的接收缓冲器SBUF中的; 2、单片机将串行口中的数据存放在一个临时变量中; 3、单片机将存放在临时变量中的数据发送到发送缓冲器SBUF中,在PC机上显示。 */ #include <reg52.h> #define u16 unsigned int #define u8 unsigned char // 电机开关管脚 sbit moto = P1^0; u16 k; // 串行口通信初始化函数 void StartInit() { /* 1、确定T1的工作方式(编程TMOD寄存器):因为串行口中断是由定时器T1决定的, 所以,低四位全部为0,高四位中,GATE=0,C/T非=0,选择工作方式1(8位的自动重装载),即M1M0=10 所以是:00100000,转成十六进制数是:0x20 */ TMOD=0x20; /* 2、计算T1的初值,装载TH1、TL1:使用工具生成,设置参数,定时器方式:方式2;晶振频率:12Mhz; 波特率:4800;SMOD:波特率倍增位,1,即增加1倍;计算结果是:F3H 所以TH1=0xF3,TL1=0xF3,自动重装载 */ TH1=0xF3; TL1=0xF3; /* PCON:与串行口工作相关的参数,只有一位SMOD(最高位),在串行口方式1、方式2、方式3时, 波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0, 这里波特率提高一倍,所以SMOD=1,即10000000,转成十六进制数字是:0x80 */ PCON=0x80; /* 4、启动T1(编程TCON中的TR1位):TR1=1时,定时器T1才开始启动 */ TR1=1; /* 5、确定串行口控制(编程SCON寄存器):选择工作方式1(10位异步收发器,8位数据,1位起始位,1位停止位), 所以SM0=0,SM1=1;不需要RB8控制RI的激活(就是为了简单),设置SM2=0(SM2是多机通信控制位); REN,允许串行接收位,启动串行口接收数据,REN=1; TB8,RB8,TI,RI均为0(看资料),所以是:01010000,转成十六进制数是:0x50 */ SCON=0x50; /* 6、中断位的开启,总中断允许位EA=1;串行口中断允许位ES=1 */ EA=1; ES=1; } // ========================================= 电机模块 // 延迟函数,1ms void delay1ms(void) //误差 0us { unsigned char a,b,c; for(c=1;c>0;c--) for(b=142;b>0;b--) for(a=2;a>0;a--); } // 电机启动Xs //void motoOnXs(u16 x) void motoOnXs() { moto = 1; /* u16 j = 1000*x; while(j>0) { moto = 1; delay1ms(); j--; } */ } // 电机停止Xs //void motoOffXs(u16 x) void motoOffXs() { moto = 0; /* for(k=0; k<1000*x; k++) { delay1ms(); }*/ } // 电机模块 void motoFun() { // 电机停止2s,启动5s为一个周期不断循环 while(1) { u16 flag; if(flag % 2 == 0) { // 电机停止 motoOffXs(); } else { // 电机启动 motoOnXs(); } // 改变变量的值 flag++; } } // 主函数 void main() { StartInit(); // 串行口通信初始化 while(1); // 等待数据的发送和接收 } // 发送或接收完一帧数据引起中断,串行口中断函数 void Start() interrupt 4 { u8 receiveData; // 用一个变量存放数据 receiveData=SBUF; // 从单片机的接收缓冲器中获取数据 RI=0; // 当数据接收完成后,由内部硬件将RI置1,所以这里需要把RI置0,等待下一次继续接收数据 SBUF=receiveData; // 把变量中的数据放到发送缓冲器中,向PC机发送数据 while(!TI); // 当数据发送完成后(即串行口在发送停止位时,由内部硬件将TI置1,所以数据发送完成时TI=1) TI=0; // 数据发送完成时,要将TI置0,等待下一次继续发送数据 // 其他子功能模块 if(receiveData=='1') { //motoFun(); motoOnXs(); } else { motoOffXs(); } }
实验现象:按下启动按钮,电机启动,按下停止按钮,电机停止!