目录

1. 新建类mpsse_iic

2. 修改类mpsse_gpio

3. iic的初始化

4. IIC的Start

5. IIC的Stop

6. IIC的读一个字节

7. IIC的发送一个字节

8. IIC读操作

9. IIC写操作

10. 验证


IIC的实现采用GPIO模拟的方式。GPIO的方式可以采用任意IO作为IIC的管脚。这里为了程序简单点,只使用PortD口作为IIC的IO。

为了保持兼容性,选择xDBUS0作为IIC的SCL,xDBUS1和xDBUS2短接在一起作为SDA,xDBUS1作为SDA的输出,而xDBUS2作为SDA的输入。实际只使用xDBUS1作为SDA口的输入输出。

1. 新建类mpsse_iic

public class mpsse_iic {public FT_Device ftDevice;mpsse_gpio gpio;public mpsse_iic(mpsse_gpio spiGPIO){gpio = spiGPIO;}
}

1.1 增加变量表示对应IO口位置

private byte SCL = 0;
private byte SDAO = 1;
private byte SDAI = 2;

1.2 增加变量保存IO控制序列

private ArrayList ftCommand = new ArrayList();

在控制GPIO时,不是每次写一次IO口的状态,而是写入一组IO的状态,例如一次写入8bit的数据,可以把这8bit写入USB Buffer中的数据一次写入,这样就把这些命令序列保存在ftCommand变量中,最后一次写出去即可。

1.3 增加变量确定IO的频率

private int mCLK = 0;

2. 修改类mpsse_gpio

为了在操作IIC的时候不影响其他IO口的状态,增加一些方法的实现。

将变量

private byte PortDDir;
private byte PortDLevel;
private byte PortCDir;
private byte PortCLevel;

改为Class,以实现这4个变量能被获取。

    public static class classPort{public byte PortDDir;public byte PortDLevel;public byte PortCDir;public byte PortCLevel;}classPort mPort = new classPort();public classPort getPortState(){return mPort;}public void setPortState(classPort port){mPort = port;}

3. iic的初始化

在类mpsse_iic中添加init,clk表示gpio的频率,一般为1(800KHz)或2(400KHz)即可,注意这个速率是大概的速率,并不是很准确。

    /** clk: normally 1 or 2.* ioSCL/ioSDA:  0-7 low byte io, xDBUS0 - xDBUS7*/public void init(int clk, byte ioSCL, byte ioSDA){mCLK = clk;SCL = ioSCL;SDAO = ioSDA;gpio.setDir(SCL, (byte)0); //SCL is outputgpio.setDir(SDAO, (byte)0); //SDA(AD1) is outputgpio.setDir(SDAI, (byte)1); //SDA(AD2) is inputgpio.output(SCL, mpsse_gpio.eLevel.High);gpio.output(SDAO, mpsse_gpio.eLevel.High);}

4. IIC的Start

这里只是把Start的命令序列写入到ftCommand中,利用MPSSE的0x80命令控制GPIO。

IIC的Start时序是SDA和SCL开始输出高电平,然后SDA产生一个下降沿。

    private void start(){mpsse_gpio.classPort port;Log.i("IIC", "Start");port = gpio.getPortState();port.PortDLevel |= (byte)1 << SCL | (byte)1 << SDAO; //SCL outputs high, SDA outputs highfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel &= (byte)(~((byte)1 << SDAO));       //SDA outputs lowfor (int i = 0; i < mCLK * 2; i++) //Wait a moment{ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}gpio.setPortState(port);}

例如,当SCL=4,SDAO=5,mCLK = 2时,ftCommand里面的内容为:

80 fe 3b 80 fe 3b 80 de 3b 80 de 3b 80 de 3b 80 de 3b

每3个字节为一次IO控制,mCLK为2表示重复一次,即连续同样操作2次IO,频率就相当于最高频率 / 2了。

fe -> de即SDA(位5)由高变为低。

5. IIC的Stop

IC的Stop时序是SCL输出高,然后SDA产生一个上升沿。

    private void stop(){mpsse_gpio.classPort port;Log.i("IIC", "Stop");port = gpio.getPortState();port.PortDLevel &= (byte)(~((byte)1 << SDAO));    //SDA outpus lowfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)1 << SCL;                //SCL outputs highfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)1 << SDAO;               //SDA outputs highfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}gpio.setPortState(port);}

6. IIC的读一个字节

IIC的SCL产生一个上升沿后读入SDA的电平,循环8次读入1个字节数据,然后根据是否要ACK设置SDA,如果要ACK则SDA输出0,否则输出1,最后设置SCL输出低。

    private void receiveByte(boolean ack){mpsse_gpio.classPort port;Log.i("IIC", "receiveByte");port = gpio.getPortState();port.PortDLevel &= (byte)(~(byte)1 << SCL | (byte)1 << SDAO); //SCL outputs low, SDA outputs lowport.PortDDir &= (byte)(~((byte)1 << SDAO));         //Set SDA as inputftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);if(ioCtrlMode == true){byte loop = 8;while (loop-- > 0){port.PortDLevel &= (byte)(~((byte)1 << SCL)); //SCL output lowfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)(1 << SCL); //SCL output highfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}ftCommand.add((byte)0x81); //Rd SDA}}else{ftCommand.add((byte)0x22);ftCommand.add((byte)7);}port.PortDLevel &= (byte)(~(byte)1 << SCL | (byte)1 << SDAO); //SCL outputs low, SDA outputs lowport.PortDDir |= ((byte)1 << SDAO);     //Set SDA as outputftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);if (ioCtrlMode == true){if (ack == true)port.PortDLevel &= (byte)(~((byte)1 << SDAO));elseport.PortDLevel |= ((byte)1 << SDAO);for (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)((byte)1 << SCL);for (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}}else{ftCommand.add((byte)0x13); //Clock Data Bits Out on clock raise edge MSB firstftCommand.add((byte)0x0);               // 1bitif (ack == true)ftCommand.add((byte)0x00);          // SDA outputs low means ackelseftCommand.add((byte)0x80);          // SDA outputs high means nack, only use bit7.}ftCommand.add((byte)0x87);port.PortDLevel &= (byte)(~((byte)1 << SCL)); //SCL outputs lowftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);gpio.setPortState(port);}

这里读入的SDA电平状态会在FT4232H的缓存中,最后写入0x87命令的目的是告诉FT4232H把缓存中的数据立即发送给主机。

7. IIC的发送一个字节

设置SCL为低并且SDA设置好对应的数据位,然后SCL拉高,重复8次发送一个字节数据,然后读取SDA的电平判断从机是否ACK,最后SCL输出低,SDA输出高。

    private void sendByte(byte dat){mpsse_gpio.classPort port;Log.i("IIC", "sendByte");port = gpio.getPortState();if (ioCtrlMode == true){for(byte j = 0; j < 8; j++){port.PortDLevel &= (byte)(~((byte)1 << SCL));  //SCL outputs low//for (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}if ((dat & 0x80) == 0x80)port.PortDLevel |= (byte)(1 << SDAO);           //SDA Output Highelseport.PortDLevel &= (byte)(~((byte)1 << SDAO));  //SDA Output Lowdat <<= 1;port.PortDDir |= (byte)(1 << SDAO);                 //Set SDA as output//for (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)(1 << SCL);            //set SCL to highfor (int i = 0; i < mCLK * 1; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}}}else{port.PortDLevel &= (byte)(~((byte)1 << SCL));     //SCL outputs lowport.PortDLevel |= (byte)(1 << SDAO);             //SDA outputs highport.PortDDir |= (byte)(1 << SDAO);               //Set SDA as outputfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}ftCommand.add((byte)0x13); //Clock Data Bits Out on clock raise edge MSB firstftCommand.add((byte)7);ftCommand.add(dat);}port.PortDLevel &= (byte)(~((byte)1 << SCL) | (byte)1 << SDAO); //SCL and SDA output lowport.PortDDir &= (byte)(~((byte)1 << SDAO));                    //Set SDA as inputfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}if (ioCtrlMode == true){port.PortDLevel &= (byte)(~((byte)1 << SCL)); //SCL output lowfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}port.PortDLevel |= (byte)1 << SCL;          //set SCL to highfor (int i = 0; i < mCLK * 10; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}ftCommand.add((byte)0x81); //Rd SDAport.PortDLevel |= (byte)1 << SDAO;          //SDA outputs highport.PortDDir |= (byte)1 << SDAO;            //Set SDA as outputfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}}else{ftCommand.add((byte)0x26); //Clock Data Bits In on clock falling edge MSB firstftCommand.add((byte)0);    // 1bitftCommand.add((byte)0x87);}port.PortDLevel &= (byte)(~((byte)1 << SCL));      //SCL outputs low// port.PortDLevel |= (byte)0x02;                  //SDA outputs highport.PortDDir |= (byte)1 << SDAO;                  //Set SDA as outputfor (int i = 0; i < mCLK; i++){ftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);}/*port.PortDLevel |= (byte)1 << SDAO;                    //SDA outputs highport.PortDDir |= (byte)1 << SDAO;                      //Set SDA as outputftCommand.add((byte)0x80);ftCommand.add(port.PortDLevel);ftCommand.add(port.PortDDir);*/gpio.setPortState(port);}

8. IIC读操作

参数slaveAddr表示IIC从设备的IIC地址;addrbit表示IIC设备内部地址的宽度,有效值为0,8,16;addr表示设备内部地址;dat是读入数据缓存;len表示需要读入多少字节数据,因为一次USB通信最多64KB字节,GPIO操作会用到比较多的命令字节,所以建议一次读入数据不要超过1KB。

    public boolean read(byte slaveAddr, byte addrbit, int addr, byte[] dat, int len){if (len == 0)return false;int rdDatLen = len;if (ioCtrlMode == true)rdDatLen = len * 8;int rdLen = (int)(addrbit / 8 + 2 + rdDatLen);if(addrbit == 0)rdLen = (int)(addrbit / 8 + 1 + rdDatLen);int byteWritten = 0, byteRead = 0, dly = 0;//Read USB buffer first to clear the buffer.byteRead  = ftDevice.getQueueStatus();if (byteRead > 0){byte[] tmpbuf = new byte[byteRead];ftDevice.read(tmpbuf, byteRead);}//Create command listftCommand.clear();start();if(addrbit > 0)sendByte(slaveAddr);if (addrbit == 16)sendByte((byte)(addr >> 8));if(addrbit > 0) {sendByte((byte) (addr >> 0));start();}sendByte((byte)(slaveAddr | 0x01));while (--len > 0){receiveByte(true);}receiveByte(false);ftCommand.add((byte)0x87);stop();byte[] cmdBuf = new byte[ftCommand.size()];for (int i = 0; i < ftCommand.size(); i++)cmdBuf[i] = (byte)ftCommand.get(i);ftDevice.write(cmdBuf, cmdBuf.length);byte[] rdBuf = new byte[rdLen];int offset = 0;while (true){byteRead  = ftDevice.getQueueStatus();dly++;if (dly > 0xffff){Log.e("iic read", "read data time out");return false;}if(byteRead == 0)continue;byte[] tmpBuf = new byte[byteRead];ftDevice.read(tmpBuf, byteRead);for (int i = 0; i < tmpBuf.length; i++ ){rdBuf[offset++] = tmpBuf[i];}if (offset >= rdLen)break;try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 0; i < rdBuf.length - rdDatLen; i++){if (ioCtrlMode == true){if ((rdBuf[i] & ((byte)(1 << SDAO))) == (byte)(1 << SDAO)) //Check ACK{Log.e("iic read", "return nack:" +Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));return false;}}else{if ((byte)(rdBuf[i] & 0x01) == (byte)0x01){Log.e("iic read", "return nack:" +Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));return false;}}}for (int i = (int)(rdBuf.length - rdDatLen); i < rdBuf.length; i++){if(ioCtrlMode == true){int max = i + 8;byte tmp = 0;for(; i < max; i++){tmp <<= 1;if ((rdBuf[i] & ((byte)(1 << SDAO))) == (byte)(1 << SDAO)){tmp |= 0x01;}}dat[(i - (rdBuf.length - rdDatLen)) / 8 - 1] = tmp;i--;}elsedat[i - (rdBuf.length - rdDatLen)] = rdBuf[i];}return true;}

将command的数据一次发送给FT4232H后,读回来的数据会在FT4232H的缓冲中,将这些数据读回rdBuf中,这些数据包括IO的电平和ACK信息。

8.1 检查发送地址的ACK是否正确

在发送slaveAddr和addr时会得到(rdBuf.length - rdDatLen)个ACK信息,所以这里会遍历这几个ACK是否为低电平。即

for (int i = 0; i < rdBuf.length - rdDatLen; i++)
{if (ioCtrlMode == true){if ((rdBuf[i] & ((byte)(1 << SDAO))) == (byte)(1 << SDAO)) //Check ACK{Log.e("iic read", "return nack:" +Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));return false;}}else{if ((byte)(rdBuf[i] & 0x01) == (byte)0x01){Log.e("iic read", "return nack:" +Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));return false;}}
}

8.2 接收数据

接下里的数据就是真正的SDA数据,注意读入的是整个PortD的电平,所以需要将对应位组合成字节。即

for (int i = (int)(rdBuf.length - rdDatLen); i < rdBuf.length; i++)
{if(ioCtrlMode == true){int max = i + 8;byte tmp = 0;for(; i < max; i++){tmp <<= 1;if ((rdBuf[i] & ((byte)(1 << SDAO))) == (byte)(1 << SDAO)){tmp |= 0x01;}}dat[(i - (rdBuf.length - rdDatLen)) / 8 - 1] = tmp;i--;}elsedat[i - (rdBuf.length - rdDatLen)] = rdBuf[i];
}

9. IIC写操作

IIC写操作与读操作类似,读回来的数据比较简单,都是ACK信息。

    public boolean write(byte slaveAddr, byte addrbit, int addr, byte[] dat, int len){if (len == 0)return false;int rdLen = (int)(addrbit / 8 + 1 + len);ftCommand.clear();start();sendByte(slaveAddr);if (addrbit == 16)sendByte((byte)(addr >> 8));if(addrbit > 0)sendByte((byte)(addr >> 0));int n = 0;while (len-- > 0){sendByte(dat[n++]);}stop();ftCommand.add((byte)0x87);byte[] cmdBuf = new byte[ftCommand.size()];Log.i("iic write", "Command Length:" + ftCommand.size());for (int i = 0; i < ftCommand.size(); i++) {cmdBuf[i] = (byte) ftCommand.get(i);/*if((i + 1) % 16 == 0){Log.i("iic write", "cmd[" + (i - 15) + "] - cmd[" + i + "]=" +Integer.toHexString((cmdBuf[i - 15] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 14] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 13] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 12] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 11] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 10] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 9] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 8] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 7] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 6] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 5] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 4] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 3] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 2] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 1] & 0x000000FF) | 0xFFFFFF00).substring(6) + " " +Integer.toHexString((cmdBuf[i - 0] & 0x000000FF) | 0xFFFFFF00).substring(6) + " ");}*/}int byteRead = 0, dly = 0;Log.i("iic write", "write command buffer");ftDevice.write(cmdBuf, cmdBuf.length);Log.i("iic write", "read response data");while (true){byteRead  = ftDevice.getQueueStatus();dly++;if (dly > 0xffff){Log.e("iic write", "time out");return false;}if (byteRead >= rdLen)break;try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}byte[] rdBuf = new byte[byteRead];ftDevice.read(rdBuf, byteRead);Log.i("iic write", "read buffer len:" + rdBuf.length);for (int i = 0; i < rdBuf.length; i++){if (ioCtrlMode == true){if ((rdBuf[i] & ((byte)(1 << SDAO))) == (byte)(1 << SDAO)) //Check ACK{Log.e("iic write", "return nack" + i + ":"+Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));//return false;}}else{if ((byte)(rdBuf[i] & 0x01) == (byte)0x01){Log.e("iic write", "return nack" + i + ":"+Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6));return false;}}}Log.i("iic write", "return ok");return true;}

10. 验证

ADBUS4作为SCL,ADBUS5作为SDA,接一颗IIC接口的EEPROM芯片。验证代码:

    TextView tvERomWr;TextView tvERomRd;void ERomTest(){if(mpsseDev == null)return;byte[] wrBuf = new byte[10];byte[] rdBuf = new byte[10];tvERomWr.setText("");for(int i = 0; i < wrBuf.length; i++){wrBuf[i] = (byte)(Math.random() * 256);tvERomWr.append(Integer.toHexString((wrBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6) + " ");}mpsseDev.iic.write((byte)0xA0, (byte)16, 0, wrBuf, wrBuf.length);mpsseDev.iic.read((byte)0xA0, (byte)16, 0, rdBuf, rdBuf.length);tvERomRd.setText("");for(int i = 0; i < rdBuf.length; i++){tvERomRd.append(Integer.toHexString((rdBuf[i] & 0x000000FF) | 0xFFFFFF00).substring(6) + " ");}}

初始化IIC

mpsseDev.iic.init((byte)2, (byte)4, (byte)5);

测试结果:

FT4232H Android开发 6 - USB转IIC相关推荐

  1. FT4232H Android开发 4 - USB转GPIO

    USB转GPIO利用的是FT4232H的MPSSE模式.FT4232H虽然有4路UART,但是只能支持2路MPSSE(Channel A和Channel B).其中Channel A对应ADBUS0 ...

  2. FT4232H Android开发 5 - USB转SPI

    目录 1.  基本原理 2. 设置频率 3. CS电平控制 4. SPI写的实现 5. SPI读的实现 6. 验证 当FT4232H作为MPSSE设备时,DBUS0固定为CLK输出,DBUSD1固定为 ...

  3. FT4232H Android开发 3 - USB转UART

    目录 1. 新建继承FTDevice的类usb2uart 2.  函数open 3. 函数close 4. 函数write 5. 函数read 6. 验证 6.1 发送数据 6.2 处理read的线程 ...

  4. FT4232H Android开发 2 - 建立一个FTDI设备的样板工程

    目录 1. 新建一个FTDevice的类 2. 导入用到的类 3.  添加变量 4. 定义构造函数 5. 成员函数selectDevice 6. 成员函数getDeviceType 7. 成员函数cl ...

  5. FT4232H Android开发 1 - 建立环境

    系统:Windows 10 64bit IDE: Android Studio 硬件平台:FT4232H Mini Module 1. 新建工程 2. 下载J2XX https://ftdichip. ...

  6. Android Camera相机开发示例、Android 开发板 USB摄像头采集、定期拍照、定时拍照,安卓调用摄像头拍照、Android摄像头预览、监控,USB摄像头开发、摄像头监控代码

    我们有个需求,在机器上加个摄像头,定时拍照: 我到网上搜索,发现没有快速上手和简单使用的: 个人感觉,大部分博客写得很乱,或者长篇大论: 而我只想简单实现功能,并不打算学习多少理论: 下面代码是我写来 ...

  7. Android开发之USB数据通信

    Android开发中USB串口通信开发主要涉及到以下几个类及相应的方法: 1 ,UsbManager:负责管理USB设备的类,你可以在相应代码中通过以下方法获得 //获取UsbManager实例方法 ...

  8. mac android手机调试,mac os开发android应用通过usb真机调试

    当前开发用的ari,sublime + webstrom 开发node.js还比较流畅,还没有出现被堵被坑的局面. 尝试开发android应用时,各种坑,其中一个比较深的坑就是今天要和大家分享的. m ...

  9. B4A 或其它Android开发平台连接USB设备进行调试

    -   配置Android开发环境.   (Basic4android新手指南-1 搭建环境.pdf) -  首先下载Android设备相关的自身驱动. - 下载安装USB驱动管理软件 UsbDriv ...

最新文章

  1. VirtualBox装ghost XP
  2. RocketMQ--生产者与消费者的简单示例
  3. linux 环境下配置ftp服务器
  4. MySQL数据库服务器优化详细
  5. 对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全
  6. MDK调试:设置断点处,代码运行的次数
  7. 萌新向Python数据分析及数据挖掘 第二章 pandas 第二节 Python Language Basics, IPython, and Jupyter Notebooks...
  8. python的for语句要用冒号吗_python中循环的写法 for
  9. ffmpeg 将拆分的数据合成一帧_FFMPEG 视频分割和合并
  10. 51单片机驱动TM1640实现多个LED灯控制
  11. android webview打开pdf文件
  12. Excel列宽在哪里设置?Excel怎么设置行高和列宽
  13. exdoll机器人_打造国内领先的定制化人工智能机器人品牌, EXDOLL新品惊艳亮相...
  14. CDN是什么?一分钟带你了解CDN
  15. ds18b20程序c语言,单片机中使用DS18B20温度传感器C语言程序(参考6)
  16. mysql 导入tsv文件,MySQL导出TSV格式文件
  17. 中煤哈密智能汽车电子衡系统过磅流程
  18. 高精度除法(高精度除以高精度)
  19. 运用python求次方
  20. 编程路上的重要概念记录

热门文章

  1. 电磁流量计的工作原理及特点
  2. 可爱的二代身份证终于到手了
  3. 在中国应如何改良Scrum框架
  4. 每日一个css小技巧 6/10 水平垂直居中
  5. 迅雷苹果版怎么下载,iOS下载迅雷安装地址办法,手机安装迅雷无需电脑beta
  6. 汽车美容管理软件的选择要点
  7. 旅游系统(SSM框架+MySQL+Redis+VUE)前端页面代码
  8. 如何构建完善的质量追溯管理 | MES
  9. 线扫相机 编码器_VisionPro连接线扫相机使用说明
  10. 细化公诉环节适用刑事和解程序