FT4232H Android开发 6 - USB转IIC
目录
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相关推荐
- FT4232H Android开发 4 - USB转GPIO
USB转GPIO利用的是FT4232H的MPSSE模式.FT4232H虽然有4路UART,但是只能支持2路MPSSE(Channel A和Channel B).其中Channel A对应ADBUS0 ...
- FT4232H Android开发 5 - USB转SPI
目录 1. 基本原理 2. 设置频率 3. CS电平控制 4. SPI写的实现 5. SPI读的实现 6. 验证 当FT4232H作为MPSSE设备时,DBUS0固定为CLK输出,DBUSD1固定为 ...
- FT4232H Android开发 3 - USB转UART
目录 1. 新建继承FTDevice的类usb2uart 2. 函数open 3. 函数close 4. 函数write 5. 函数read 6. 验证 6.1 发送数据 6.2 处理read的线程 ...
- FT4232H Android开发 2 - 建立一个FTDI设备的样板工程
目录 1. 新建一个FTDevice的类 2. 导入用到的类 3. 添加变量 4. 定义构造函数 5. 成员函数selectDevice 6. 成员函数getDeviceType 7. 成员函数cl ...
- FT4232H Android开发 1 - 建立环境
系统:Windows 10 64bit IDE: Android Studio 硬件平台:FT4232H Mini Module 1. 新建工程 2. 下载J2XX https://ftdichip. ...
- Android Camera相机开发示例、Android 开发板 USB摄像头采集、定期拍照、定时拍照,安卓调用摄像头拍照、Android摄像头预览、监控,USB摄像头开发、摄像头监控代码
我们有个需求,在机器上加个摄像头,定时拍照: 我到网上搜索,发现没有快速上手和简单使用的: 个人感觉,大部分博客写得很乱,或者长篇大论: 而我只想简单实现功能,并不打算学习多少理论: 下面代码是我写来 ...
- Android开发之USB数据通信
Android开发中USB串口通信开发主要涉及到以下几个类及相应的方法: 1 ,UsbManager:负责管理USB设备的类,你可以在相应代码中通过以下方法获得 //获取UsbManager实例方法 ...
- mac android手机调试,mac os开发android应用通过usb真机调试
当前开发用的ari,sublime + webstrom 开发node.js还比较流畅,还没有出现被堵被坑的局面. 尝试开发android应用时,各种坑,其中一个比较深的坑就是今天要和大家分享的. m ...
- B4A 或其它Android开发平台连接USB设备进行调试
- 配置Android开发环境. (Basic4android新手指南-1 搭建环境.pdf) - 首先下载Android设备相关的自身驱动. - 下载安装USB驱动管理软件 UsbDriv ...
最新文章
- VirtualBox装ghost XP
- RocketMQ--生产者与消费者的简单示例
- linux 环境下配置ftp服务器
- MySQL数据库服务器优化详细
- 对于线程安全的集合类(例如Vector)的任何操作是不是都能保证线程安全
- MDK调试:设置断点处,代码运行的次数
- 萌新向Python数据分析及数据挖掘 第二章 pandas 第二节 Python Language Basics, IPython, and Jupyter Notebooks...
- python的for语句要用冒号吗_python中循环的写法 for
- ffmpeg 将拆分的数据合成一帧_FFMPEG 视频分割和合并
- 51单片机驱动TM1640实现多个LED灯控制
- android webview打开pdf文件
- Excel列宽在哪里设置?Excel怎么设置行高和列宽
- exdoll机器人_打造国内领先的定制化人工智能机器人品牌, EXDOLL新品惊艳亮相...
- CDN是什么?一分钟带你了解CDN
- ds18b20程序c语言,单片机中使用DS18B20温度传感器C语言程序(参考6)
- mysql 导入tsv文件,MySQL导出TSV格式文件
- 中煤哈密智能汽车电子衡系统过磅流程
- 高精度除法(高精度除以高精度)
- 运用python求次方
- 编程路上的重要概念记录