【嵌入式】串行通信协议总结:UART,SPI,IIC,CAN
前言
随着半导体技术的发展,数据传输速度逐渐增加,随之而来的是串行通信基本取代了并行通信,因此,了解常用的串行通信协议对于嵌入式开发来说非常有必要,这里总结一些用过的串行通信协议,重点在于其数据传输时序图。
由于看到很多CSDN大佬写的文章非常详细也非常全面,故而本文主要是总结链接,以及总结个人实践经验。
参考链接
UART
所谓UART,即Universal Asynchronous Receiver / Transmitter,通用异步串行通讯,也就是我们日常说的串口。这种串口大部分的单片机都会有硬件支持,即可以很方便地传输数据。
但是,如果外设数量较多,而且都是使用串口通讯的话,但单片机上内置的串口外设数量不够,怎么办呢?这个时候就需要用到模拟串口,也就是我们常说的软串口,所谓“软”,即没有硬件支持,而是通过一般的IO引脚模拟传输数据时的高低电平变化。然后按照设定的波特率来进行延时。
具体参考参考这个链接,真的是讲得非常非常详细!
附:UART接口与COM口的区别
SPI
参考资料
SPI通信协议(SPI总线)学习 - 博客园
SPI总线协议概述 - CSDN
概述
简单来说,SPI传输协议就是通过主设备发生时钟,然后交换数据,不同的模式区别只在于数据是什么时候采样,什么时候锁存传输的,但是似乎目前大部分设备这一点都是设定好的,不能修改。
IIC
参考链接
总结
上面那几篇文章确实写得非常好,而且也非常详细,总结来说:
-
IIC协议为两线,属于半双工,即能发送接收数据,但不能同时进行。
-
IIC中的信号有三种:起始信号、停止信号、应答信号,分别对应不同的两线电平状态。
-
IIC协议传输数据时有起始位,停止位,其数据传输结构为:1位起始位、7位的器件地址(即向谁写入/读取数据)、1位读/写标识位、之后就是数据位(可以有多个字节)、1位停止位在最后,且每传输一个字节都有应答位。


其中,深色代表主机发送的数据,浅色代表从机向主机发送的数据。 -
高字节先写入
-
数据的有效性:数据在时钟线SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。且要求数据传输过程中有一定的延时,如下图所示。

-
有时候主机读入数据时,如果从机没有读入应答位的需求,则可以不加应答位。
C51实现
#include <reg52.h>
sbit SCL=P2^1;
sbit SDA=P2^0;
/*******************************************************************************
* 函数名 : Delay10us()
* 函数功能 : 延时10us
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
/*******************************************************************************
* 函数名 : I2cStart()
* 函数功能 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
* 输入 : 无
* 输出 : 无
* 备注 : 起始之后SDA和SCL都为0
*******************************************************************************/
void I2cStart()
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();//建立时间是SDA保持时间>4.7us
SDA=0;
Delay10us();//保持时间是>4us
SCL=0;
Delay10us();
}
/*******************************************************************************
* 函数名 : I2cStop()
* 函数功能 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
* 输入 : 无
* 输出 : 无
* 备注 : 结束之后保持SDA和SCL都为1;表示总线空闲
*******************************************************************************/
void I2cStop()
{
SDA=0;
Delay10us();
SCL=1;
Delay10us();//建立时间大于4.7us
SDA=1;
Delay10us();
}
/*******************************************************************************
* 函数名 : I2cSendByte(unsigned char dat)
* 函数功能 : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定
* 输入 : num
* 输出 : 0或1。发送成功返回1,发送失败返回0
* 备注 : 发送完一个字节SCL=0,SDA=1
*******************************************************************************/
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat=dat<<1;
Delay10us();
SCL=1;
Delay10us();//建立时间>4.7us
SCL=0;
Delay10us();//时间大于4us
}
SDA=1;
Delay10us();
SCL=1;
while(SDA)//等待应答,也就是等待从设备把SDA拉低
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
Delay10us();
return 0;
}
}
SCL=0;
Delay10us();
return 1;
}
/*******************************************************************************
* 函数名 : I2cReadByte()
* 函数功能 : 使用I2c读取一个字节
* 输入 : 无
* 输出 : dat
* 备注 : 接收完一个字节SCL=0,SDA=1.
*******************************************************************************/
unsigned char I2cReadByte() //不产生应答位
{
unsigned char a=0,dat=0;
SDA=1; //起始和发送一个字节之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
return dat;
}
CAN
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)