Back to all posts
Notes

Embedded Communications

Serial communication suits microcontrollers due to fewer pins. Asynchronous UART uses baud rate and start/stop bits, while synchronous I2C and SPI rely on a clock line. Distinction: UART uses baud rate, I2C address, SPI slave select.

Overview

这部分可以分成 3 大块:

Serial Communications 串行通信基础

重点概念:

对比 Serial 串行 Parallel 并行
传输方式 bit by bit,一个一个 bit 传 多个 bit 同时传
线路数量 少,通常 1 条或少数几条 多,需要多条数据线
适合场景 MCU 引脚有限、长距离传输 短距离、高吞吐
问题 速度相对低 长线容易干扰、占引脚

考试/理解重点:Serial communication 更适合嵌入式系统,因为 MCU 引脚有限,而且很多外设通信不需要很宽的数据总线。


Synchronous vs Asynchronous 同步/异步通信

对比 Synchronous 同步 Asynchronous 异步
时钟 发送方和接收方共享/同步时钟 不共享时钟
数据形式 连续数据流/block 一个 character 一个 character 传
额外 bit 通常不需要 start/stop bit 需要 start bit 和 stop bit
速度 通常更快 通常较慢
典型协议 I2C, SPI UART

记忆方式:

I2C/SPI = synchronous,因为它们有 clock line。

UART = asynchronous,因为没有 clock line,而是靠 baud rate + start/stop bits。


三种常见串行通信协议

UART

UART 是 Universal Asynchronous Receiver-Transmitter。严格来说,它不是像 I2C/SPI 那样的“协议”,而是 MCU 里的一个硬件模块,用来做异步串行通信。

特点:

  • 没有 clock line
  • 使用 TX 和 RX 两根主要数据线
  • 需要双方设置相同 baud rate
  • 每个数据包有 start bit 和 stop bit
  • 常用于 MCU 和 PC terminal 通信

本讲例子中,UART 初始化常见代码是:

UART1_Init(9600);
UART1_Write_Text("Start");

I2C

I2C 是 Inter-Integrated Circuit,是同步、multi-master、multi-slave 的串行通信协议。

特点:

  • 两根线:

    SCL:Serial Clock

    SDA:Serial Data

  • 支持多个 slave

  • 每个 slave 有地址
  • 常用于 EEPROM、ADC、DAC、传感器等

Lecture 里的 EEPROM 例子中,7-bit 地址是 0x50,写操作时变成:

0x50 << 1 = 0xA0

如果是读操作,则最低位 R/W bit 为 1,所以是:

0xA1

SPI

SPI 是 Serial Peripheral Interface,也是同步通信协议。

四根主要信号线:

信号 含义
SCLK Serial Clock
MOSI Master Output Slave Input
MISO Master Input Slave Output
SS Slave Select

SPI 通常比 I2C 快,但需要更多线。多个 slave 时,每个 slave 通常需要单独的 SS 线。


PIC18 上的通信模块

Lecture 3 主要讲了两个模块:

EUSART

用于 UART 通信。

相关寄存器:

功能 常见寄存器
发送 Tx TXREGx, TXSTAx, BAUDCONx, SPBRGx
接收 Rx RCREGx, RCSTAx, INTCON, PIEx, PIRx

Tx 关键配置:

TXSTA1.TXEN = 1;      // enable transmission
TXSTA1.SYNC = 0;      // asynchronous mode
TXSTA1.BRGH = 1;      // high baud rate
BAUDCON1.BRG16 = 0;   // 8-bit baud generator
SPBRG1 = 51;          // baud rate = 9600

Rx 关键配置:

RCSTA1.SPEN = 1;      // enable serial port
RCSTA1.CREN = 1;      // enable continuous receive
INTCON.GIE = 1;       // enable global interrupt
INTCON.PEIE = 1;      // enable peripheral interrupt
PIE1.RC1IE = 1;       // enable EUSART1 receive interrupt

MSSP

用于同步串行通信:

  • I2C mode
  • SPI mode

相关寄存器:

寄存器 作用
SSPxSTAT status
SSPxCON1 / SSPxCON3 control
SSPxBUF data buffer
SSPxADD address
SSPxSR shift register

Serial vs Parallel

Serial Communication 串行通信

串行通信的特点是:

数据按 bit 一个一个传输。

比如一个 byte:

10110010

串行通信会这样传:

1 → 0 → 1 → 1 → 0 → 0 → 1 → 0

也就是说,同一时间只传一个 bit

优点:

  • 用线少
  • 省 MCU 引脚
  • 适合长距离通信
  • 嵌入式系统里很常见

缺点:

  • 同一时刻只传一个 bit,所以理论上不如并行快

Parallel Communication 并行通信

并行通信的特点是:

多个 bit 同时传输。

比如同样传一个 byte:

10110010

并行通信可以用 8 根线同时传:

b7 b6 b5 b4 b3 b2 b1 b0

也就是说,同一时间传多个 bit

优点:

  • 短距离时速度快
  • 一次能传很多 bit

缺点:

  • 需要很多线
  • 占用很多 MCU 引脚
  • 长距离时容易出现 interference,也就是线路之间互相干扰

考试记忆点

最重要的一句话:

Serial uses fewer wires and is better for MCUs with limited pins. Parallel can be faster over short distance but uses more wires and may suffer interference over long cables.

中文理解:

串行通信省引脚、适合 MCU 和较长距离;并行通信短距离速度快,但占线多,长距离容易干扰。


Synchronous vs Asynchronous

串行通信又可以分成:

  • Synchronous communication 同步通信
  • Asynchronous communication 异步通信

Synchronous Communication 同步通信

同步通信的核心是:

Sender 和 receiver 的 clock 是同步的。

也就是说,发送方和接收方有统一的时钟节奏。

常见例子:

  • I2C
  • SPI

为什么它们是 synchronous?

因为它们都有 clock line。

I2C 里有:

SCL = clock line
SDA = data line

SPI 里有:

SCLK = clock line
MOSI / MISO = data lines

所以 I2C 和 SPI 都属于同步通信。


Asynchronous Communication 异步通信

异步通信的核心是:

Sender 和 receiver 没有共享 clock。

那没有 clock 怎么知道什么时候读数据?

靠三个东西:

  1. Baud rate
  2. Start bit
  3. Stop bit

UART 就是异步通信。

UART 发送一个字符时,大概结构是:

Start bit | Data bits | Stop bit

例如发送 8-bit data:

0 | 8 data bits | 1

其中:

  • start bit 通常是 0
  • stop bit 通常是 1
  • receiver 看到 start bit 后,就按照约定好的 baud rate 读取后面的 data bits

Synchronous vs Asynchronous 对比

对比点 Synchronous Asynchronous
是否共享 clock
是否需要 start/stop bit 通常不需要 需要
速度 通常更快 通常较慢
数据流 连续传输 一个 character 一个 character 传
典型协议 I2C, SPI UART

三个协议先建立印象

现在你先记住这个总表:

协议 类型 关键词
UART Asynchronous TX, RX, baud rate, start/stop bits
I2C Synchronous SDA, SCL, address, multi-slave
SPI Synchronous SCLK, MOSI, MISO, SS, fast

一句话总结:

UART 靠 baud rate,I2C 靠 address,SPI 靠 slave select。


UART

UART = Universal Asynchronous Receiver-Transmitter

它用于 asynchronous serial communication

注意一个细节:

UART 严格来说不是 I2C/SPI 那种 protocol,而是 MCU 里的一个硬件模块/电路。

它负责把 MCU 里的 parallel data 转换成 serial data 发出去,也负责把接收到的 serial data 转回 MCU 可处理的数据。


UART 用几根线?

最核心两根:

线 作用
TX transmit,发送数据
RX receive,接收数据

连接时要交叉:

MCU TX  →  PC/Terminal RX
MCU RX  ←  PC/Terminal TX

所以不是 TX 接 TX,而是 TX 接 RX


UART 为什么不需要 clock line?

因为它是 asynchronous。

发送方和接收方提前约定好:

Baud rate = 9600 bps

然后 receiver 看到 start bit 后,就按照这个速度去采样后面的 data bits。

例如一个常见 UART frame:

Start bit | 8 data bits | Stop bit

可以理解为:

0 | data | 1
  • start bit 通常是 low,也就是 0
  • stop bit 通常是 high,也就是 1
  • idle 状态通常也是 high

Baud rate 是什么?

Baud rate 是 UART 的传输速率。

例如:

UART1_Init(9600);

意思是初始化 UART,速率为 9600 bps

这里 bps 通常可以理解为:

每秒传输多少 bit。

如果两边 baud rate 不一致,就会读错数据。

比如:

MCU: 9600 bps
PC terminal: 115200 bps

这样通信大概率会乱码。


UART Transmit 发送配置

Tx 示例:

TXSTA1.TXEN = 1;      // enable transmission
TXSTA1.SYNC = 0;      // enable asynchronous mode
TXSTA1.BRGH = 1;      // select high baud rate
BAUDCON1.BRG16 = 0;   // select 8-bit baud rate
SPBRG1 = 51;          // set baud rate to 9600

逐句解释:

代码 含义
TXEN = 1 enable transmission,允许发送
SYNC = 0 asynchronous mode,异步模式
BRGH = 1 high baud rate
BRG16 = 0 使用 8-bit baud rate generator
SPBRG1 = 51 设置 baud rate 为 9600

UART Receive 接收配置

Rx 示例:

RCSTA1.SPEN = 1;      // enable serial port
RCSTA1.CREN = 1;      // enable continuous receive
INTCON.GIE = 1;       // enable global interrupt
INTCON.PEIE = 1;      // enable peripheral interrupt
PIE1.RC1IE = 1;       // enable EUSART1 receive interrupt

逐句解释:

代码 含义
SPEN = 1 enable serial port
CREN = 1 continuous receive,连续接收
GIE = 1 global interrupt enable
PEIE = 1 peripheral interrupt enable
RC1IE = 1 enable EUSART1 receive interrupt

重点是:

如果用 interrupt 接收 UART 数据,除了开 UART receive interrupt,还要开 global interrupt 和 peripheral interrupt。


8. 最简单的 UART echo 程序

echo 逻辑:

char uart_rd;

void main() {
    ANSELC = 0;              // Configure PORTC pins as digital
    UART1_Init(9600);        // Initialize UART module at 9600 bps
    Delay_ms(100);           // Wait for UART module to stabilize

    UART1_Write_Text("Start");
    UART1_Write(13);
    UART1_Write(10);

    while (1) {
        if (UART1_Data_Ready()) {
            uart_rd = UART1_Read();
            UART1_Write(uart_rd);
        }
    }
}

它做的事情是:

  1. 初始化 UART
  2. 发送 "Start"
  3. 一直等待输入
  4. 如果 PC terminal 发送了一个字符给 MCU
  5. MCU 读取这个字符
  6. MCU 再把它发回 PC terminal

这就是 UART echo


UART is asynchronous, so it does not use a clock line. It uses baud rate, start bit, and stop bit to synchronize data transfer.

TX and RX should be cross-connected.

For UART receiving with interrupt, SPEN, CREN, GIE, PEIE, and RC1IE should be enabled.

TXREG is used for transmit data, and RCREG is used for received data.


I2C

I2C = Inter-Integrated Circuit

它是一种:

synchronous, multi-master, multi-slave, serial communication protocol

拆开看:

关键词 含义
synchronous 有 clock line
multi-master 可以有多个 master
multi-slave 可以有多个 slave
serial 数据 bit by bit 传输
protocol 它是一套通信规则

在本课里,常见结构是:

MCU = Master
EEPROM = Slave

2. I2C 用几根线?

I2C 只用两根主要线:

线 全称 作用
SDA Serial Data 传输数据
SCL Serial Clock 传输时钟

所以 I2C 是 synchronous,因为它有 SCL clock line

记忆:

SDA = data
SCL = clock

I2C 为什么适合连接多个外设?

因为 I2C 使用 address 区分不同 slave。

比如一条 I2C bus 上可以接:

MCU
 ├── EEPROM, address 1
 ├── sensor, address 2
 └── ADC, address 3

所有设备共享 SDA 和 SCL,但每个 slave 有自己的 address。Master 先发送 address,被选中的 slave 才响应。

所以 I2C 的关键词是:

address-based communication


I2C 和 UART 的最大区别

对比 UART I2C
类型 asynchronous synchronous
clock line 没有 有 SCL
主要线 TX, RX SDA, SCL
是否有地址 通常没有 有 slave address
常见用途 MCU 和 PC terminal MCU 和 EEPROM / sensor

一句话:

UART 靠 baud rate,I2C 靠 clock + address。


EEPROM 地址:7-bit 和 8-bit

EEPROM 的 7-bit address 是:

0x50

但是 I2C 发送时,通常会把 7-bit address 左移 1 位,再加上 R/W bit。

公式:

8-bit address = 7-bit address << 1 + R/W bit

所以:

Write 写操作

R/W bit = 0

0x50 << 1 = 0xA0

所以写地址是:

0xA0

Read 读操作

R/W bit = 1

0xA0 + 1 = 0xA1

所以读地址是:

0xA1

注意 Lecture 代码里有时会出现 0xA20xA3,这是因为 EEPROM 的 chip enable address 位不同,但核心逻辑一样:

write address = even number
read address = write address + 1

I2C 写 EEPROM 的基本流程

典型写入流程:

I2C1_Start();
I2C1_Wr(0xA2);    // device address + Write
I2C1_Wr(2);       // EEPROM memory address
I2C1_Wr(0xAA);    // data to write
I2C1_Stop();

逐句解释:

代码 含义
I2C1_Start() 发起 I2C 通信
I2C1_Wr(0xA2) 选择 EEPROM,并指定 write
I2C1_Wr(2) 要写入 EEPROM 的第 2 个地址
I2C1_Wr(0xAA) 写入数据 0xAA
I2C1_Stop() 结束通信

逻辑是:

Start → Slave address + W → Memory address → Data → Stop

I2C 读 EEPROM 的基本流程

典型读取流程:

I2C1_Start();
I2C1_Wr(0xA2);             // device address + Write
I2C1_Wr(2);                // EEPROM memory address
I2C1_Repeated_Start();
I2C1_Wr(0xA3);             // device address + Read
PORTB = I2C1_Rd(0u);       // read data, no acknowledge
I2C1_Stop();

为什么读之前还要先 write?

因为要先告诉 EEPROM:

我要读 EEPROM 内部的哪个 memory address。

所以读取 EEPROM 的流程是:

Start
→ Slave address + W
→ Memory address
→ Repeated Start
→ Slave address + R
→ Read data
→ Stop

这里的 Repeated Start 很重要。它表示没有完全释放 bus,而是直接从“指定地址”切换到“读取模式”。


8. I2C1_Rd(0u) 里的 0u 是什么?

在 mikroC 里:

I2C1_Rd(0u)

表示:

Read the data with NO acknowledge.

如果读多个 byte,前面的 byte 通常发送 ACK,最后一个 byte 发送 NACK,表示:

我读完了,不需要继续发送了。

所以单 byte 读取时经常用:

I2C1_Rd(0u);

I2C is synchronous because it uses SCL as the clock line.

I2C uses two wires: SDA for data and SCL for clock.

I2C uses slave addresses, so multiple devices can share the same bus.

For EEPROM reading, the MCU first sends the memory address using write mode, then uses repeated start and read mode to read data.

7-bit address 0x50 becomes 0xA0 for write and 0xA1 for read.


SPI 是什么?

SPI = Serial Peripheral Interface

它是一种:

synchronous, master-slave, serial communication protocol

关键词:

关键词 含义
synchronous 有 clock line
master-slave 一个 master 控制一个或多个 slave
serial bit by bit 传输
protocol 一套通信规则

和 I2C 一样,SPI 也是同步通信,因为它有 clock。


SPI 的 4 根主要线

SPI 最重要的是这 4 根线:

信号 全称 作用
SCLK Serial Clock master 提供时钟
MOSI Master Output Slave Input master 发给 slave
MISO Master Input Slave Output slave 发给 master
SS Slave Select 选择某个 slave

记忆方法:

MOSI: Master → Slave
MISO: Slave → Master

也就是:

MOSI = master sends data out
MISO = master receives data in

SPI 为什么是 synchronous?

因为 SPI 有:

SCLK

SCLK 是 master 产生的 clock signal。

Slave 根据这个 clock 来发送/接收数据。

所以 SPI 不需要像 UART 那样依靠 start bit 和 stop bit 来判断字符边界。


SPI 如何选择 slave?

SPI 用 SS / Slave Select 线选择 slave。

比如一个 master 接 3 个 slave:

Master
 ├── SS1 → Slave 1
 ├── SS2 → Slave 2
 └── SS3 → Slave 3

当 master 要和 Slave 2 通信时,就使能 Slave 2 的 SS 线。

重点:

I2C 用 address 选择 slave;SPI 用 SS line 选择 slave。


SPI 和 I2C 对比

对比 I2C SPI
通信类型 synchronous synchronous
线数 2 根:SDA, SCL 通常 4 根:SCLK, MOSI, MISO, SS
slave 选择方式 address SS line
速度 较慢 通常更快
多 slave 扩展 容易,因为共用 SDA/SCL slave 越多,SS 线越多
常见用途 EEPROM、sensor 高速外设、display、ADC、flash

一句话:

I2C saves wires, SPI is usually faster.


SPI 和 UART 对比

对比 UART SPI
类型 asynchronous synchronous
clock line 没有 有 SCLK
主要线 TX, RX SCLK, MOSI, MISO, SS
是否需要 baud rate 需要 不像 UART 那样依赖 baud rate
是否需要 start/stop bit 需要 通常不需要
典型连接 MCU ↔ PC terminal MCU ↔ peripheral

三个协议总表

现在把 UART、I2C、SPI 放在一起记:

协议 类型 主要线 选择对象方式 关键词
UART asynchronous TX, RX 点对点 baud rate, start bit, stop bit
I2C synchronous SDA, SCL address multi-slave, EEPROM
SPI synchronous SCLK, MOSI, MISO, SS slave select fast, more wires

UART uses baud rate. I2C uses address. SPI uses slave select.


Share this post

Back to home

Comments