zoukankan      html  css  js  c++  java
  • android之WIFI小车编程详述

    有了前几篇wifi模块eps8266的使用,单片机设置eps8266程序,android TCP客户端,现在就做一个wifi小车

    先上图

    小车是四个轮子的,每个轮子上都有电机驱动,前进后退的时候四个轮子同时前进和后退,转弯的时候,小车两边的轮子按反方向转。

    为了达到更好的操作效果(一直按下前进,小车前进,按下左右转小车左右转,松开左右转,小车继续前进。松开前进,小车停止。后退同理),在单片机程序里加入了前进或后退的标志位。先说明一下,,,,,,

    按下前进向单片机发送‘0’,按下后退向单片机发送‘1’,按下左转向单片机发送‘2’,按下右转向单片机发送‘3’,松开前进或后退向单片机发送‘5’,松开左转或右转向单片机发送‘6’,这样子发数据也是为了获得更好的操作体验

    前进 后退 左转 右转按钮是使用的setOnTouchListener方法,以便在按钮按下或松开时发送数据,

    就看一下前进代码

    我在前面声明了一下

    //前进,关于OnTouchListener的使用,,找度娘,我也是找的度娘,不要偷懒呦

     //前进
        private OnTouchListener forwordButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN://如果按下
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("0".getBytes());//发送0
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP://如果松开
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("5".getBytes());//发送‘5’
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
    //源码
    package com.wifi_Contrl;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    
    @SuppressLint("ClickableViewAccessibility") public class MainActivity extends Activity {
    
        boolean isConnect=true;//连接还是断开
        Button connectButton;//定义连接按钮
        Button forwordButton;//定义前进按钮
        Button backButton;//定义后退按钮
        Button leftButton;//定义左转按钮
        Button righButton;//定义右转按钮
        EditText ipEditText;//定义ip输入框
        EditText portText;//定义端口输入框
        Socket socket = null;//定义socket
        private InputStream inputStream=null;//定义输入流
        private OutputStream outputStream=null;//定义输出流
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            connectButton = (Button) findViewById(R.id.btConnect);
            forwordButton = (Button) findViewById(R.id.btqianjin);
            backButton = (Button) findViewById(R.id.bthoutui);
            leftButton = (Button) findViewById(R.id.btzuozhuan);
            righButton = (Button) findViewById(R.id.btyuozhuan);
            ipEditText = (EditText) findViewById(R.id.etIP);
            portText = (EditText) findViewById(R.id.etPort);
            
            connectButton.setOnClickListener(connectButtonListener);
            forwordButton.setOnTouchListener(forwordButtonTouch);
            backButton.setOnTouchListener(backButtonTouch);
            leftButton.setOnTouchListener(leftButtonTouch);
            righButton.setOnTouchListener(righButtonTouch);
           
        }
        //连接
        private OnClickListener connectButtonListener = new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if (isConnect == true) //标志位 = true表示连接
                {
                    isConnect = false;//置为false
                    connectButton.setText("断开");//按钮上显示--断开
                    //打开连接线程
                    Connect_Thread connect_Thread = new Connect_Thread();
                    connect_Thread.start();
                }
                else //标志位 = false表示退出连接
                {
                    isConnect = true;//置为true
                    connectButton.setText("连接");//按钮上显示连接
                    Toast.makeText(MainActivity.this,"已退出连接!", Toast.LENGTH_SHORT).show();
                    try 
                    {
                        socket.close();//关闭连接
                        socket=null;
                    } 
                    catch (IOException e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        };
        //前进
        private OnTouchListener forwordButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("0".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("5".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //后退
        private OnTouchListener backButtonTouch = new OnTouchListener() {
                
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        try 
                        {
                            //获取输出流
                            outputStream = socket.getOutputStream();
                            //发送数据
                            //outputStream.write(msgEditText.getText().toString().getBytes());
                            outputStream.write("1".getBytes());
                        } 
                        catch (Exception e) 
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        try 
                        {
                            //获取输出流
                            outputStream = socket.getOutputStream();
                            //发送数据
                            //outputStream.write(msgEditText.getText().toString().getBytes());
                            outputStream.write("5".getBytes());
                        } 
                        catch (Exception e) 
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    default:
                        break;
                    }
                    return false;
                }
        };
        //左转
        private OnTouchListener leftButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("2".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("6".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //右转
        private OnTouchListener righButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("3".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("6".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //连接线程
        class Connect_Thread extends Thread//继承Thread
        {
            public void run()//重写run方法
            {
                try 
                {
                    if (socket == null) 
                    {
                        //用InetAddress方法获取ip地址
                        InetAddress ipAddress = InetAddress.getByName(ipEditText.getText().toString());
                        int port =Integer.valueOf(portText.getText().toString());//获取端口号 
                        socket = new Socket(ipAddress, port);//创建连接地址和端口    
                        if (socket !=null) {
                            runOnUiThread(new Runnable()
                            {
                                public void run() 
                                {    
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"已成功连接!", Toast.LENGTH_SHORT).show();
                                }                        
                            });
                        }
                    }    
                } 
                catch (Exception e) 
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    //布局源码,大神勿喷,小弟才入门android,所以关于布局还,,,,,
    <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_purple"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.wifi_Contrl.MainActivity" >
    
        <!-- IP地址 : -->
        <TextView
            android:id="@+id/tvIP"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="IP地址 :"
            android:textSize="23dp" 
            android:layout_x="0dp"
            android:layout_y="0dp"
            />
            
        <!-- 左转 -->
        <Button
            android:id="@+id/btzuozhuan"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_x="400dp"
            android:layout_y="118dp"
            android:text="左转" />
    
        <!-- 右转 -->
        <Button
            android:id="@+id/btyuozhuan"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_x="520dp"
            android:layout_y="118dp"
            android:text="右转" />
    
        <!-- 后退 -->
    
        <Button
            android:id="@+id/bthoutui"
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:layout_x="105dp"
            android:layout_y="200dp"
            android:text="后退" />
    
        <!-- 前进 -->
        <Button
            android:id="@+id/btqianjin"
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:layout_marginBottom="21dp"
            android:layout_x="105dp"
            android:layout_y="65dp"
            android:text="前进" />
        
        <!-- 连接 -->
        <Button
            android:id="@+id/btConnect"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginBottom="21dp"
            android:layout_x="500dp"
            android:text="连接" />
    
        <!-- 端口号 : -->
        <TextView
            android:id="@+id/tvPort"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_x="280dp"
            android:layout_y="0dp"
            android:text="端口号 :"
            android:textSize="23dp" />
    
        <!-- 输入端口地址的文本控件 -->
        <EditText
            android:id="@+id/etPort"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:layout_x="380dp"
            android:layout_y="0dp"
            android:background="@android:color/white"
            android:ems="10"
            android:text="8080" />
    
        <!-- 输入ip地址的文本控件 -->
    
        <EditText
            android:id="@+id/etIP"
            android:layout_width="150dp"
            android:layout_height="30dp"
            android:layout_x="100dp"
            android:layout_y="0dp"
            android:background="@android:color/white"
            android:ems="10"
            android:text="192.168.4.1" >
    
            <requestFocus />
        </EditText>
    
    </AbsoluteLayout>

    再看单片机,因为学实时操作系统UCOSII的时候,写程序就养成了这样写程序习惯,如果对于这样

    #ifndef _USART_C_//如果没有定义_USART_C_
    #define _USART_ex_ extern
    #else
    #define _USART_ex_
    #endif

    _USART_ex_ unsigned char Usart_Receive[20];
    _USART_ex_ unsigned char Usart_Cnt;
    _USART_ex_ bit Usart_AT_flage;
    _USART_ex_ bit Command_Flag;
    _USART_ex_ unsigned char UsartData;
    _USART_ex_ void InitUART(void);//串口初始化
    _USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据
    _USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止

    其实这样写,有助于各个c文件之间调用变量。说一下

    #ifndef _USART_C_//如果没有定义_USART_C_
    #define _USART_ex_ extern//就定义_USART_ex_ 为extern
    #else//否则
    #define _USART_ex_就定义_USART_ex_为空
    #endif

    如果是自身文件编译由于我在USART.C文件的开头加上了#define _USART_C_所以,就定义_USART_C_为空

    即   unsigned char Usart_Receive[20];

    如果别的文件编译那么因为别的文件没有定义#define _USART_C_ 所以就定义_USART_ex_ 为extern

    extern  unsigned char Usart_Receive[20];

    对于extern  这应该不陌生吧,好了接着往下看,

    不好意思再啰嗦下,我把所有的.h文件全放在了一个.h文件中,这样在每个c文件的开头只需加上#include "include.h"就方便多了

    #define _MAIN_C_
    #include "include.h"
    
    sbit a1 = P1^0;//前左轮前进
    sbit a2 = P1^1;//前左轮后退
    sbit a3 = P1^2;//前右轮前进
    sbit a4 = P1^3;//前右轮后进
    sbit a5 = P1^4;//后左轮前进
    sbit a6 = P1^5;//后左轮后退
    sbit a7 = P1^6;//后右轮前进
    sbit a8 = P1^7;//后右轮后进
    
    bit forword_flag=0;
    bit back_flag=0;
    
    unsigned char CWMODE[]="AT+CWMODE=2
    "; //设置模块的工作的模式为AP模式
    unsigned char RST[]="AT+RST
    "; //重启模块使AT+CWMODE=2模式生效
    unsigned char CIPMUX[]="AT+CIPMUX=1
    "; //启动多连接
    unsigned char CIPSERVER[]="AT+CIPSERVER=1,8080
    ";//开启服务器模式,端口号8080
    
    
    void delay1s(void) //误差 -0.00000000024us
    {
     unsigned char a,b,c;
     for(c=95;c>0;c--)
    for(b=26;b>0;b--)
    for(a=185;a>0;a--);
    }
    
    //多连接AP模式
    void ManyConnect_AP()
    {
        P0=0x00;
        while(1)
        {
        UartSends(CWMODE);//返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x01;
        break;
        } 
        }
     }
        UartSends(RST);//返回一大溜,不用判断返回
    delay1s();
        delay1s();
        while(1)
        {
        UartSends(CIPMUX);//返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x03;
        break;
        } 
        }
     }
        while(1)
        {
        UartSends(CIPSERVER);//返回ok,多了也返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x07;
        break;
        } 
        }
     }
    }
    
    void main()
    {
        InitUART();
        while(1)
        {
        ManyConnect_AP();//多连接AP模式
    while(1)
        {
        //由于消息的开头是+IP 故做此判断
    if((Usart_Receive[0]=='+')&&(Usart_Receive[1]=='I')&&(Usart_Receive[2]=='P'))
        {
        if((Usart_Receive[3]=='D')&&(Usart_Receive[6]==','))
        {
        if(Usart_Receive[9]=='0')//前进
    {
    forword_flag = 1;//前进标志位置一
    back_flag = 0; //后退标志位置零
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后进
    /*sbit a1 = P1^0;//前左轮前进
    sbit a2 = P1^0;//前左轮后退
    sbit a3 = P1^1;//前右轮前进
    sbit a4 = P1^2;//前右轮后进
    sbit a5 = P1^3;//后左轮前进
    sbit a6 = P1^0;//后左轮后退
    sbit a7 = P1^0;//后右轮前进
    sbit a8 = P1^1;//后右轮后进*/
    
        }
    if(Usart_Receive[9]=='1')//后退
    {
    forword_flag = 0;//前进标志位置一
    back_flag = 1; //后退标志位置零
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后进
    }
    if(Usart_Receive[9]=='6')//左右转停止
    {
    if(forword_flag == 1 && back_flag == 0)//上一次按下的是前进,没松开
    {
        //前进
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后进
    }
    if(forword_flag == 0 && back_flag == 1)//上一次按下的是后退,没松开
    {
        //后退
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后进
    }
    if(forword_flag == 0 && back_flag == 0)//上一次松开了前进或后退
    {
        //停止
    a1 = 0;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 0;//后右轮后进
    }
        }
    if(Usart_Receive[9]=='2')//左转
    {
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后退
    }
    if(Usart_Receive[9]=='3')//右转
    {
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后退
    }
    if(Usart_Receive[9]=='5')//停止
    {
    forword_flag = 0;//前进标志位置零
    back_flag = 0; //后退标志位置零
    a1 = 0;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 0;//后右轮后进
    }
        }
        }
        }
        }
    }

    #define _USART_C_
    #include "include.h"
    unsigned char Usart_Receive[20]={0};
    unsigned char Usart_Cnt=0;
    bit Usart_AT_flage;
    bit flage;
    bit Command_Flag;
    void InitUART(void)
    {
        TMOD = 0x20;
        SCON = 0x50;
        TH1 = 0xFD;
        TL1 = TH1;
        PCON = 0x00;
        EA = 1;
        ES = 1;
        TR1 = 1;
    }
    
    void SendOneByte(unsigned char c)
    {
            SBUF = c;
            while(!TI);
            TI = 0;    
    }
    
    //串行口连续发送char型数组,遇到终止号/0(空格)将停止
    void UartSends(unsigned char *str)
    {
        while(*str!='')
        {
            SBUF=*str;
            while(!TI);//等待发送完成信号(TI=1)出现
            TI=0;
            str++;
        }
    }
    
    void UARTInterrupt(void) interrupt 4
    {
        RI=0;
        Usart_Receive[Usart_Cnt]=SBUF;//接收串口数据
        Usart_Cnt++;//
        //返回数据以回车结尾,有回车,而且数据个数大于2,说明接收到了数据
        if(Usart_Receive[Usart_Cnt-2]=='
    ' && Usart_Receive[Usart_Cnt-1]=='
    ' && Usart_Cnt >= 2)
        {
            Usart_Cnt = 0;//接收数据计数清零
            Usart_AT_flage = 1;//数据接收成功标志位
      }
        else if(Usart_Cnt > 20)//
        {
            Usart_Cnt = 0;
        }    
    }

     

    #ifndef __USART_H_
    #define __USART_H_
    
    
    #ifndef _USART_C_
    #define _USART_ex_ extern
    #else
    #define _USART_ex_
    #endif
    
    _USART_ex_ unsigned char Usart_Receive[20];
    _USART_ex_ unsigned char Usart_Cnt;
    _USART_ex_ bit Usart_AT_flage;
    _USART_ex_ bit Command_Flag;
    _USART_ex_ unsigned char UsartData;
    _USART_ex_ void InitUART(void);//串口初始化
    _USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据
    _USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止
    #endif

    #include <REGX52.H>
    #include "USART.h"
    #include <string.h>

    下载好程序,接好线,等一会用手机连接就好了,连接成功会显示连接成功

    eps8266说是3.3v供电因为我手头没有降压模块也没有二极管所以就直接接的5v供电,不过没有烧,正常工作,就是摸上去有点热。其实程序还有点不够可靠,以后再改进

  • 相关阅读:
    微软外服 AlI In One
    js 循环多次和循环一次的时间的性能对比 All In One
    vue inject All In One
    Excel 表格数据倒置 All In One
    SVG tickets All In One
    OH MY ZSH All In One
    js array for loop performance compare All In One
    mac terminal show You have new mail All In one
    新闻视频 26 制作母版页
    转自牛腩 母版页和相对路径
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/5220919.html
Copyright © 2011-2022 走看看