Android Things:外设I/O接口-SPI

来源:互联网 发布:m1213nf mfp mac扫描 编辑:程序博客网 时间:2024/04/25 08:07

一、接口简介


串行外围接口(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这个信号就不必须。
这里写图片描述

二、接口使用


  1. 打开连接
    创建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);            }        }    }}
  2. 配置时钟和数据模式
    在一个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}
  3. 传输数据

    • SPI支持半双工和全双工数据传输。
    • 大多数应用程序应该都使用半双工write()或read()方法与Slave设备交换数据。
    // Half-duplex data transferpublic 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 transferpublic void sendCommand(SpiDevice device, byte[] buffer) throws IOException {      byte[] response = new byte[buffer.length];      device.transfer(buffer, response, buffer.length);    ...}
  4. 关闭连接
    当你完成和外部设备的通信,调用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块
    • 面包板 1块
    • Max7219点阵模块
    • 杜邦线(公对母)若干
  2. 电路搭建(注意,没有找个对应的元器件图,下图多一个引脚)
    这里写图片描述
  3. 代码编写
    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

  4. 运行结果
    运行程序,显示器上闪烁显示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。(甭客气!尽情的扫描或者长按!)
qq群

1 0
原创粉丝点击