1.SPI
1.1 简介
spi是串行外围设备接口,是一种同步、全双工、主从式接口。
产生时钟信号的设备为"主机"。
芯片的管脚上只占用四根线:
MOSI: 主设备数据输出,从设备数据输入。
MISO: 从设备数据输出,主设备数据输入。
SCK: 时钟信号,由主设备发出。
CS(NSS): 从设备选择信号,由主设备控制。CS为低电平时选择从设备。
三线制SPI没有MISO,或者MISO和MOSI共线。
1.2 IIC与SPI区别
1. IIC只需要两根信号线,而标准的SPI需要4根信号线,若存在多个从设备,信号需要很多,虽然SPI由三线制,但是片选线需要一对一。
2.如果要使用高速数据传输,那么SPI是必然的选择。因为SPI是全双工,而IIC不是。SPI没定义速度限制,一般的实现通常能达到甚至超过10Mbps。IIC最高速度也就快速模式(1Mbps)和高速模式(3.4Mbps)。
SPI的缺陷:
SPI有一个非常大的缺陷,没有标准的协议,SPI比较混乱,所以衍生出多个版本,但是没有本质差异。
2.SPI接线
以下是一个常见的SPI接线方式示例,使用ESP32S3:
- SCK: 连接到Arduino的13号引脚。
- MISO: 连接到Arduino的12号引脚。
- MOSI: 连接到Arduino的11号引脚。
- SS: 连接到Arduino的10号引脚。
请确保连接的外部设备也正确接线,从设备的SCK、MISO、MOSI、SS引脚连接到相应的ESP32引脚。
3.相关API
3.1 初始化SPI
void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
- 四个参数分别对应SPI的四根信号线,缺省时为默认值。
3.2 配置SPI
//设置高低位先行
void setBitOrder(uint8_t bitOrder);
//设置SPI模式
void setDataMode(uint8_t dataMode);
//设置频率
void setFrequency(uint32_t freq);
//设置分频,和设置频率任选其一即可
void setClockDivider(uint32_t clockDiv)
3.3 配置并启动SPI
void SPIClass::beginTransaction(SPISettings settings)
SPISettings() :_clock(1000000), _bitOrder(SPI_MSBFIRST), _dataMode(SPI_MODE0) {}
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) :_clock(clock), _bitOrder(bitOrder), _dataMode(dataMode) {}
- clock 时钟频率。
- bitOrder 高位先行或者低位先行,MSB为1,LSB为0。
LSB:least significant bit 表示二进制数据的最低位
MSB : most significant bit 表示二进制数据的最高位
spi传输数据时有两种方式:MSB first 和LSB first
- dataMode SPI模式,如下。
使用方法:
SPI.beginTransaction(SPISettings(1000000, SPI_MSBFIRST, SPI_MODE0));
3.4 发送数据并接收返回数据
uint8_t SPIClass::transfer(uint8_t data)
uint16_t SPIClass::transfer16(uint16_t data)
uint32_t SPIClass::transfer32(uint32_t data)
3.5 片选控制
void SPIClass::setHwCs(bool use)
4.示例
这里以w25q128读取设备ID为例:
void SPI_W25Q128_init(void)
{
//片选线引脚初始化
pinMode(SS,OUTPUT);
//SPI引脚配置为默认引脚
SPI.begin();
//配置SPI
SPI.beginTransaction(SPISettings(1000000, SPI_MSBFIRST, SPI_MODE0));
}
void SPI_W25Q128(void)
{
//选择从设备
digitalWrite(SS,LOW);
//要发送的数据
uint8_t sendData = 0x90;
//发送数据并接受返回数据
SPI.transfer(sendData);
SPI.write(0);
SPI.write16(0);
uint16_t receivedData = SPI.transfer16(0xffff);
//取消选择从设备
digitalWrite(SS,HIGH);
// 打印输出到串口
Serial.print("Sent Data: ");
Serial.println(sendData, HEX);
Serial.print("Received Data: ");
Serial.println(receivedData, HEX);
// 延时等待
delay(1000);
}