Chenyj Space
返回博客
·44 分钟

嵌入式通信协议详解:I2C、SPI、UART 与 CAN

嵌入式I2CSPIUARTCAN通信协议嵌入式

通信协议概述

嵌入式系统中,MCU 需要与各种外设进行通信。不同的通信协议适用于不同的应用场景。

1. 协议对比

协议线数速率距离特点典型应用
UART2115200bps15m异步、简单调试、GPS
I2C2400Kbps1m多设备、地址传感器、EEPROM
SPI410Mbps1m高速、全双工Flash、LCD
CAN21Mbps1km多主、可靠汽车、工业

UART 串口通信

1. UART 原理

code
UART 数据帧格式:
┌─────┬─────────────────────┬─────┬─────┐
│起始位│      数据位 (8位)    │校验位│停止位│
│  0  │ D0 D1 D2 D3 D4 D5 D6 D7 │  X  │  1  │
└─────┴─────────────────────┴─────┴─────┘

波特率:每秒传输的位数
常用波特率:9600, 19200, 38400, 115200

2. UART 配置

c
// UART 初始化
void UART_Init(uint32_t baudrate) {
    // 1. 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置 GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // TX - PA9
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // RX - PA10
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 3. 配置 UART
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = baudrate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStruct);
    
    // 4. 使能 UART
    USART_Cmd(USART1, ENABLE);
}

3. UART 数据收发

c
// 发送单个字节
void UART_SendByte(uint8_t data) {
    USART_SendData(USART1, data);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

// 接收单个字节
uint8_t UART_ReceiveByte(void) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    return USART_ReceiveData(USART1);
}

// 发送字符串
void UART_SendString(const char *str) {
    while(*str) {
        UART_SendByte(*str++);
    }
}

// printf 重定向
int fputc(int ch, FILE *f) {
    UART_SendByte(ch);
    return ch;
}

4. UART 中断接收

c
// 中断接收配置
void UART_Interrupt_Init(void) {
    NVIC_InitTypeDef NVIC_InitStruct;
    
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}

// 接收缓冲区
#define RX_BUFFER_SIZE 256
uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t rx_count = 0;

// 中断服务函数
void USART1_IRQHandler(void) {
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t data = USART_ReceiveData(USART1);
        
        if(rx_count < RX_BUFFER_SIZE) {
            rx_buffer[rx_count++] = data;
        }
        
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

I2C 通信

1. I2C 原理

code
I2C 总线结构:
        VCC
         │
        ┌┴┐
        │ │ 4.7KΩ 上拉电阻
        └┬┘
         │
┌────────┴────────┐
│    SDA (数据线)  │
├─────────────────┤
│    SCL (时钟线)  │
└─────────────────┘
         │
    ┌────┴────┐
    │  主设备  │
    └────┬────┘
         │
    ┌────┴────┐
    │  从设备  │
    └─────────┘

I2C 时序:
┌───┐   ┌───┐   ┌───┐   ┌───┐
│ S │   │ A │   │ D │   │ P │
└─┬─┘   └─┬─┘   └─┬─┘   └─┬─┘
  │       │       │       │
  ↓       ↓       ↓       ↓
开始    地址    数据    停止

2. I2C 配置

c
// I2C 初始化
void I2C_Init(void) {
    // 1. 使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    // 2. 配置 GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // SCL - PB6
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // SDA - PB7
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // 3. 配置 I2C
    I2C_InitTypeDef I2C_InitStruct;
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStruct.I2C_ClockSpeed = 400000;  // 400KHz
    I2C_Init(I2C1, &I2C_InitStruct);
    
    // 4. 使能 I2C
    I2C_Cmd(I2C1, ENABLE);
}

3. I2C 读写操作

c
// I2C 写单个字节
void I2C_WriteByte(uint8_t addr, uint8_t reg, uint8_t data) {
    // 等待总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    
    // 发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    
    // 发送设备地址
    I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    
    // 发送寄存器地址
    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    
    // 发送数据
    I2C_SendData(I2C1, data);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    
    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
}

// I2C 读单个字节
uint8_t I2C_ReadByte(uint8_t addr, uint8_t reg) {
    uint8_t data;
    
    // 等待总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    
    // 发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    
    // 发送设备地址(写)
    I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    
    // 发送寄存器地址
    I2C_SendData(I2C1, reg);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    
    // 重新发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    
    // 发送设备地址(读)
    I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    
    // 禁用应答
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    
    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
    
    // 接收数据
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    data = I2C_ReceiveData(I2C1);
    
    // 重新使能应答
    I2C_AcknowledgeConfig(I2C1, ENABLE);
    
    return data;
}

4. I2C 设备驱动示例

c
// MPU6050 陀螺仪驱动
#define MPU6050_ADDR  0xD0

void MPU6050_Init(void) {
    // 唤醒 MPU6050
    I2C_WriteByte(MPU6050_ADDR, 0x6B, 0x00);
    
    // 配置采样率
    I2C_WriteByte(MPU6050_ADDR, 0x19, 0x07);  // 1KHz
    
    // 配置低通滤波
    I2C_WriteByte(MPU6050_ADDR, 0x1A, 0x06);
    
    // 配置陀螺仪量程
    I2C_WriteByte(MPU6050_ADDR, 0x1B, 0x18);  // ±2000°/s
    
    // 配置加速度计量程
    I2C_WriteByte(MPU6050_ADDR, 0x1C, 0x01);  // ±4g
}

// 读取加速度数据
void MPU6050_ReadAccel(int16_t *ax, int16_t *ay, int16_t *az) {
    uint8_t data[6];
    
    // 读取 6 个字节
    for(int i = 0; i < 6; i++) {
        data[i] = I2C_ReadByte(MPU6050_ADDR, 0x3B + i);
    }
    
    // 组合数据
    *ax = (data[0] << 8) | data[1];
    *ay = (data[2] << 8) | data[3];
    *az = (data[4] << 8) | data[5];
}

SPI 通信

1. SPI 原理

code
SPI 总线结构:
┌─────────┐      ┌─────────┐
│  主设备  │      │  从设备  │
├─────────┤      ├─────────┤
│  MOSI ──┼──────┼── DI    │
│  MISO ──┼──────┼── DO    │
│  SCK  ──┼──────┼── CLK   │
│  CS   ──┼──────┼── CS    │
└─────────┘      └─────────┘

SPI 时钟模式:
CPOL = 0: 空闲时 SCL 为低
CPOL = 1: 空闲时 SCL 为高
CPHA = 0: 第一个边沿采样
CPHA = 1: 第二个边沿采样

2. SPI 配置

c
// SPI 初始化
void SPI_Init(void) {
    // 1. 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置 GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // SCK - PA5
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // MOSI - PA7
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // MISO - PA6
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // CS - PA4
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 3. 配置 SPI
    SPI_InitTypeDef SPI_InitStruct;
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStruct.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStruct);
    
    // 4. 使能 SPI
    SPI_Cmd(SPI1, ENABLE);
}

3. SPI 读写操作

c
// SPI 发送接收单个字节
uint8_t SPI_TransferByte(uint8_t data) {
    // 等待发送缓冲区空
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    
    // 发送数据
    SPI_I2S_SendData(SPI1, data);
    
    // 等待接收缓冲区非空
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    
    // 接收数据
    return SPI_I2S_ReceiveData(SPI1);
}

// SPI 发送多个字节
void SPI_SendBuffer(const uint8_t *data, uint16_t len) {
    for(uint16_t i = 0; i < len; i++) {
        SPI_TransferByte(data[i]);
    }
}

// SPI 接收多个字节
void SPI_ReceiveBuffer(uint8_t *data, uint16_t len) {
    for(uint16_t i = 0; i < len; i++) {
        data[i] = SPI_TransferByte(0xFF);
    }
}

4. SPI 设备驱动示例

c
// W25Q128 Flash 驱动
#define W25Q128_CS_LOW()   GPIO_ResetBits(GPIOA, GPIO_Pin_4)
#define W25Q128_CS_HIGH()  GPIO_SetBits(GPIOA, GPIO_Pin_4)

// 读取设备 ID
uint16_t W25Q128_ReadID(void) {
    uint16_t id;
    
    W25Q128_CS_LOW();
    SPI_TransferByte(0x90);  // 读取 ID 命令
    SPI_TransferByte(0x00);
    SPI_TransferByte(0x00);
    SPI_TransferByte(0x00);
    id = SPI_TransferByte(0xFF) << 8;
    id |= SPI_TransferByte(0xFF);
    W25Q128_CS_HIGH();
    
    return id;
}

// 读取数据
void W25Q128_ReadData(uint32_t addr, uint8_t *data, uint32_t len) {
    W25Q128_CS_LOW();
    SPI_TransferByte(0x03);  // 读取数据命令
    SPI_TransferByte((addr >> 16) & 0xFF);
    SPI_TransferByte((addr >> 8) & 0xFF);
    SPI_TransferByte(addr & 0xFF);
    
    for(uint32_t i = 0; i < len; i++) {
        data[i] = SPI_TransferByte(0xFF);
    }
    
    W25Q128_CS_HIGH();
}

// 写入数据(页编程)
void W25Q128_WritePage(uint32_t addr, const uint8_t *data, uint16_t len) {
    // 写使能
    W25Q128_CS_LOW();
    SPI_TransferByte(0x06);
    W25Q128_CS_HIGH();
    
    // 页编程
    W25Q128_CS_LOW();
    SPI_TransferByte(0x02);  // 页编程命令
    SPI_TransferByte((addr >> 16) & 0xFF);
    SPI_TransferByte((addr >> 8) & 0xFF);
    SPI_TransferByte(addr & 0xFF);
    
    for(uint16_t i = 0; i < len; i++) {
        SPI_TransferByte(data[i]);
    }
    
    W25Q128_CS_HIGH();
    
    // 等待写入完成
    while(W25Q128_ReadStatus() & 0x01);
}

CAN 通信

1. CAN 原理

code
CAN 总线结构:
┌─────────┐     ┌─────────┐     ┌─────────┐
│  节点1   │     │  节点2   │     │  节点3   │
└────┬────┘     └────┬────┘     └────┬────┘
     │               │               │
     └───────────────┼───────────────┘
                     │
              ┌──────┴──────┐
              │   120Ω 终端  │
              └─────────────┘

CAN 数据帧格式:
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ SOF │ ID  │ RTR │ IDE │ DLC │数据 │ CRC │ ACK │ EOF │
│ 1位 │11位 │ 1位 │ 1位 │ 4位 │0-8字│15位 │ 2位 │ 7位 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

2. CAN 配置

c
// CAN 初始化
void CAN_Init(void) {
    // 1. 使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置 GPIO
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // CAN_TX - PA12
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // CAN_RX - PA11
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 3. 配置 CAN
    CAN_InitTypeDef CAN_InitStruct;
    CAN_InitStruct.CAN_TTCM = DISABLE;
    CAN_InitStruct.CAN_ABOM = DISABLE;
    CAN_InitStruct.CAN_AWUM = DISABLE;
    CAN_InitStruct.CAN_NART = DISABLE;
    CAN_InitStruct.CAN_RFLM = DISABLE;
    CAN_InitStruct.CAN_TXFP = DISABLE;
    CAN_InitStruct.CAN_Mode = CAN_Mode_Normal;
    CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStruct.CAN_BS1 = CAN_BS1_3tq;
    CAN_InitStruct.CAN_BS2 = CAN_BS2_2tq;
    CAN_InitStruct.CAN_Prescaler = 6;  // 36MHz / (1+3+2) / 6 = 1Mbps
    CAN_Init(CAN1, &CAN_InitStruct);
    
    // 4. 配置过滤器
    CAN_FilterInitTypeDef CAN_FilterInitStruct;
    CAN_FilterInitStruct.CAN_FilterNumber = 0;
    CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStruct.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStruct.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    CAN_FilterInitStruct.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStruct);
}

3. CAN 数据收发

c
// CAN 发送数据
void CAN_SendMessage(uint32_t id, uint8_t *data, uint8_t len) {
    CanTxMsg TxMessage;
    
    TxMessage.StdId = id;
    TxMessage.ExtId = 0x00;
    TxMessage.RTR = CAN_RTR_Data;
    TxMessage.IDE = CAN_ID_STD;
    TxMessage.DLC = len;
    
    for(uint8_t i = 0; i < len; i++) {
        TxMessage.Data[i] = data[i];
    }
    
    CAN_Transmit(CAN1, &TxMessage);
}

// CAN 接收数据
void CAN_ReceiveMessage(uint32_t *id, uint8_t *data, uint8_t *len) {
    CanRxMsg RxMessage;
    
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
    
    *id = RxMessage.StdId;
    *len = RxMessage.DLC;
    
    for(uint8_t i = 0; i < *len; i++) {
        data[i] = RxMessage.Data[i];
    }
}

4. CAN 中断接收

c
// CAN 中断配置
void CAN_Interrupt_Init(void) {
    NVIC_InitTypeDef NVIC_InitStruct;
    
    NVIC_InitStruct.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

// 中断服务函数
void USB_LP_CAN1_RX0_IRQHandler(void) {
    if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
        uint32_t id;
        uint8_t data[8];
        uint8_t len;
        
        CAN_ReceiveMessage(&id, data, &len);
        
        // 处理接收到的数据
        CAN_ProcessMessage(id, data, len);
        
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
    }
}

协议选择指南

1. 选择标准

code
选择通信协议的考虑因素:

1. 速度需求
   - 低速:UART, I2C
   - 高速:SPI, CAN

2. 距离需求
   - 短距离:I2C, SPI
   - 长距离:UART, CAN

3. 设备数量
   - 单设备:UART, SPI
   - 多设备:I2C, CAN

4. 可靠性需求
   - 一般:UART, I2C, SPI
   - 高可靠性:CAN

2. 应用场景

场景推荐协议原因
调试串口UART简单、通用
传感器数据I2C多设备、低功耗
高速数据采集SPI高速、全双工
汽车电子CAN可靠、多主
显示屏SPI高速、大数据量
存储器SPI高速、简单

下一篇

接下来我们将深入探讨嵌入式实时操作系统(RTOS),包括任务管理、同步机制和内存管理等内容。