总线协议
I2C (又称I^2^C、IIC等)
I2C(Integrated Circuit)是两线式半双工串行总线
由数据线SDA和时钟SCL构成
一般可达400kbps以上
协议栈
底层硬件
SDA和SCL分别上拉到VCC,同时接入设备
主设备操纵SCL,可以接收/发送SDA
从设备可以发送/接收SDA
驱动
空闲(释放总线)
SDA=1 SCL=1
起止信号
起始信号:SCL=1 SDA下降沿
停止信号:SCL=1 SDA上升沿
应答信号ACK
发送器每发送一个字节,就在时钟9器件释放SDA,由接收器反馈一个应答信号
0为有效应答,ACK称为应答位,表示接收器已接收
1为非应答,NACK称为非应答位,表示接收器接收该字节没有成功
从设备要求:
在第9个时钟脉冲之前的低电平期间将SDA拉低,并确保在该时钟高电平期间位稳定的低电平
主设备要求:
在收到最后一个字节后发送一个NACK信号以通知被控发送器结束数据发送,并SDA=1(释放SDA),以便从设备发送停止信号P
数据有效性确认
SCL=1期间,SDA上的数据必须保持稳定,只有在SCL=0时,SDA才允许变化
即数据在SCL上升沿到来前就要准备好,并在下降沿到来前必须稳定
stm32实现
stm32自带I2C不稳定,通常使用GPIO模拟I2C
iic.h
1 |
|
iic.c
1 |
|
应用
示例程序:I2C驱动24C01(EEPROM)
24C02规格:总容量2K=256B*8
引脚定义如下:【1-A0 2-A1 3-A2】(地址线) 4-GND 【5-SDA 6-SCL】(I2C控制线) 7-WP(写保护) 8-VCC
在此A0=A1=A2=0
SCL==PB8 SDA==PB9
详细内容参考芯片手册即可
写时序
start->片选->选择地址->wait->传输数据->stop
读时序
start->片选->选择地址线->start->选择地址线->wait->读取数据->stop
程序读者自写
SPI
SPI(Serial Peripheral interface)串行外围设备接口,是一种四线、高速、全双工、同步通信总线。应用广泛
四条通信线:
MISO:(Master input & Slave output)主设备数据输入、从设备数据输出 即 从设备->主设备
MOSI:(Master output & Slave input)主设备数据输出、从设备数据输入 即 主设备->从设备
SCLK:时钟信号,由主设备产生
CS:片选信号,由主设备控制
协议栈
底层硬件
stm32f4自带SPI接口,相关内容参考芯片手册即可
基本原理
- 4线总线
- 主机从机各有一个串行移位寄存器(以下简称SPI寄存器),主机通过向它的SPI寄存器写入一个字节来发起一次传输
- SPI寄存器通过MOSI线将字节传输给从机,从机也将自己SPI寄存器中的内容通过MISO线返回主机,最终两个移位寄存器中的内容被交换
- 外设读写操作同步完成,如果只进行写操作,主机忽略收到数据即可;若只进行读操作,需要发送一个空字节来引发从机的传输
外设SPI的MISO、MOSI、SCLK可直接挂载到总线上,但CS线需要单独连接到stm32的GPIO模拟CS引脚,当对应GPIOxPinx<->CS拉低时表示选中该外设,才可进行通信
驱动
驱动由stm32f4 STL提供,只需调用库函数即可
应用
SPI应用过程
- 使能SPIx和GPIO时钟
- 初始化GPIO为复用功能
- 设置引脚复用为映射
- 初始化SPIx,设置SPIx工作模式
- 使能SPIx
- SPI传输数据
- 查看SPI传输状态
示例程序:SPI驱动W25Q128
W25Q128规格:总容量16M 分成256块64K 每个块分成16扇区,每个扇区4K
擦写周期多达10W次,具有20年的数据保存期限
支持电压2.7-3.6V
最小擦除单位为一个扇区,也就是每次必须擦除4K个字节
需要给W25Q128开辟一个至少4K的缓存区
支持标准SPI协议,还支持双输出/四输出的SPI,最大SPI时钟可以到80MHz(双输出时相当于160MHz,四输出时相当于320MHz)
引脚定义如下:
1 片选信号CS 2 MISO线SO 3 使能引脚WP# 4 接地GND 5 MOSI线SI 6 SCK线CLK 7 保持位HOLD 8 接电源VCC
代码实现
spi.c
1 |
|
spi.h
1 |
|
W25Q128.c
1 | u16 W25QXX_TYPE;//FLASH型号 |
W25Q128.h
1 | //前部分略 |
CAN
协议栈
CAN(Controller Area Network)是ISO国际标准化的串行通信协议,由德国电气商博世公司在1986年率先提出。此后CAN通过ISO11898及ISO11519进行了标准化,可靠性高
具有两个标准:
ISO11898高速通信标准(速率125Kbps~1Mbps)
ISO11519-2低速通信标准(速率125Kbps以下)
特点:
- 多主控制
总线空闲时所有单元都可发送消息,两个以上单元同时发送消息时,根据标识符(ID,不是地址)决定优先级。对各个消息ID的各个位进行逐个仲裁比较,仲裁获胜单元可继续发送消息,失利的单元需立刻停止发送而进行接收工作
- 系统柔软性
连接总线的单元没有类似地址的信息,可以很方便地添加新单元,不需要改动旧设备
- 速度快,距离远
速率最高1Mbps(距离<40m),最远可达10km(速率<5kbps)
- 具有错误检测、错误通知和错误恢复功能
所有单元都能检测错误,检测到错误会立即通知所有其他单元,正在发送消息的单元一旦检测到出错会强制结束发送,并不断反复重新发送此消息直到发送成功
- 故障封闭功能
可以判断出错误的类型是总线上暂时的数据错误还是持续的数据错误。当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去
- 连接节点多
可同时连接多个单元,理论上没有总数限制,但实际上可连接单元越多,通信速率越慢;通信速率越快,可连接单元数越少
底层硬件
使用ISO11898标准
CAN控制器根据CAN_L和CAN_H上的电位差来判断总线电平
发送方通过使总线电平发生变化将消息发送给接收方
显性电平对应逻辑0:CAN_H与CAN_L之差在2V左右
隐性电平对应逻辑1:CAN_H与CAN_L之差为0V
总线电平必为二者之一,显性电平具有优先权,只要一个单元输出显性电平,总线上即为显性电平;只有所有单元都输出隐性电平,总线上才为隐性电平
单元在总线上呈并联,总线起止端各有一个120Ω的终端电阻(作用:阻抗匹配,减少回波反射)
stm32f407自带2个基本可扩展CAN外设(bxCAN),支持CAN协议2.0A和2.0B主动模式,波特率最高1Mbps,通过GPIO复用2个引脚输出,但需要接入TJA1050电平转换ic才能正常接入CAN总线
每个CAN具有3个3级深度(可同时存储三条有效报文)发送邮箱,互相独立;2个接收FIFO,最多28个可变筛选器组
两个CAN分别拥有独立的发送邮箱和接收FIFO,但他们会共用28个筛选器
CAN标识符筛选器
CAN的标识符不表示目标地址而是表示发送优先级,接收节点根据标识符的值决定是否接受对应信息
STM32 CAN控制器每个筛选器组由2个32位寄存器组成,根据位宽不同,每个筛选器组可提供
- 1个32位筛选器,包括STDID[10:0] EXTID[17:0] IDE RTR
- 2个16位筛选器,包括STDID[10:0] IDE RTR EXTID[17:15]
应用程序不用的筛选器组应当保持禁用
筛选器编号从0开始
筛选器可配置为屏蔽位模式和标识符列表模式:
屏蔽位模式下,标识符寄存器指定报文标识符哪一位“必须匹配”;屏蔽寄存器指定报文标识符哪一位“不用关心”
屏蔽寄存器置0的标识寄存器对应位会被忽略
类似“掩码”操作,一次筛选出一组标识符
标识符列表模式下,屏蔽寄存器也被当做标识符寄存器用,接受报文标识符的每一位都必须和筛选器标识符相同
一次过滤出一个标识符号
举例:1个32位筛选器-标识符屏蔽模式,设置CAN_F0R1=0xFFFF0000,CAN_F0R2=0xFF00FF00,则期望收到的id形式为0xFFFF0000,同时必须关心id形式为0xFF00FF00,即标记为F的四个位必须和F0R1中的对应位一模一样,另外的六个位可以一样也可以不一样,即收到的映像必须是0xFF??00??才算是正确的,并不关心标?的位是多少
驱动
CAN通信
数据帧:发送单元向接收单元传送数据
遥控帧:接收单元向具有相同ID的发送单元请求数据
错误帧:检测出错时向其他单元通知错误
过载帧:接收单元通知其尚未做好接收准备(标记忙碌状态)
间隔帧:将数据帧和遥控帧与前面的帧分隔开的帧
数据帧和遥控帧有11位ID的标准格式和29位ID的拓展格式
数据帧
由7个段组成,下面是标准格式的实现
- 帧起始:1位显性电平
- 仲裁段:11位ID+1位RTR(显性电平)
表示数据优先级。ID高位在前,低位在后,禁止高7位都是隐性(不能ID=1111111XXXX)
RTR:远程请求位——0表示数据帧,1表示远程帧
SRR:替代远程请求位——设置为1
IDE:标识符选择位——0表示标准标识符,1表示扩展标识符
- 控制段:1位IDE(显性电平)+1位r0(显性电平)+4位DLC
r0、r1:保留位——必须以显性电平发送,但接收可以是隐性电平
DLC:数据长度码——0-8表示发送/接收的数据长度(字节)
- 数据段:0-64位(0-8个字节)的数据
从最高位开始输出
- CRC段:15位+1位RCR界定符(隐性电平)
用于检查帧传输错误
CRC的值计算范围包括:帧起始、仲裁段、控制段、数据段
接收方和发送方以同样的算法计算CRC并进行比较,不一致时会通报错误
- ACK段:1位ACK槽(发送位为隐性电平,接收位随接收成功与否变化)+1位ACK界定符(隐性电平)
用来确认是否正常接收
发送单元ACK段发送2个隐性电平
接收单元ACK段:接收到正确消息的单元在ACK槽发送显性位,称之为发送ACK/返回ACK
发送ACK的时既不处于总线关闭态也不处于休眠态的所有接受单元中,接收到正常消息(不含填充错误、格式错误、CRC错误)的单元,发送单元不会发送ACK
- 帧结束:7位EOF(7位隐性电平)
总线仲裁
- 总线空闲时最先发送的单元优先,一旦发送无法被抢占
- 多个单元同时发送,连续输出显性电平多的单元优先
- 先比较ID,若ID相同,就比较RTR、SRR等位
位时序(波特率)
位速率:发送单元在非同步情况下发送的每秒钟位数称为位速率
一个位一般可以分成四段
这些段又由最小时间单位Time Quantum(Tq)组成
1位分4段,1段分多个Tq,即位时序
$$位时间=\frac{1}{波特率}$$
可以任意设定位时序,多个单元可同时采样,也可任意设定采样点
- 同步段 SS
多个单元实现时序同步,1Tq
电平边沿跳变最好出现在此段中
- 传播时间段 PTS
吸收网络物理延迟
该段时间=2*(发送单元输出延迟+总线信号传播延迟+接受单元输入延迟)=1~8Tq
- 相位缓冲段1 PBS1
1~8Tq
- 相位缓冲段2 PBS2
2~8Tq
两段负责补偿未被包含在SS段的信号边沿;通过对相位缓冲段加减SJW吸收细微时钟误差,但会导致通信速度下降
- 再同步补偿宽度 SJW
1~4Tq
补偿时钟频率偏差/传输延迟等导致误差的最大值
STM32F407的CAN控制器设置
可分为三种模式
工作模式,通过CAN_MCR寄存器控制
INRQ=1,SLEEP=0 初始化工作模式
INRQ=0,SLEEP=0 正常工作
SLEEP=1 开启睡眠,降低功耗
测试模式,通过CAN_BTR控制
LBKM=0,SLIM=1 静默,CANtx恒为1(只接收不发送),可以监控总线数据
LBKM=1,SLIM=0 环回,CANrx被阻塞(只发送不接收)
LBKM=1,SLIM=1 环回静默,CANrx、CANtx都被阻塞(不接收不发送)
调试模式
CAN发收流程
CAN发送流程
- 选择空置邮箱(TME=1)
- 设置标识符(ID)、数据长度、待发送的数据内容
- 设置CAN_TIxR的TXRQ位为1,请求发送
- 邮箱挂号,等待成为最高优先级才能够发送
- 预定发送,等待总线空闲
- 发送数据
- 邮箱空置
可随时置ABRQ为1退出发送进入等待,如果发送失败则可以重新等待发送或重启发动流程
CAN接收流程
- FIFO为空
- 收到有效报文(被正确接收(直到EOF都未出现错误)且通过标识符过滤的报文)
- 挂号1,存入FIFO的一个邮箱(此步骤由硬件完成)
- 收到有效报文
- 挂号2
- 收到有效报文
- 挂号3
- 收到有效报文
- 溢出,可设置是否锁定,锁定后新数据将被丢弃,不锁定则新数据会替代老数据
通过读取CAN_RFxR的FMP寄存器获取FIFO中当前存储的数据条数,只要不为0则可以读取报文
STM32 CAN位时序
$波特率=\frac{1}{正常的位时间}$
$正常的位时间=1*t_q+t_{BS1}+t_{BS2}$
$t_{BS1}=t_q*(TS1[3:0]+1)$
$t_{BS2}=t_q*(TS2[2:0]+1)$
$t_q=(BRP[9:0]+1)*t_{PCLK}$
$t_q$代表1个时间单元,$t_{PCLK}$表示APB时钟的时钟周期
对于stm32f407,设置TS1=6,TS2=5,BRP=5
$波特率=\frac{42000}{[(7+6+1)*6]}=500Kbps$
应用
初始化流程
- 配置引脚复用
- 使能CAN控制器时钟
- 设置CAN工作模式和波特率
- 设置过滤器
- CAN自动开始工作
can.c
1 |
|
can.h
1 |
|
main.c
1 |
|