有了UART,为什么还有IIC和SPI?
大家好,我是良许。
在嵌入式开发中,我们经常会接触到UART、IIC(I2C)和SPI这三种通信协议。
很多初学者会有疑问:既然UART已经可以实现串行通信了,为什么还需要IIC和SPI呢?
今天我们就来深入聊聊这个话题,看看这三种通信协议各自的特点和应用场景。
1. 三种通信协议的基本特点
1.1 UART的特点与局限
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是我们最常接触的串行通信协议之一。
它的工作原理相对简单,只需要两根线就能实现全双工通信:一根TX(发送)、一根RX(接收),再加上一根GND(地线)。
UART的优点很明显:实现简单,使用方便,几乎所有的MCU都支持。
在调试阶段,我们经常用UART来打印日志信息,这也是为什么串口调试助手成为嵌入式工程师必备工具的原因。
但是,UART也有它的局限性。
首先,UART是点对点通信,一个UART接口只能连接一个设备。
如果你的STM32需要同时和多个传感器通信,就需要多个UART接口,这会占用大量的GPIO资源。
其次,UART没有时钟线,通信双方必须事先约定好波特率,如果波特率不匹配,通信就会出错。
最后,UART的传输速度相对较慢,常用的波特率是9600、115200等,对于需要高速传输的场景就显得力不从心了。
1.2 IIC的独特优势
IIC(Inter-Integrated Circuit)是由飞利浦公司开发的一种两线式串行总线协议。
它只需要两根线:SCL(时钟线)和SDA(数据线),就可以实现多主多从的通信架构。
IIC最大的优势在于它的多设备支持能力。
在同一条IIC总线上,你可以挂载多达127个设备(理论上),每个设备都有自己独特的7位地址(也支持10位地址)。
这意味着,用STM32的一个IIC接口,你就可以同时连接多个传感器、EEPROM、RTC等设备,大大节省了GPIO资源。
在实际项目中,我曾经用一个IIC总线同时连接了温湿度传感器、光照传感器、OLED显示屏和一个EEPROM芯片。
如果用UART实现同样的功能,至少需要4个UART接口,这在资源有限的MCU上是不现实的。
IIC的另一个优点是支持多主机模式。
虽然在实际应用中多主机场景不多见,但在某些复杂系统中,这个特性还是很有用的。
比如在汽车电子系统中,多个ECU可能需要共享同一条IIC总线来访问某些共享资源。
1.3 SPI的高速特性
SPI(Serial Peripheral Interface)是由摩托罗拉公司推出的一种高速全双工同步串行通信协议。
标准的SPI需要四根线:SCLK(时钟线)、MOSI(主机输出从机输入)、MISO(主机输入从机输出)和SS/CS(片选信号)。
SPI最突出的特点就是速度快。
因为它是同步通信,有独立的时钟线,所以不存在波特率不匹配的问题。
SPI的时钟频率可以达到几十MHz甚至上百MHz,这使得它非常适合需要高速数据传输的场景,比如SD卡、Flash存储器、高速ADC/DAC等。
在我之前做的一个汽车仪表项目中,需要驱动一块TFT彩屏显示复杂的图形界面。
我们选择了SPI接口的屏幕,时钟频率设置到了36MHz,这样才能保证画面刷新足够流畅。
如果用UART或者IIC,根本无法满足这个速度要求。
SPI也支持多从机模式,但和IIC不同的是,每增加一个从机设备,就需要额外占用一个GPIO作为片选信号。
这是SPI的一个小缺点,但考虑到它的高速特性,这点代价还是值得的。
2. 实际应用场景对比
2.1 何时选择UART
UART最适合的场景是点对点的中低速通信。比如:
调试输出是UART最常见的应用。
我们在开发STM32程序时,经常会用printf函数通过UART输出调试信息。
这种场景下,UART的简单易用性是其他协议无法比拟的。
下面是一个简单的HAL库UART输出示例:
// UART初始化(通常由CubeMX自动生成)
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&huart1);
}
// 重定向printf到UART
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
// 使用示例
int main(void)
{
HAL_Init();
MX_USART1_UART_Init();
printf("System initialized!\r\n");
printf("Temperature: %d degrees\r\n", temperature);
while(1)
{
// 主循环
}
}
除了调试,UART还常用于和PC通信、GPS模块通信、蓝牙模块通信等场景。
这些场景的共同特点是:设备数量少(通常就一个),对速度要求不高,但需要可靠的数据传输。
2.2 何时选择IIC
IIC最适合连接多个低速外设的场景。
在我做过的项目中,IIC的典型应用包括:
传感器网络是IIC的主战场。比如在一个环境监测系统中,你可能需要同时读取温湿度传感器(如SHT30)、气压传感器(如BMP280)、光照传感器(如BH1750)等。
这些传感器的数据更新频率不高,但数量多,用IIC连接最合适。
// IIC读取SHT30温湿度传感器示例
I2C_HandleTypeDef hi2c1;
#define SHT30_ADDR 0x44 << 1 // 7位地址左移1位
void SHT30_ReadData(float *temperature, float *humidity)
{
uint8_t cmd[2] = {0x2C, 0x06}; // 高重复性测量命令
uint8_t data[6];
// 发送测量命令
HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR, cmd, 2, HAL_MAX_DELAY);
HAL_Delay(20); // 等待测量完成
// 读取数据
HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR, data, 6, HAL_MAX_DELAY);
// 计算温湿度
uint16_t temp_raw = (data[0] << 8) | data[1];
uint16_t humi_raw = (data[3] << 8) | data[4];
*temperature = -45 + 175 * ((float)temp_raw / 65535.0);
*humidity = 100 * ((float)humi_raw / 65535.0);
}
// 在同一总线上读取多个传感器
void ReadAllSensors(void)
{
float temp, humi;
uint16_t light;
// 读取温湿度
SHT30_ReadData(&temp, &humi);
printf("Temperature: %.2f C, Humidity: %.2f %%\r\n", temp, humi);
// 读取光照(假设BH1750地址为0x23)
// ... BH1750读取代码
// 所有传感器共用同一个IIC总线
}
EEPROM存储也是IIC的常见应用。
很多小容量的EEPROM芯片(如AT24C02、AT24C256)都使用IIC接口。
在需要保存系统配置参数、校准数据等场景下,IIC EEPROM是很好的选择。
2.3 何时选择SPI
SPI最适合需要高速数据传输的场景。典型应用包括:
Flash存储器是SPI的重要应用领域。
在我参与的一个数据记录仪项目中,需要存储大量的传感器数据,我们选择了SPI接口的NOR Flash芯片(如W25Q128)。
SPI的高速特性保证了数据能够快速写入和读取。
// SPI Flash写入示例(W25Q128)
SPI_HandleTypeDef hspi1;
#define W25Q128_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define W25Q128_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
void W25Q128_WritePage(uint32_t addr, uint8_t *data, uint16_t len)
{
uint8_t cmd[4];
// 写使能
W25Q128_CS_LOW();
cmd[0] = 0x06; // Write Enable命令
HAL_SPI_Transmit(&hspi1, cmd, 1, HAL_MAX_DELAY);
W25Q128_CS_HIGH();
// 页编程
W25Q128_CS_LOW();
cmd[0] = 0x02; // Page Program命令
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
HAL_SPI_Transmit(&hspi1, cmd, 4, HAL_MAX_DELAY);
HAL_SPI_Transmit(&hspi1, data, len, HAL_MAX_DELAY);
W25Q128_CS_HIGH();
// 等待写入完成
HAL_Delay(5);
}
显示屏驱动也经常使用SPI。
TFT彩屏、OLED屏等都有SPI接口版本。
由于显示屏需要传输大量的像素数据,SPI的高速特性能够保证画面流畅显示。
高速ADC/DAC也是SPI的典型应用。
在音频处理、高速数据采集等场景下,SPI能够提供足够的带宽来传输采样数据。
3. 三种协议的技术细节对比
3.1 硬件资源占用
从硬件资源占用的角度来看,三种协议各有特点。
UART每个接口需要2个GPIO(TX和RX),如果需要硬件流控,还需要额外的RTS和CTS引脚。
重要的是,每增加一个UART设备,就需要一个完整的UART外设模块。
对于GPIO资源紧张的MCU来说,这是个不小的负担。
IIC只需要2个GPIO(SCL和SDA),无论连接多少个设备,都只占用这两个引脚。
这是IIC最大的优势。
但需要注意的是,IIC总线需要上拉电阻(通常是4.7K或10K),这在设计PCB时需要考虑进去。
SPI需要3个共享的GPIO(SCLK、MOSI、MISO),加上每个从设备一个独立的片选信号。
如果你要连接5个SPI设备,就需要3+5=8个GPIO。
虽然比UART好一些,但还是比IIC占用更多的引脚资源。
3.2 传输速度对比
传输速度是选择通信协议时的重要考量因素。
UART的速度通常在几Kbps到几Mbps之间。
常用的波特率有9600、115200、460800、921600等。在实际应用中,115200bps是最常用的速度,因为它在可靠性和速度之间取得了很好的平衡。
更高的波特率虽然理论上可行,但容易受到线缆长度、电磁干扰等因素的影响。
IIC的标准速度有三种:标准模式(100Kbps)、快速模式(400Kbps)和高速模式(3.4Mbps)。
在实际应用中,大多数IIC设备工作在100Kbps或400Kbps。
虽然速度不如SPI,但对于传感器、EEPROM等低速设备来说已经足够了。
SPI的速度可以达到几十MHz甚至上百MHz。
在STM32中,SPI的时钟频率通常可以设置到APB总线频率的一半。
比如如果APB2总线是72MHz,SPI就可以工作在36MHz。
这个速度是UART和IIC无法企及的。
3.3 可靠性与抗干扰能力
在可靠性方面,三种协议各有千秋。
UART采用异步通信,没有时钟线,因此对时钟精度要求较高。
如果收发双方的时钟偏差太大,就会导致数据错误。
但UART通常有奇偶校验位和停止位,可以在一定程度上检测传输错误。
在工业现场,UART常常配合RS485或RS232电平转换芯片使用,以提高抗干扰能力和传输距离。
IIC采用开漏输出加上拉电阻的方式,这种设计天然支持多主机仲裁和时钟同步。
IIC协议本身包含了应答机制,每传输一个字节,接收方都要发送ACK或NACK信号,这提高了通信的可靠性。
但IIC对上拉电阻的阻值比较敏感,如果选择不当,可能会导致通信不稳定。
SPI采用推挽输出,信号边沿陡峭,抗干扰能力较强。由于有独立的时钟线,不存在时钟同步问题。
但SPI协议本身没有应答机制,如果需要确认数据是否正确接收,需要在应用层实现。
在高速应用中,SPI的信号完整性需要特别注意,可能需要考虑阻抗匹配、走线长度等因素。
4. 总结与选择建议
回到最初的问题:有了UART,为什么还需要IIC和SPI?答案很简单:因为它们各有所长,适用于不同的应用场景。
UART适合点对点、中低速、需要简单可靠通信的场景。
它的优势在于实现简单、使用方便、几乎所有MCU都支持。
如果你只需要连接一两个设备,不需要很高的速度,UART是最好的选择。
IIC适合连接多个低速外设的场景。
它的最大优势是节省GPIO资源,一条总线可以挂载多个设备。
如果你的项目需要连接多个传感器、EEPROM等低速设备,IIC是不二之选。
SPI适合需要高速数据传输的场景。
它的速度是三者中最快的,适合Flash存储器、显示屏、高速ADC/DAC等应用。
如果你的项目对速度有较高要求,SPI是最佳选择。
在实际项目中,这三种协议往往是配合使用的。
比如在我做过的一个智能家居项目中,STM32通过UART连接WiFi模块与云端通信,通过IIC连接多个环境传感器采集数据,通过SPI连接Flash存储历史数据。
这样的设计充分发挥了每种协议的优势,实现了最优的系统架构。
选择通信协议时,需要综合考虑设备数量、传输速度、GPIO资源、成本等多个因素。没有最好的协议,只有最合适的协议。
理解每种协议的特点和适用场景,才能在项目中做出正确的选择。
希望这篇文章能帮助大家更好地理解UART、IIC和SPI这三种常用的通信协议。
浙公网安备 33010602011771号