1. SPI 通讯
简介
串行外设接口(Serial Peripheral Interface, SPI)是微控制器使用的同步串行数据协议,用于在短距离内快速与一个或多个外围设备通信。它还可以用于两个微控制器之间的通信。
该接口一般使用4条线进行连接:
- SCK - 主机驱动的串行时钟,用于同步数据传输;
- MOSI(Master Out Slave In)- Master line,用于Master向Slave发送数据
- MISO(Master In Slave Out)- Slave line,用于Slave向Master发送数据
- SS(Slave Select)- 外设选择线,这条线也称为 CS(Chip Select,芯片选择线或简称片选)不同引脚分配给所有外设,输出0代表选取某设备,避免由于线路忙导致的错误传输。
SPI 时序和工作模式
上图中的时序是 SPI 不同的通讯模式,SSEL、SCK、MOSI 信号都由主机控制产生,而 MISO 的信 号由从机产生,主机通过该信号线读取从机的数据。MOSI 与 MISO 的信号只在 SSEL 为低 电平的时候才有效,在 SCK 的每个时钟周期 MOSI 和 MISO 传输一位数据。
SPI 一共有四种通讯模式,它们的主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻,涉及到两个概念:
时钟极性 CPOL 指 SPI 通讯设备空闲时,SCK 信号线的电平信号(即 SPI 通讯开始前、 NSS 线为高电平时 SCK 的状态)。
CPOL=0 时, SCK 在空闲状态时为低电平,CPOL=1 时,则相反。
时钟相位 CPHA 指数据的采样的时刻,CPHA=0,表示数据采样是在第1个边沿(上升或下降),数据发送在第2个边沿;CPHA=1,表示数据采样是在第2个边沿,数据发送在第1个边沿
根据 CPOL 及 CPHA 的不同状态,SPI 有以下四种工作模式,主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是“模式 0”与“模式 3”,因为它们都是在上升沿采样数据,不用去在乎时钟的初始电平是什么,只要在上升沿采集数据就行。
需要注意的是:
我们的主设备能够控制时钟,因为我们的SPI通信并不像UART或者IIC通信那样有专门的通信周期,有专门的通信起始信号,有专门的通信结束信号;所以我们的SPI协议能够通过控制时钟信号线,当没有数据交流的时候我们的时钟线要么是保持高电平要么是保持低电平。
内部工作机制
SSPSR 是 SPI 设备内部的移位寄存器(Shift Register). 它的主要作用是根据 SPI时钟信号状态, 往 SSPBUF 里移入或者移出数据, 每次移动的数据大小由 Bus-Width 以及 Channel-Width 所决定.
SPI接口在内部硬件实际上是两个简单的移位寄存器,传输的数据为8位,在主器件产生的从器件使能信号和移位脉冲下,按位传输,高位在前,低位在后。
特点
-
优点
– 支持全双工通信
– 通信简单
– 数据传输速率块 -
缺点
– 没有指定的流控制,没有应答机制确认是否接收到数据,所以跟 IIC总线协议比较在数据可靠性上有一定的缺陷。
2. Arduino + u8g2 + oled
-
材料准备
u8g2库安装
arduino uno
六针 oled 屏幕 -
接线
GND:电源地
VCC:2.2V~5.5V
SCL(D0):CLK 时钟 (高电平 2.2V~5.5V)
SDA(D1):MOSI 数据(高电平 2.2V~5.5V)
RST:复位(高电平 2.2V~5.5V)
D/C:数据/命令(高电平 2.2V~5.5V)
六针oled屏没有CS接口,其在硬件中直接接地(只有一个SPI从机时CS可以不使用);
此外,Arduino发送指令和数据到 OLED,OLED 并不需要反馈任何数据。因此, OLED 模块是只有 MOSI(SDA)引脚,没 有 MISO 引脚的。
- 代码
#include <Arduino.h>
#include <SPI.h>
#include <U8g2lib.h>
// 前缀_U8G2
// 驱动芯片_SSD1306
// 屏幕尺寸_128X64
// 显示器名称_NONAME
// 缓存大小_F/1/2
// 通信协议4W_SW_SPI-四线软件模拟SPI总线
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 10,
/* cs=*/ 12, /* dc=*/ 8, /* reset=*/ 9);
void setup(void)
{
u8g2.begin(); //选择U8G2模式,或者U8X8模式
}
void loop(void)
{
u8g2.clearBuffer(); // 清除内部缓冲区
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory
u8g2.drawStr(0,20,"OLED TEST!"); // write something to the internal memory
u8g2.drawStr(0,30,"Welcome to U8G2!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(1000);
}
参考资料:
SPI协议和OLED详解及裸机程序开发分析(软件结构模拟SPI)
SPI工作方式简介
SPI通信协议(SPI总线)学习
u8g2 官方文档
arduino驱动4线/6线OLED屏幕(I2C/SPI通讯)
Auduino + EEPROM 官方文档
SPI总线协议及SPI时序图详解
嵌入式STM32 HAL_IIC EEPROM
手撸SPI接口oled屏幕驱动(stm32)