串行外围接口(Serial Peripheral Interface)设备通常需要快速的数据传输速率。SPI适合高带宽使用情况,如外部非易失性存储器和图形显示,许多传感器除了I2C也支持SPI。
SPI总线是一种同步的串行接口:这意味着它依赖于共享的时钟信号来同步设备之间的数据传输。控制时钟信号的设备被称为master。其它所有连接的外设被认为是Slaves。每个设备连接到同一组数据信号以形成总线。从理论上讲,SPI数据传输率是仅限于master切换时钟信号的快慢。时钟速度通常在16MHz到25MHz范围。高速共享时钟允许SPI外设更快的传输数据,比UART错误更少。
SPI支持全双工数据传输:意味着master和slave可以同时交换数据。为了支持全双工传输,总线必须提供下列单独的信号,使得SPI最少四线接口:
SPI支持同一总线连接多个从设备:和I2C不同,slave设备使用硬件寻址。每个slave都需要外部芯片选择信号,来让master定位特定的设备作为数据传输的目标。如果仅仅使用一个slave这个信号就不必须。
打开连接
创建PeripheralManagerService对象,使用你想打开端口的名称,调用open()方法打开连接。
public class HomeActivity extends Activity {
// SPI Device Name
private static final String SPI_DEVICE_NAME = ...;
private SpiDevice mDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Attempt to access the SPI device
try {
PeripheralManagerService manager = new PeripheralManagerService();
mDevice = manager.openSpiDevice(SPI_DEVICE_NAME);
} catch (IOException e) {
Log.w(TAG, "Unable to access SPI device", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDevice != null) {
try {
mDevice.close();
mDevice = null;
} catch (IOException e) {
Log.w(TAG, "Unable to close SPI device", e);
}
}
}
}
配置时钟和数据模式
在一个SPI总线连接建立之后,配置数据传输速率和操作模式来匹配同一条总线上的Slave设备。为了成功的传输数据,在总线的所有设备必须具有相同的时钟和数据格式行为。
设置SPI模式,定义了时钟信号的极性和相位。你选择的属性基于三个属性:
支持以下模式:
设置如下SpiDevice参数:
public void configureSpiDevice(SpiDevice device) throws IOException {
// Low clock, leading edge transfer
device.setMode(SpiDevice.MODE0);
device.setFrequency(16000000); // 16MHz
device.setBitsPerWord(8); // 8 BPW
device.setBitJustification(false); // MSB first
}
传输数据
// Half-duplex data transfer
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
// Shift data out to slave
device.write(buffer, buffer.length);
// Read the response
byte[] response = new byte[32];
device.read(response, response.length);
...
}
// Full-duplex data transfer
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
byte[] response = new byte[buffer.length];
device.transfer(buffer, response, buffer.length);
...
}
关闭连接
当你完成和外部设备的通信,调用close()方法关闭连接并释放资源。此外在现有端口关闭之前,你不能打开相同端口的新连接。
public class HomeActivity extends Activity {
// SPI Device Name
private static final String SPI_DEVICE_NAME = ...;
private SpiDevice mDevice;
@Override
protected void onDestroy() {
super.onDestroy();
if (mDevice != null) {
try {
mDevice.close();
mDevice = null;
} catch (IOException e) {
Log.w(TAG, "Unable to close SPI device", e);
}
}
}
}
下面我们就通过spi接口,控制Max7219模块的显示来演示接口的使用。
代码编写
SpiDemo\app\src\main\java\com\chengxiang\spidemo\MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String SPI_DEVICE_NAME = "SPI0.0";
private static final byte OP_NOOP = 0;
private static final byte OP_DIGIT0 = 1;
private static final byte OP_DIGIT1 = 2;
private static final byte OP_DIGIT2 = 3;
private static final byte OP_DIGIT3 = 4;
private static final byte OP_DIGIT4 = 5;
private static final byte OP_DIGIT5 = 6;
private static final byte OP_DIGIT6 = 7;
private static final byte OP_DIGIT7 = 8;
private static final byte OP_DECODEMODE = 9;
private static final byte OP_INTENSITY = 10;
private static final byte OP_SCANLIMIT = 11;
private static final byte OP_SHUTDOWN = 12;
private static final byte OP_DISPLAYTEST = 15;
public static final byte[] ALIEN_FRAME_1 = new byte[]{
(byte)0b00001000,
(byte)0b00011000,
(byte)0b00001000,
(byte)0b00001000,
(byte)0b00001000,
(byte)0b00001000,
(byte)0b00001000,
(byte)0b00000000
};
public static final byte[] ALIEN_FRAME_2 = new byte[]{
(byte)0b00011000,
(byte)0b00100100,
(byte)0b00100100,
(byte)0b00000100,
(byte)0b00001000,
(byte)0b00010000,
(byte)0b00111110,
(byte)0b00000000
};
public static final byte[] ALIEN_FRAME_3 = new byte[]{
(byte)0b00011000,
(byte)0b00100100,
(byte)0b00000100,
(byte)0b00011000,
(byte)0b00000100,
(byte)0b00100100,
(byte)0b00011000,
(byte)0b00000000
};
public static final byte[][] FRAMES = new byte[][]{ALIEN_FRAME_1, ALIEN_FRAME_2, ALIEN_FRAME_3};
private SpiDevice mDevice;
private byte[] spidata = new byte[2];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
//打开SPI接口连接
PeripheralManagerService manager = new PeripheralManagerService();
mDevice = manager.openSpiDevice(SPI_DEVICE_NAME);
//设置SPI信号模式、频率、每个字比特数等
mDevice.setMode(SpiDevice.MODE0);
mDevice.setFrequency(1000000);
mDevice.setBitsPerWord(8);
mDevice.setBitJustification(false);
//设置译码模式,0-用于驱动LED点阵屏
spiTransfer(OP_DECODEMODE, 0);
//设置扫描限制,显示7行
spiTransfer(OP_SCANLIMIT, 7);
//设置显示器检测,0-一般模式
spiTransfer(OP_DISPLAYTEST, 0);
//设置停机为false
spiTransfer(OP_SHUTDOWN, 1);
//设置显示强度为3
spiTransfer(OP_INTENSITY, 15);
while (true) {
for (int i = 0; i < FRAMES.length; i++) {
for (int j = 0; j < FRAMES[i].length; j++) {
spiTransfer((byte) (OP_DIGIT0 + j), FRAMES[i][j]);
}
Thread.sleep(500);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDevice != null) {
try {
mDevice.close();
mDevice = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void spiTransfer(byte opcode, int data) throws IOException {
spidata[0] = opcode;
spidata[1] = (byte) data;
mDevice.write(spidata, 2);
}
}
代码库:https://github.com/ThingsDeveloper/spidemo
1.抛弃各种找元器件的烦恼,来“1024工场”旗舰店,一次性买到你所想要的:树莓派套装—专为Android Things打造。
电脑用户,点击如下链接进入淘宝宝贝页面:
https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263
手机用户,打开淘宝客户端扫描二维码:
2.完整和持续更新的《使用Android打开物联网开发大门——Andoid Thigns开发》文档,欢迎大家阅读!
https://www.kancloud.cn/workshop1024/android_things_develop/360773
3.新技术,新未来!欢迎大家关注“1024工场”微信服务号,时刻关注我们的最新的技术讯息。(甭客气!尽情的扫描或者长按!)
4.加入“Android Things开发”QQ讨论群,一起学习一起Hi。(甭客气!尽情的扫描或者长按!)