以下内容都是博主课上学习,以及在看了CSDN上相关文章加强理解后的笔记内容。转载请先联系博主!
10 Serial Communication
一、将Word转换为连续的比特
1. Serial vs. Parallel
系统中表示N个bit的两种方法
- Serial:一个bit为一个周期,N个bit需要N个周期
- Parallel:N个bit一个周期
![image-20220526233452447](https://i-blog.csdnimg.cn/blog_migrate/a843912ce18da97c5d6eff447e8af759.png)
2. 串口通信
Serial Communication(缩写为:Serial Comm)
主要优点:减少连接两个系统的数据线的数量
- 代价:有时延,效率低。
2.1 串口通信的3种模式
-
Simplex:单向的,固定一个发一个收
-
Half Duplex:Time-shared,时差双向发送(不可以同时双向收发)
-
Full Duplex:可以同时双向收发
![image-20220526233855525](https://i-blog.csdnimg.cn/blog_migrate/6e5edbae7fbc3d7b464039f6458156bb.png)
2.2 同步
传输的时一个二进制数据流,即一个“0”或“1”的序列
- 发送端:encode the stream
- 例如,
'A' = 0x41=b"01000001"
- 例如,
- 接收端:decode the stream
- 为了成功通信,系统在传输过程中必须保持同步。
两种传输方法:
- Synchronous:系统使用统一的时钟
- Asynchronous:系统使用分开的时钟
二、比特的发送和接收
1. 同步发送
依靠信号中的时钟分量来保持时钟一致
![image-20220526234600512](https://i-blog.csdnimg.cn/blog_migrate/06517ddaf5eb5cfea1a1749079d8699f.png)
- 使用移位寄存器和一个时钟信号完成串并转换
**同步:**与数据信号一起的称为explicit clock(显式时钟信号)
2. 异步发送
使用不同的时钟
- 正确解码的前提:接收机必须与发射机同步采样。
在实际中,时钟会因为error而出现错误
- 所以,我们必须定期重新同步以确保时钟保持同步。
为了解决同步问题,我们使用Asynchronous Communication Protocol
2.1 异步串口通信协议
发送编码
数据在包含的帧中编码(每个数据的最小单位是frame)
- Start bit:接收器同步的起始位(感应到这个就开始同步)
- Data bits:传输的word的data
- Stop bit:表示该帧已传输完
Frame与Frame之间保持高电位(IDLE)【空闲状态保持高电平】。
![image-20220527002122960](https://i-blog.csdnimg.cn/blog_migrate/936181082e1b239a12159da6420db70a.png)
接收解码
接收机检测Start bit前沿,然后将其作为采样数据线的定时参考,在时间 T b i t ∗ ( N + 1.5 ) T_{bit}*(N+1.5) Tbit∗(N+1.5)内提取N个数据比特
- 通过采样来提取
- 只有当line在帧结束时处于预期状态(stop = HIGH)时,数据才被正确读取【读取完一个完整的Frame后数据才能被完整的解码】
![image-20220527002410269](https://i-blog.csdnimg.cn/blog_migrate/a1bf2b9d19563f72d44416ab39fe4dbd.png)
误差忍受度
对于8位数据,我们可以容忍大约5%的时钟速度差异。
![image-20220527002504352](https://i-blog.csdnimg.cn/blog_migrate/bbf5b4b0da3f7ec6f18cb7d1cadba25d.png)
3. 详解串口通信
3.1 Data Frame格式
Start bit:1个bit
Data:LSB最先,总长度为7-9个bits
Parity Bit:(可选)用于检测数据中是否有error
Stop bit:1个bit或者2个bits
3.2 串口通信速率
所有设备必须使用相同的通信参数
- 例如通信速度(300波特、600、1200、2400、9600、14400、19200等)
3.3 复杂网络
复杂的网络协议在每个数据帧中包含更多的信息
![image-20220527002829721](https://i-blog.csdnimg.cn/blog_migrate/a698e5fc94a4da7ae71bfb74d42938ee.png)
4. Error检测
- 可以发送附加信息来验证数据是否正确接收
- 需要指定Parity Code来进行奇偶校验
- Parity Bit是用来检测frame中data部分
1
的个数,Parity Bit有两种,表示偶的Parity Bit(even parity bit)以及表示奇的Parity Bit(odd partiy bit),低电平表示为真- 当data部分有6个
1
时,当parity bit是odd parity bit时,会被设置为1
;当parity bit是even parity bit时,会被设置为0
- 当data部分有5个
1
时,当parity bit是odd parity bit时,会被设置为0
;当parity bit是even parity bit时,会被设置为1
- 当data部分有6个
- 单一parity bit会检测1,3,5,7,9 bit是否损坏了,但是不会检验偶数的bit
- 更强的错误检测码(如Cyclic Redundancy Check - CRC)存在并使用多个位(如8,16),可以检测更多的错误。
Parity Bit 例子
![image-20220527003828389](https://i-blog.csdnimg.cn/blog_migrate/caffb941cd0960adf9707fbb833d7485.png)
5. 串口通信优缺点
异步串口通信:
-
优点:
- 简单和便宜
-
缺点:
- 高开销,因为启动和停止位占用了至少2/10(或更多)的frame的位置。【意味大带宽】
同步串口通信:
- 更有效率,但更复杂
在同步通信中如何获取时钟?
- 将时钟和数据以不同的线传输
- 将时钟信号编码至数据流中,例如曼彻斯特编码
三、异步传输协议 — RS232C
1. RS232C异步协议
是常用的异步传输协议,PC的串口用的就是 RS232C协议
规定了==反极性电压==
- -3v到-15v:表示逻辑
1
- 3v到15v:表示逻辑
0
1.1 RS232传输系统例子
2. RS232C Flow Control
- 连续发送过多字节可能会使接收端输入缓冲区溢出。
- **request-to-send(RTS)和clear-to-send(CTS)**允许硬件控制数据流。
常有的设计问题:
- 我们可能想要连接两个数据终端设备
- 把电脑和打印机连接起来
3. 最小Serial Link电路
四、解析消息 — 从接受到的比特流中解码
1. 消息解码
两种类型的消息:
- Actual binary data sent【就是比特流】
- 首先识别消息类型
- 其次,基于此消息类型,将二进制数据从消息字段复制到变量中
- 可能需要使用指针和强制转换来获得正确和安全的格式
- 表示所发送数据的ASCII text characters【将比特流用ASCII转换为Char】
- 首先识别消息类型
- 其次,基于此消息类型,将数据从ASCII消息格式转换(解析)为二进制格式
- 第三,将二进制数据复制到变量中
第一步都是要识别消息类型
Binary Serial Data例子:TSIP
用不同index来划分不同消息,划分一定长度得bit来表达。
ASCII Serial Data例子:NMEA-0183
头几个字符分别为:
- 开始符
- ID
- 三个字母来描述消息内容的助记符。MSG
然后中间是消息
后几个字符:
*
是用来分开消息何checksum的标识CS
是checksum\r\n
:是结束
五、USART - 特征
同步/异步 串口通信
1. STM32F401 - USART
USART: Universal Synchronous Asynchronous Receiver Transmitter
- 可以同步也可以异步
具备以下特点:
- 全双工,异步通信
- 用NRZ来传号和传空
- 可配置的oversampling方法,通过16或8在速度和时钟公差之间提供灵活性
- 有不同级别baud rate的产生系统
- Data word的长度可以设置为8bits或者9bits
- 可以设置stop bits的长度,1或2 bit
- Parity Control
- 四个Error detection flag
- 10个interrupt sources with flag
- 有同步模式
- HW 流控制模式
2. USART区块图
3. USART 模式
- Normal mode:用到TX pin以及RX pin
- RX:接收serial data的数据接入扣
- TX:数据发送口
- 当Transmitter disable的时候,TX口的电位根据Configuration给
- 当Transmitter enable的,但没有任何东西要发的时候,TX保持高电位(开了但没发东西就默认为高电位)
- Synchronous mode:除了TX和RX还用到CLK
- Hardware flow control mode:用到CTS和RTS
- CTS:clear to send,有效电平为低
- RTS:用来指示USART以及准备好接收数据了,有效电平为低
4. 如何管理USART的TX/RX
- 如何知道数据何时等待接收或准备传输?
- 如何在RX/TX和其他计算和操作之间共享微处理器时间?
- STM32F401 USART的设计允许灵活的实现和连接。
5. Software Structure
通信和程序是异步的 - 不知道程序会执行什么代码【不知道什么时候收到消息】
- 不知道下一个item什么时候来
- 不知道当前的item什么时候完成传输
- 不知道有没有error发生
需要在程序和串行通信接口之间以某种方式进行同步。两个选择:
- Polling:
- 一直监听知道data可以用
- 简单但是效率很低
- Interrupt:
- CPU当数据好了就发interrupt
- 高效,但是复杂
6. 串口通信和Interrupt
想在程序中提供多线程控制【一个主线程,三个ISR】
- Main Program
- Transimit ISR:当Serial Interface准备好发送下一个char时触发
- Receive ISR:当Serial interface接收到了一个char时触发
- Error ISR:当有Error的时候触发
各个线程之间需要一个Buffer来存数据:用有首指针和尾指针的循环队列来存
6.1 实现队列的代码
队尾写新,队头读取
-
队列的长度是在初始化的时候就定死的
-
TX和RX都有一个队列【TX和RX都有buffer】
- TX ISR:
unload tx_q
- RX ISR:
loads rx_q
- TX ISR:
-
其他的线程要用的时候就分别用
unload tx_q
和loads rx_q
-
用
%
运算符来确保这是一个循环队列- 如果队列大小不是2的幂,则使用
%
(模,余数)操作符 - 如果队列大小是2的幂,则使用
&
(bitwise and)
- 如果队列大小不是2的幂,则使用
-
判断队列空:
tail == head
-
判断队列满:
(tail + 1) % size == head
队列初始化
判断是否为满
入队& 出队
六、USART - Control Regs
1. USART 字符描述
- Word长度(基于USAR_CR1中的M)【M是parity。如果M作为Partiy的话那word长就是8bits;如果不做parity,那就是9bits】
- 在Start Bit期间,TX引脚处于低电位;在Stop bit期间,它处于高电位。
- Idle character: 一整个frame都是
1
- Brak character:整个frame周期内都接收到
0
2. USART Transmitter
- 当【USART_AR1中的】TE设定后,在transmit shift register中的数据会输出到TX上(LSB先出)
- USART_DR(TDR)缓存内部Bus和transmit shift register中间部分的数据。
![image-20220531205138485](https://i-blog.csdnimg.cn/blog_migrate/06d6367d7abae8388702984b0e338b49.png)
-
写入USART_DR(TDR)时将TXE(Transmit buffer empty)标清除。
-
TXE当以下情况时会被HW设置:
- 当数据从TDR转移到shift regs时 - 数据开始发送
- TDR为空
- 下一个数据可以被写入USART_DR register时
3. USART Receiver
意义:
- 用上图中间采样的三位来根据下表进行判断,用于噪声误差检测和字符接收
- Frame错误检测:在预期的接收时间没有识别到停止位 (FE【frame error】位在USART_SR中设置)
- FE位通过USART_SR寄存器读操作和USART_DR寄存器读操作复位。
![image-20220531210240404](https://i-blog.csdnimg.cn/blog_migrate/192f4ec7c19be2ecbc966201da5b0a00.png)
4. Baud Rate的生成
Rx和TX的波特率都设置为与USART_BRR中USARTDIV的Mantissa和Fraction value相同的值。
-
OVER8在使用16 oversampling的时候设为0;当使用8 oversampling的时候设为1
-
USARTDIV
是一个在USART_BRR寄存器上编码的unsigned fix number。 -
USART_CR1
中的OVER8定义过采样率。
得到4位的Fraction后,用Fraction的十进制数除以16得到fraction所表示的小数
左边例子:
- 0x1BC转为二进制为11011 1100,取前五位为Mantissa,后四位为Fraction【都要用四位为Fraction,是固定的】
5. Parity Check
Parity Control:用于生成传输用的parity code和接收时用来检验的parity code【传输和接收用的其实是一样的parity】
- 通过设置在USART_CR1中的PCE bit(Parity Check Enable)来Enable【来控制M是否用来做Parity Code,同时也影响了word length】:
Even Parity:用来校验Frame里面全部bit的1
是否为偶数。data = 00110101时候,even parity为0
Odd Parity:用来校验Frame里面全部bit的1
是否为偶数。data = 00110101时候,odd parity为1