基于arduino和蓝牙通信的智能窗户控制系统

最近因为要做实训,智能窗户,所以就写了一个蓝牙通信的APP来控制。所以也不是很深入的了解使用,只是那别人的改改。

1、需要在AndroidManifest.xml中加入一下权限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 要想改变蓝牙的可发现性以及启用/禁用蓝牙适配器需要加入下面的权限-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
2、检查设备上蓝牙的状态
private BluetoothAdapter buAdapter; 
buAdapter = BluetoothAdapter.getDefaultAdapter();
if(buAdapter == null){
            //返回null表示设备不支持蓝牙
            return;
        }
        if(buAdapter.isEnabled()){
            //设备的蓝牙是打开的
            return;
        }else {
            //方式一
            //buAdapter.enable();打开蓝牙设备
            //方式二,建议使用
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE);
        }
private static final int REQUEST_ENABLE = 1;
private static final int REQUEST_DISCOVERABLE = 2;
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        switch (requestCode) {
        case REQUEST_ENABLE:
            if(resultCode != Activity.RESULT_OK){
                showToast("Bluetooth Not Enabled.");
            }
            break;
        case REQUEST_DISCOVERABLE:

            break;
        default:
            break;
        }
    }
3、搜索模式
private ArrayList<SiriListItem> list;
public class SiriListItem {
        String message;
        boolean isSiri;
        public SiriListItem(String msg, boolean siri) {
            message = msg;
            isSiri = siri;
        }
    }
    public void find() {
        if(btn_find.getText().equals("搜索设备")){
            mListView.setVisibility(View.VISIBLE);
            //setPr
            tv.setVisibility(View.GONE);
            progressDialog.setMessage("正在搜索....");
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.show();
            if(buAdapter.isDiscovering()){
                buAdapter.cancelDiscovery();
                //btn_find.setText("停止搜索");
            }else {
                list.clear();
                mAdapter.notifyDataSetChanged();
                pairedDevices = buAdapter.getBondedDevices();
                if (pairedDevices.size() > 0) {

                    for (BluetoothDevice device : pairedDevices) {
                        list.add(new SiriListItem(device.getName() + "\n" + device.getAddress(), true));
                        mAdapter.notifyDataSetChanged();
                        mListView.setSelection(list.size() - 1);
                    }

                }else {
                    list.add(new SiriListItem("No devices have been paired", true));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(list.size() - 1);
                }
            }
            //开始搜索
            buAdapter.startDiscovery();
            //btn_find.setText("停止搜索"); 
        }else {
            if (serviceOrCilent == ServerOrCilent.CILENT) 
            {
                shutdownClient();
            }
            else if (serviceOrCilent == ServerOrCilent.SERVICE) 
            {
                shutdownServer();
            }
            serviceOrCilent=ServerOrCilent.NONE;
            showToast("已断开连接!");
            btn_find.setText("搜索设备");
        }

    }
4、设备连接
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
        public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
            // Cancel discovery because it's costly and we're about to connect     

            SiriListItem item = list.get(arg2);
            String info = item.message;
            String address = info.substring(info.length() - 17);                 
            BlueToothAddress = address;

             AlertDialog.Builder StopDialog =new AlertDialog.Builder(MainActivity.this);//定义一个弹出框对象
             StopDialog.setTitle("连接");//标题          
             StopDialog.setMessage(item.message);
             StopDialog.setPositiveButton("连接", new DialogInterface.OnClickListener() {  
             public void onClick(DialogInterface dialog, int which) {  
                 buAdapter.cancelDiscovery();//停止搜索  
                 serviceOrCilent=ServerOrCilent.CILENT;
                 clientThread clientConnectThread = new clientThread();
                 clientConnectThread.start();
             }  
             });
             StopDialog.setNegativeButton("取消",new DialogInterface.OnClickListener() {                       
                 public void onClick(DialogInterface dialog, int which) {  
                     BlueToothAddress = null;
                 }
             });
             StopDialog.show();                            
        }
    };  

5、广播和服务

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) 
            {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // If it's already paired, skip it, because it's been listed already
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) 
                {
                    list.add(new SiriListItem(device.getName() + "\n" + device.getAddress(), false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(list.size() - 1);
                }
            // When discovery is finished, change the Activity title
            } 
            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) 
            {
                setProgressBarIndeterminateVisibility(false);
                if (mListView.getCount() == 0) 
                {
                    list.add(new SiriListItem("没有发现蓝牙设备", false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(list.size() - 1);
                }
                //btn_find.setText("重新搜索");
            }
        }
    };  

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // Make sure we're not doing discovery anymore
        if (buAdapter != null) {
            buAdapter.cancelDiscovery();
        }
        // Unregister broadcast listeners
        this.unregisterReceiver(mReceiver);
    }
  //开启客户端
    private class clientThread extends Thread { 

        public void run() {

            try {
                device = buAdapter.getRemoteDevice(BlueToothAddress);
                //创建一个Socket连接:只需要服务器在注册时的UUID号
                // socket = device.createRfcommSocketToServiceRecord(BluetoothProtocols.OBEX_OBJECT_PUSH_PROTOCOL_UUID);
                socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                Message msg2 = new Message();
                msg2.obj = "请稍候,正在连接服务器:"+BlueToothAddress;
                msg2.what = 1;
                LinkDetectedHandler.sendMessage(msg2);
                socket.connect();
                Message msg = new Message();
                msg.obj = "已经连接上" + BlueToothAddress + "服务端!可以发送信息";
                msg.what = 0;
                LinkDetectedHandler.sendMessage(msg);
                //启动接受数据
                mreadThread = new readThread();
                mreadThread.start();

            } 
            catch (IOException e) 
            {
                Log.e("connect", "", e);

            } 
        }
    };

    //开启服务器
    private class ServerThread extends Thread { 
        public void run() {

            try {
                /* 创建一个蓝牙服务器 
                 * 参数分别:服务器名称、UUID   */ 
                mserverSocket = buAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
                        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));       

                Log.d("server", "wait cilent connect...");

                Message msg = new Message();
                msg.obj = "请稍候,正在等待客户端的连接...";
                msg.what = 3;
                LinkDetectedHandler.sendMessage(msg);

                /* 接受客户端的连接请求 */
                socket = mserverSocket.accept();
                Log.d("server", "accept success !");

                Message msg2 = new Message();
                String info = "客户端已经连接上!可以发送信息。";
                msg2.obj = info;
                msg.what = 3;
                LinkDetectedHandler.sendMessage(msg2);
                //启动接受数据
                mreadThread = new readThread();
                mreadThread.start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };

    /* 停止服务器 */
    private void shutdownServer() {
        new Thread() {
            public void run() {
                if(startServerThread != null)
                {
                    startServerThread.interrupt();
                    startServerThread = null;
                }
                if(mreadThread != null)
                {
                    mreadThread.interrupt();
                    mreadThread = null;
                }               
                try {                   
                    if(socket != null)
                    {
                        socket.close();
                        socket = null;
                    }
                    if (mserverSocket != null)
                    {
                        mserverSocket.close();/* 关闭服务器 */
                        mserverSocket = null;
                    }
                } catch (IOException e) {
                    Log.e("server", "mserverSocket.close()", e);
                }
            };
        }.start();
    }
    /* 停止客户端连接 */
    private void shutdownClient() {
        new Thread() {
            public void run() {
                if(clientConnectThread!=null)
                {
                    clientConnectThread.interrupt();
                    clientConnectThread= null;
                }
                if(mreadThread != null)
                {
                    mreadThread.interrupt();
                    mreadThread = null;
                }
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    socket = null;
                }
            };
        }.start();
    }
  //发送数据
    private void sendMessageHandle(String msg) 
    {       
        if (socket == null) 
        {
            showToast("没有连接");
            return;
        }
        try {               
            OutputStream os = socket.getOutputStream(); 
            os.write(msg.getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }           
    }
6、读取数据
//读取数据
     private class readThread extends Thread { 
         public void run() {

             byte[] buffer = new byte[1024];
             int bytes;
             InputStream mmInStream = null;

            try {
                mmInStream = socket.getInputStream();//蓝牙获取的数据
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }   
             while (true) {
                 try {
                    // String ss = new String();
                     // Read from the InputStream
                     bytes = mmInStream.read(buffer);

                     String buf_data = new String(buffer);
                      buf_data = buf_data.substring(0, bytes);
                        if(buf_data != null)
                        sss += buf_data;
                        else
                            return;
                        if(!sss.contains("#")){
                            continue;
                        }
                        Log.i("接收完毕:", sss);
                        Message msg = new Message();
                        msg.obj="";
                        msg.obj = sss;
                        sss="";
                        msg.what = 2;
                        LinkDetectedHandler.sendMessage(msg);

                     }
                 catch (IOException e) {
                    try {
                        mmInStream.close();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                     break;
                 }
             }
         }
     }
public String dataTime(){
        // 创建日期对象
        Date d = new Date();
        //在把一个字符串解析为日期的时候,请注意格式必须和给定的字符串格式匹配
        SimpleDateFormat sdf = new SimpleDateFormat("MM月dd日 HH:mm");
        String s = sdf.format(d);
        return s;
     }
7、数据反馈
private Handler LinkDetectedHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             CloudsServe cloudsServe = new CloudsServe(MainActivity.this);
             String time = dataTime();
             switch (msg.what) {
            case 0:
                progressDialog.dismiss();
                btn_find.setText("断开连接");
                showToast("连接成功");
                mListView.setVisibility(View.GONE);
                tv.setVisibility(View.VISIBLE);             
                String str2 = (String)msg.obj;
                msgArrary2.add(str2);               
                String s2 = "";
                for(String msgStr: msgArrary2){
                    s2 += msgStr + "\n";
                }
                tv.setText(s2);
                break;
            case 1:
                progressDialog.setMessage("正在连接....");
                progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                progressDialog.show();
                break;
            case 2:
                mListView.setVisibility(View.GONE);
                tv.setVisibility(View.VISIBLE); 
                String str = (String)msg.obj;
                str = str.substring(0,str.length()-1);
                Boolean closeOk = str.contains("close windows ok!");
                Boolean openOk = str.contains("open windows ok!");
                Boolean closeNo = str.contains("close no!");
                Boolean openNo = str.contains("open no!");

                if(str.contains("rain")){
                    int start = str.indexOf('=');
                    String rain = str.substring(start + 1);
                    showToast(rain);
                    Integer integer = new Integer(rain);
                    int nowRain = (int)integer;

                    String state = "";
                    if(str.contains("close")){
                        state = "close";
                    }else {
                        state = "open ";
                    }   
                    if(nowRain < 900){
                        read("小娜为您播报天气情况,现在是北京时间" + time + "雨水量为" + rain + "最近下过雨,出门记得带雨伞");
                    }else {
                        read("小娜为您播报天气情况,现在是北京时间" + time + "雨水量为" + rain + "最近没有下雨,放心去玩吧");
                    }
                    cloudsServe.saveDate("三教204", rain,state , time);
                    Double r = new Double(rain);
                    insertApi(r, time.substring(time.indexOf(" ")));

                }
                if(openOk){
                    int end = str.indexOf('o');
                    String rain = str.substring(0,end);
                    read("正在为您打开窗户");
                    cloudsServe.saveDate("三教204", rain,"open ", time);
                    Double r = new Double(rain);
                    insertApi(r, time.substring(time.indexOf(" ")));
                }
                if(closeOk){
                    int end = str.indexOf('c');
                    String rain = str.substring(0,end);
                    read("正在为您关闭窗户");
                    cloudsServe.saveDate("三教204", rain,"close", time);
                    Double r = new Double(rain);
                    insertApi(r, time.substring(time.indexOf(" ")));
                }
                if(openNo){
                    int end = str.indexOf('o');
                    String rain = str.substring(0,end);
                    read("现在窗户已经打开了,不能再开了");
                    cloudsServe.saveDate("三教204", rain,"close", time);
                    Double r = new Double(rain);
                    insertApi(r, time.substring(time.indexOf(" ")));
                }
                if(closeNo){
                    int end = str.indexOf('c');
                    String rain = str.substring(0,end);
                    read("现在窗户已经关闭了,不能再关了");
                    cloudsServe.saveDate("三教204", rain,"open ", time);
                    Double r = new Double(rain);
                    insertApi(r, time.substring(time.indexOf(" ")));
                }
                msgArrary.add(str);             
                String s = "";
                for(String msgStr: msgArrary){
                    s += msgStr + "\n";
                }

                tv.setText(s);
                break;
            default:
                break;
            }
         }

     };   
8、相应的初始化
/* 一些常量,代表服务器的名称 */
    public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap";
    public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
    public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep";
    public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex";

    private BluetoothServerSocket mserverSocket = null;
    private ServerThread startServerThread = null;
    private clientThread clientConnectThread = null;
    private BluetoothSocket socket = null;
    private BluetoothDevice device = null;
    private readThread mreadThread = null;; 
    private Button btn_device,btn_find,btn_star,btn_open,btn_close,btn_look,btn_voice,btn_clouds,btn_chart;
    private TextView tv;
    static String BlueToothAddress = "null";
    enum ServerOrCilent{
        NONE,
        SERVICE,
        CILENT
    };
    static ServerOrCilent serviceOrCilent = ServerOrCilent.NONE;
    private BluetoothAdapter buAdapter; 
    Set<BluetoothDevice> pairedDevices;
    private ArrayList<SiriListItem> list;
    private ListView mListView;
    MyAdapetr mAdapter;
    Context mContext;
    ProgressDialog progressDialog;
    ArrayList<String> msgArrary;
    ArrayList<String> msgArrary2;
    ArrayList<Double> yList;
    ArrayList<String> xRawDatas;
//获取蓝牙适配器
        buAdapter = BluetoothAdapter.getDefaultAdapter();
list = new ArrayList<SiriListItem>();
        mAdapter = new MyAdapetr(this, list);
        mListView = (ListView) findViewById(R.id.list);
        mListView.setAdapter(mAdapter);
        mListView.setFastScrollEnabled(true);
        mListView.setOnItemClickListener(mDeviceClickListener);     
         // Register for broadcasts when a device is discovered
        IntentFilter discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(mReceiver, discoveryFilter);

         // Register for broadcasts when discovery has finished
        IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(mReceiver, foundFilter);

        // Get a set of currently paired devices
        Set<BluetoothDevice> pairedDevices = buAdapter.getBondedDevices();

        // If there are paired devices, add each one to the ArrayAdapter
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                list.add(new SiriListItem(device.getName() + "\n" + device.getAddress(), true));
                mAdapter.notifyDataSetChanged();
                mListView.setSelection(list.size() - 1);
            }
        } else {
            list.add(new SiriListItem("没有设备已经配对", true));
            mAdapter.notifyDataSetChanged();
            mListView.setSelection(list.size() - 1);
        }
public class MyAdapetr extends BaseAdapter{
    private ArrayList<SiriListItem> list;
    private LayoutInflater mInflater;
    public MyAdapetr(Context context, ArrayList<SiriListItem> list){
        this.list = list;
        mInflater = LayoutInflater.from(context);
    }
    public int getCount() {
        return list.size();
    }

    public Object getItem(int position) {
         return list.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        SiriListItem  item=list.get(position);
        if(convertView == null){
            convertView = mInflater.inflate(R.layout.list_item, null);          
            viewHolder=new ViewHolder(
                    (View) convertView.findViewById(R.id.list_child),
                    (TextView) convertView.findViewById(R.id.chat_msg)
                   );
            convertView.setTag(viewHolder);
        }
        else{
            viewHolder = (ViewHolder)convertView.getTag();
        }       

        if(item.isSiri)
        {
            viewHolder.child.setBackgroundResource(R.drawable.msgbox_rec);
        }
        else 
        {
            viewHolder.child.setBackgroundResource(R.drawable.msgbox_send);
        }
        viewHolder.msg.setText(item.message);    

        return convertView;
    }
    class ViewHolder {
      protected View child;
        protected TextView msg;

        public ViewHolder(View child, TextView msg){
            this.child = child;
            this.msg = msg;

        }
  }
  }
8、arduino模块代码
#include<Stepper.h>
int ASignal = A0;//定义雨水量的模拟引脚
int Do = 7;//传感器的端口
int ledPin = 12;//定义板子的灯
//定义电机的端口号
#define A1 8  
#define B1 9
#define C1 10
#define D1 11
//声明布进电机的4步函数
void Phase_A();
void Phase_B();
void Phase_C();
void Phase_D();
void zhengZhuan();
void fanZhuan();
int flag = 1; //初始化窗户为打开状态,0为关闭状态
int flag2 = 3;//初始化开始的模式
void setup() {    
  //定义引脚的状态,输出,输入状态
   pinMode(ASignal, INPUT);  
   pinMode(12, OUTPUT);
   pinMode(Do, INPUT);
   pinMode(A1,OUTPUT); 
   pinMode(B1,OUTPUT); 
   pinMode(C1,OUTPUT); 
   pinMode(D1,OUTPUT); 
   Serial.begin(9600); //发送数据的波特率
}

void loop() {
   int sensorValue = analogRead(ASignal); //获取雨水量的模拟量
   int n = digitalRead(Do);//读取Do电平,Do为高电平没有水,低电平为有水
   if(Serial.available()>0){  //判断是否有蓝牙传输的数据
    char read = Serial.read();//获取蓝牙端发送的数据
    switch (read) {
    case 'z'://启动自动模式
      flag2 = 0;
      Serial.print("self-motion..#");  //发送数据到用户端
      break;
    case 'g'://启动关窗
      flag2 = 2;
      Serial.print("closeing...#");  
      break;
      case 'k'://启动开窗
            flag2 = 1;
            Serial.print("opening...#");
      break;
       case 'l'://显示下雨量
           Serial.print("rain=");
           Serial.print(sensorValue);
           Serial.print("#");
           delay(1000);
           if(flag == 1){   
              Serial.print("now=");
              Serial.print("close#");
           }else{
              Serial.print("now=");
              Serial.print("open#");
           }
       break;
    }
  }

      /**********************************************
     *             进入自动模式
    ************************************************/
  if(flag2 == 0){
           delay(1000);
           if(n == HIGH && flag == 1){ //高电平,无水,开窗
             Serial.print(sensorValue);
             Serial.print("open windows ok!#");
             digitalWrite(12, LOW);//关灯
             zhengZhuan();//开窗
             flag = 0;//窗处于开状态
         }
         if(n == LOW && flag == 0){//低电平,有水,关窗
            Serial.print(sensorValue);
            Serial.print("close windows ok!#");
            delay(1000);
            digitalWrite(12, HIGH);
            fanZhuan();//关窗
            flag = 1;//窗处于关闭状态
         }
  }

  /**********************************************
     *             进入开窗模式
    ************************************************/
 if(flag2 == 1){
      if(flag == 1){
        delay(1000);
        Serial.print(sensorValue);
        Serial.print("open windows ok!#");
       zhengZhuan();//开窗
       flag2 = 3;//改变模式
       flag =0;//将窗户的状态改变
      }else{
          delay(1000);
          Serial.print(sensorValue);
          Serial.print("open no!#");             
          flag2 = 3;             
      }
  }
  /**********************************************
     *             进入关窗模式
    ************************************************/
 if(flag2 == 2){
     if(flag == 0){
       delay(1000);
       Serial.print(sensorValue);
       Serial.print("close windows ok!#"); 
       fanZhuan();//关窗
       flag2 = 3;
       flag = 1; 
     }else{
           delay(1000);
           Serial.print(sensorValue);
           Serial.print("close no!#");          
           flag2 = 3;   
     }
  } 
}
/**********************************************
 *              步进电机的正转函数
************************************************/
void zhengZhuan(){
  for(int x = 0;x < 150;x++){//设置旋转时间
    Phase_D();
    delay(5);
    Phase_C();
    delay(5);
    Phase_B();
    delay(5);
    Phase_A();
    delay(5);
  }
}
/**********************************************
 *              步进电机的反转函数
************************************************/
void fanZhuan(){

  for(int x = 0;x < 150;x++){ //设置旋转时间
    Phase_A();
    delay(5);
    Phase_B();
    delay(5);
    Phase_C();
    delay(5);
    Phase_D();
    delay(5);
  }
}
/**********************************************
 *              步进电机的四个步骤
************************************************/
void Phase_A(){
  digitalWrite(A1,HIGH);
  digitalWrite(B1,HIGH); 
   digitalWrite(C1,HIGH);
    digitalWrite(D1,LOW); 
}
void Phase_B(){
  digitalWrite(A1,HIGH);
  digitalWrite(B1,HIGH); 
   digitalWrite(C1,LOW);
    digitalWrite(D1,HIGH); 
}
void Phase_C(){
  digitalWrite(A1,HIGH);
  digitalWrite(B1,LOW); 
   digitalWrite(C1,HIGH);
    digitalWrite(D1,HIGH); 
}
void Phase_D(){
  digitalWrite(A1,LOW);
  digitalWrite(B1,HIGH); 
  digitalWrite(C1,HIGH);
  digitalWrite(D1,HIGH); 
}
9、效果图

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值