一、接口简介
串行外围接口(Serial Peripheral Interface)设备通常需要快速的数据传输速率。SPI适合高带宽使用情况,如外部非易失性存储器和图形显示,许多传感器除了I2C也支持SPI。
SPI总线是一种同步的串行接口:这意味着它依赖于共享的时钟信号来同步设备之间的数据传输。控制时钟信号的设备被称为master。其它所有连接的外设被认为是Slaves。每个设备连接到同一组数据信号以形成总线。从理论上讲,SPI数据传输率是仅限于master切换时钟信号的快慢。时钟速度通常在16MHz到25MHz范围。高速共享时钟允许SPI外设更快的传输数据,比UART错误更少。
SPI支持全双工数据传输:意味着master和slave可以同时交换数据。为了支持全双工传输,总线必须提供下列单独的信号,使得SPI最少四线接口:
- Master出Slave入(MOSI);
- Mater入Slave出(MISO);
- 共享时钟信号(CLK);
- 共同的接地参考(GND);
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模式,定义了时钟信号的极性和相位。你选择的属性基于三个属性:
- 闲置级别:当没有数据传输的时候,时钟信号的级别(或高或低);
- 前沿:每个时钟脉冲的前沿;
- 后沿:每个时钟脉冲前沿相反过渡;
支持以下模式:
- MODE0-时钟信号闲置为低,数据传输在前时钟边沿;
- MODE1-时钟信号闲置为高,数据传输在后时钟边沿;
- MODE2-时钟信号闲置为低,数据传输在前时钟边沿;
- MODE3-时钟信号闲置为高,数据传输在后时钟边沿;
设置如下SpiDevice参数:
- 频率:以Hz为单位指定共享时钟信号。时钟信号的能力在不同的设备之间有所不同。在设置这个值之前,你应该确认下你设备支持的频率。
- xxx:指定在总线上传输的每个字节中比特的顺序,这也被称为数据的字节序。默认情况下,数据将会把最高有效位(MSB)首先发送。
- 每个字的比特:配置一次传输的比特数,…,默认的值是8比特每字。
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 }
传输数据
- SPI支持半双工和全双工数据传输。
- 大多数应用程序应该都使用半双工write()或read()方法与Slave设备交换数据。
// 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); ... }
- 要想执行全双工交换,使用transfer()方法。这个而方法接受读和写两个缓冲。写缓冲包含发送给Slave的数据,然而读缓冲是空的来接受Slave的数据。数据的长度必须小于或者等于数据缓冲的最小缓冲的大小。常见的全双工传输缓冲区大小是相等的。
// 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模块的显示来演示接口的使用。
- 硬件准备
- 树莓派开发板 1块
- 面包板 1块
- Max7219点阵模块
- 杜邦线(公对母)若干
- 电路搭建(注意,没有找个对应的元器件图,下图多一个引脚)
代码编写
SpiDemo\app\src\main\java\com\chengxiang\spidemo\MainActivity.javapublic 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); } }
- 运行结果
运行程序,显示器上闪烁显示1,2,3数字如下:
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。(甭客气!尽情的扫描或者长按!)