入门工程师指南:基于CRC校验的通信协议底层C语言实现

第一部分:基础概念详解与入门准备

1.1 核心概念深入浅出

1.1.1 生产者-消费者模式详解

什么是生产者-消费者模式?

想象一个快餐店的厨房:

  • 生产者:厨师制作汉堡(生成数据)

  • 缓冲区:保温台(存储数据)

  • 消费者:服务员取走汉堡(处理数据)

在单片机通信中:

  • 生产者:UART接收中断(接收数据)

  • 缓冲区:环形队列(存储接收到的字节)

  • 消费者:主循环或任务(解析和处理数据)

c

复制代码
// 生产者-消费者模式的简单示例
// 生产者:UART接收中断
void UART1_IRQHandler(void) {
    if (UART1->SR & UART_SR_RXNE) {
        uint8_t data = UART1->DR;  // 读取数据
        ring_buffer_put(&rx_buffer, data);  // 放入缓冲区(生产)
    }
}

// 消费者:主循环
int main(void) {
    while (1) {
        uint8_t data;
        if (ring_buffer_get(&rx_buffer, &data)) {  // 从缓冲区取出(消费)
            process_data(data);  // 处理数据
        }
    }
}
1.1.2 队列(环形缓冲区)基本原理

为什么需要队列?

  • 解决生产者和消费者速度不匹配的问题

  • 防止数据丢失

  • 实现异步处理

环形缓冲区的工作原理:

text

复制代码
初始状态:
[ ][ ][ ][ ][ ][ ][ ][ ]
 ^
head = tail = 0

放入3个数据后:
[A][B][C][ ][ ][ ][ ][ ]
           ^     ^
          tail  head

取出2个数据后:
[ ][ ][C][ ][ ][ ][ ][ ]
     ^     ^
    tail  head
1.1.3 CRC校验的本质

CRC的简单理解:

就像网购时商家给你的订单号(CRC),你收到货后自己计算订单号(CRC),如果一致说明货物完整。

CRC的核心特点:

  1. 检错能力强:能检测多种错误

  2. 计算简单:适合单片机

  3. 开销小:只需要少量校验位

1.2 开发环境搭建

1.2.1 硬件选择建议

对于入门工程师,推荐以下硬件:

单片机型号 优点 适合项目
STM32F103C8T6 资源丰富,资料多,价格便宜 学习、中小型项目
STM32F411CEU6 性能更强,有硬件CRC 需要CRC性能的项目
ATmega328P Arduino兼容,简单易用 快速原型开发
1.2.2 软件工具链

bash

复制代码
# 开发工具推荐
1. 编辑器:VS Code + PlatformIO 或 STM32CubeIDE
2. 编译器:arm-none-eabi-gcc
3. 调试器:ST-Link V2 或 J-Link
4. 串口工具:Putty、Tera Term 或 CoolTerm

# 项目目录结构
my_protocol_project/
├── inc/           # 头文件
│   ├── uart.h
│   ├── crc.h
│   ├── queue.h
│   └── protocol.h
├── src/           # 源文件
│   ├── main.c
│   ├── uart.c
│   ├── crc.c
│   ├── queue.c
│   └── protocol.c
├── drivers/       # 驱动程序
├── tests/         # 测试文件
└── Makefile       # 编译脚本
1.2.3 第一个测试程序:点亮LED

c

复制代码
// 第一个单片机程序:闪烁LED
#include "stm32f1xx.h"

// 简单延时函数
void delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 1000; i++) {
        __NOP();  // 空操作,消耗时间
    }
}

int main(void) {
    // 1. 使能GPIOC时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    
    // 2. 配置PC13为推挽输出(LED)
    GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
    GPIOC->CRH |= GPIO_CRH_MODE13_1;  // 输出模式,最大速度2MHz
    
    while (1) {
        // 3. 点亮LED(PC13低电平点亮)
        GPIOC->BRR = GPIO_BRR_BR13;
        delay_ms(500);
        
        // 4. 熄灭LED
        GPIOC->BSRR = GPIO_BSRR_BS13;
        delay_ms(500);
    }
}

第二部分:基础模块实现(从零开始)

2.1 队列(环形缓冲区)实现

2.1.1 最简单的队列实现

c

复制代码
// queue_simple.c - 最简单的队列实现
#include "queue_simple.h"

// 队列结构体
typedef struct {
    uint8_t buffer[QUEUE_SIZE];  // 缓冲区
    uint16_t head;               // 写指针(下一个写入位置)
    uint16_t tail;               // 读指针(下一个读取位置)
    uint16_t count;              // 当前元素数量(可选)
} simple_queue_t;

// 初始化队列
void queue_init(simple_queue_t *q) {
    q->head = 0;
    q->tail = 0;
    q->count = 0;
}

// 检查队列是否为空
bool queue_is_empty(simple_queue_t *q) {
    return (q->head == q->tail);
}

// 检查队列是否已满
bool queue_is_full(simple_queue_t *q) {
    return ((q->head + 1) % QUEUE_SIZE == q->tail);
}

// 入队(放入数据)
bool queue_enqueue(simple_queue_t *q, uint8_t data) {
    if (queue_is_full(q)) {
        return false;  // 队列已满
    }
    
    q->buffer[q->head] = data;
    q->head = (q->head + 1) % QUEUE_SIZE;
    q->count++;
    
    return true;
}

// 出队(取出数据)
bool queue_dequeue(simple_queue_t *q, uint8_t *data) {
    if (queue_is_empty(q)) {
        return false;  // 队列为空
    }
    
    *data = q->buffer[q->tail];
    q->tail = (q->tail + 1) % QUEUE_SIZE;
    q->count--;
    
    return true;
}

// 获取队列中元素数量
uint16_t queue_count(simple_queue_t *q) {
    return q->count;
}

// 查看队列头部元素(不取出)
bool queue_peek(simple_queue_t *q, uint8_t *data) {
    if (queue_is_empty(q)) {
        return false;
    }
    
    *data = q->buffer[q->tail];
    return true;
}
2.1.2 增强型队列(带互斥保护)

c

复制代码
// queue_enhanced.c - 增强型队列(支持多任务)
#include "queue_enhanced.h"

// 增强型队列结构体
typedef struct {
    uint8_t *buffer;            // 缓冲区指针
    uint16_t size;              // 缓冲区大小
    volatile uint16_t head;     // 写指针(volatile保证多线程可见性)
    volatile uint16_t tail;     // 读指针
    volatile uint16_t count;    // 元素数量
    bool overwrite;             // 是否允许覆盖(当队列满时)
    
    // 统计信息
    uint32_t enqueue_count;     // 入队计数
    uint32_t dequeue_count;     // 出队计数
    uint32_t overflow_count;    // 溢出计数
    uint32_t underflow_count;   // 下溢计数
} enhanced_queue_t;

// 初始化队列
bool enhanced_queue_init(enhanced_queue_t *q, uint8_t *buffer, 
                        uint16_t size, bool overwrite) {
    if (buffer == NULL || size < 2) {
        return false;
    }
    
    q->buffer = buffer;
    q->size = size;
    q->head = 0;
    q->tail = 0;
    q->count = 0;
    q->overwrite = overwrite;
    
    q->enqueue_count = 0;
    q->dequeue_count = 0;
    q->overflow_count = 0;
    q->underflow_count = 0;
    
    return true;
}

// 安全的入队操作(带互斥保护)
bool enhanced_queue_enqueue_safe(enhanced_queue_t *q, uint8_t data) {
    // 使用临界区保护(防止中断打断)
    __disable_irq();  // 禁用中断
    
    bool result = enhanced_queue_enqueue(q, data);
    
    __enable_irq();   // 启用中断
    
    return result;
}

// 入队操作
bool enhanced_queue_enqueue(enhanced_queue_t *q, uint8_t data) {
    uint16_t next_head = (q->head + 1) % q->size;
    
    if (next_head == q->tail) {
        // 队列已满
        if (q->overwrite) {
            // 允许覆盖:移动尾指针,丢弃最旧的数据
            q->tail = (q->tail + 1) % q->size;
            q->count--;
            q->overflow_count++;
        } else {
            // 不允许覆盖
            q->overflow_count++;
            return false;
        }
    }
    
    // 放入数据
    q->buffer[q->head] = data;
    q->head = next_head;
    q->count++;
    q->enqueue_count++;
    
    return true;
}

// 批量入队
uint16_t enhanced_queue_enqueue_batch(enhanced_queue_t *q, 
                                     const uint8_t *data, 
                                     uint16_t length) {
    uint16_t enqueued = 0;
    
    for (uint16_t i = 0; i < length; i++) {
        if (enhanced_queue_enqueue(q, data[i])) {
            enqueued++;
        } else {
            break;
        }
    }
    
    return enqueued;
}

// 安全的出队操作
bool enhanced_queue_dequeue_safe(enhanced_queue_t *q, uint8_t *data) {
    __disable_irq();
    bool result = enhanced_queue_dequeue(q, data);
    __enable_irq();
    
    return result;
}

// 出队操作
bool enhanced_queue_dequeue(enhanced_queue_t *q, uint8_t *data) {
    if (q->head == q->tail) {
        // 队列为空
        q->underflow_count++;
        return false;
    }
    
    // 取出数据
    *data = q->buffer[q->tail];
    q->tail = (q->tail + 1) % q->size;
    q->count--;
    q->dequeue_count++;
    
    return true;
}

// 批量出队
uint16_t enhanced_queue_dequeue_batch(enhanced_queue_t *q, 
                                     uint8_t *data, 
                                     uint16_t max_length) {
    uint16_t dequeued = 0;
    
    while (dequeued < max_length) {
        if (!enhanced_queue_dequeue(q, &data[dequeued])) {
            break;
        }
        dequeued++;
    }
    
    return dequeued;
}

// 获取队列统计信息
void enhanced_queue_get_stats(enhanced_queue_t *q, queue_stats_t *stats) {
    stats->current_count = q->count;
    stats->max_capacity = q->size - 1;
    stats->enqueue_count = q->enqueue_count;
    stats->dequeue_count = q->dequeue_count;
    stats->overflow_count = q->overflow_count;
    stats->underflow_count = q->underflow_count;
    
    // 计算使用率
    stats->usage_percent = (float)q->count / (q->size - 1) * 100.0f;
    
    // 计算平均入队/出队速率(如果记录了时间)
    // 这里需要额外的时间戳记录
}

// 队列诊断
void enhanced_queue_diagnose(enhanced_queue_t *q) {
    printf("=== Queue Diagnostics ===\n");
    printf("Size: %u\n", q->size);
    printf("Current count: %u\n", q->count);
    printf("Head: %u, Tail: %u\n", q->head, q->tail);
    printf("Enqueues: %lu, Dequeues: %lu\n", 
           q->enqueue_count, q->dequeue_count);
    printf("Overflows: %lu, Underflows: %lu\n",
           q->overflow_count, q->underflow_count);
    printf("Usage: %.1f%%\n", (float)q->count / (q->size - 1) * 100.0f);
    
    // 显示缓冲区内容(调试用)
    printf("Buffer contents:\n");
    for (uint16_t i = 0; i < q->size; i++) {
        if (i == q->head) printf("[H]");
        if (i == q->tail) printf("[T]");
        printf(" %02X", q->buffer[i]);
        if ((i + 1) % 16 == 0) printf("\n");
    }
    printf("\n");
}

2.2 CRC校验模块实现

2.2.1 最简单的CRC-8实现

c

复制代码
// crc_simple.c - 最简单的CRC实现(适合入门)
#include "crc_simple.h"

// CRC-8计算(逐位计算,最易理解)
uint8_t crc8_simple(const uint8_t *data, uint32_t length) {
    uint8_t crc = 0x00;        // 初始值
    uint8_t polynomial = 0x07;  // CRC-8多项式:x^8 + x^2 + x + 1
    
    for (uint32_t i = 0; i < length; i++) {
        crc ^= data[i];        // 异或当前字节
        
        // 处理8位
        for (int bit = 0; bit < 8; bit++) {
            if (crc & 0x80) {  // 检查最高位是否为1
                crc = (crc << 1) ^ polynomial;
            } else {
                crc = crc << 1;
            }
        }
    }
    
    return crc;
}

// CRC-8验证
bool crc8_verify(const uint8_t *data, uint32_t length) {
    if (length < 1) {
        return false;
    }
    
    // 计算除最后一个字节外的CRC
    uint8_t calculated_crc = crc8_simple(data, length - 1);
    
    // 与最后一个字节(CRC字节)比较
    return (calculated_crc == data[length - 1]);
}

// CRC-8生成(将CRC附加到数据后)
uint32_t crc8_append(uint8_t *buffer, const uint8_t *data, uint32_t data_length) {
    // 复制数据
    for (uint32_t i = 0; i < data_length; i++) {
        buffer[i] = data[i];
    }
    
    // 计算并附加CRC
    uint8_t crc = crc8_simple(data, data_length);
    buffer[data_length] = crc;
    
    return data_length + 1;  // 返回总长度
}
2.2.2 CRC-16实现(查表法优化)

c

复制代码
// crc16.c - CRC-16实现(适合实际项目)
#include "crc16.h"

// CRC-16查找表(预先计算好)
static const uint16_t crc16_table[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

// CRC-16计算(查表法,快速)
uint16_t crc16_calculate(const uint8_t *data, uint32_t length) {
    uint16_t crc = 0xFFFF;  // CRC-16初始值
    
    for (uint32_t i = 0; i < length; i++) {
        uint8_t index = (crc ^ data[i]) & 0xFF;
        crc = (crc >> 8) ^ crc16_table[index];
    }
    
    return crc;
}

// CRC-16验证
bool crc16_verify(const uint8_t *data, uint32_t length) {
    if (length < 2) {
        return false;
    }
    
    // 计算除最后两个字节外的CRC
    uint16_t calculated_crc = crc16_calculate(data, length - 2);
    
    // 提取接收到的CRC(假设低字节在前)
    uint16_t received_crc = (data[length - 1] << 8) | data[length - 2];
    
    return (calculated_crc == received_crc);
}

// CRC-16生成(将CRC附加到数据后)
uint32_t crc16_append(uint8_t *buffer, const uint8_t *data, uint32_t data_length) {
    // 复制数据
    for (uint32_t i = 0; i < data_length; i++) {
        buffer[i] = data[i];
    }
    
    // 计算CRC
    uint16_t crc = crc16_calculate(data, data_length);
    
    // 附加CRC(低字节在前)
    buffer[data_length] = crc & 0xFF;      // 低字节
    buffer[data_length + 1] = crc >> 8;    // 高字节
    
    return data_length + 2;  // 返回总长度
}

// 逐步计算CRC(用于流式数据)
uint16_t crc16_init(void) {
    return 0xFFFF;
}

uint16_t crc16_update(uint16_t crc, uint8_t data) {
    uint8_t index = (crc ^ data) & 0xFF;
    return (crc >> 8) ^ crc16_table[index];
}

uint16_t crc16_final(uint16_t crc) {
    return crc;
}

2.3 UART驱动实现

2.3.1 最简单的UART驱动

c

复制代码
// uart_simple.c - 最简单的UART驱动
#include "uart_simple.h"

// UART初始化(针对STM32F103C8T6,PA9=TX, PA10=RX)
void uart_simple_init(uint32_t baudrate) {
    // 1. 使能时钟
    // 使能GPIOA时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    // 使能USART1时钟
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    
    // 2. 配置GPIO
    // PA9 (TX) 复用推挽输出,最大速度50MHz
    GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
    GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;
    
    // PA10 (RX) 浮空输入
    GPIOA->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE10);
    GPIOA->CRH |= GPIO_CRH_CNF10_0;
    
    // 3. 配置USART
    // 禁用USART(在配置前需要禁用)
    USART1->CR1 &= ~USART_CR1_UE;
    
    // 计算波特率
    // 假设系统时钟为72MHz
    uint32_t clock = 72000000;  // 72MHz
    uint32_t usart_div = (clock + (baudrate / 2)) / baudrate;
    
    // 设置波特率
    USART1->BRR = usart_div;
    
    // 配置数据格式:8位数据,无校验,1位停止位
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE;  // 使能发送和接收
    
    // 使能USART
    USART1->CR1 |= USART_CR1_UE;
}

// 发送一个字节(轮询方式)
void uart_simple_send_byte(uint8_t byte) {
    // 等待发送缓冲区空
    while (!(USART1->SR & USART_SR_TXE)) {
        // 空循环等待
    }
    
    // 发送数据
    USART1->DR = byte;
    
    // 等待发送完成(可选)
    while (!(USART1->SR & USART_SR_TC)) {
        // 空循环等待
    }
}

// 接收一个字节(轮询方式,阻塞)
uint8_t uart_simple_receive_byte(void) {
    // 等待数据到达
    while (!(USART1->SR & USART_SR_RXNE)) {
        // 空循环等待
    }
    
    // 读取数据
    return (uint8_t)(USART1->DR & 0xFF);
}

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

// 检查是否有数据可读(非阻塞)
bool uart_simple_available(void) {
    return (USART1->SR & USART_SR_RXNE) != 0;
}

// 尝试接收字节(非阻塞)
bool uart_simple_try_receive(uint8_t *byte) {
    if (uart_simple_available()) {
        *byte = (uint8_t)(USART1->DR & 0xFF);
        return true;
    }
    return false;
}
2.3.2 中断驱动的UART(生产者)

c

复制代码
// uart_interrupt.c - 中断驱动的UART
#include "uart_interrupt.h"

// 全局接收队列(生产者-消费者模式的缓冲区)
static enhanced_queue_t uart_rx_queue;

// 接收缓冲区
static uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];

// UART初始化(带中断)
void uart_interrupt_init(uint32_t baudrate) {
    // 1. 初始化接收队列
    enhanced_queue_init(&uart_rx_queue, uart_rx_buffer, 
                       UART_RX_BUFFER_SIZE, false);
    
    // 2. 初始化UART硬件(复用之前的初始化代码)
    uart_simple_init(baudrate);
    
    // 3. 使能接收中断
    USART1->CR1 |= USART_CR1_RXNEIE;  // 接收缓冲区非空中断
    
    // 4. 在NVIC中使能USART1中断
    // 设置中断优先级
    NVIC_SetPriority(USART1_IRQn, 0);  // 最高优先级
    // 使能中断
    NVIC_EnableIRQ(USART1_IRQn);
}

// USART1中断处理函数(生产者)
void USART1_IRQHandler(void) {
    // 检查是否是接收中断
    if (USART1->SR & USART_SR_RXNE) {
        // 读取接收到的数据
        uint8_t data = (uint8_t)(USART1->DR & 0xFF);
        
        // 放入接收队列(生产数据)
        if (!enhanced_queue_enqueue(&uart_rx_queue, data)) {
            // 队列满,可以在这里处理溢出
            // 例如:点亮错误LED、增加错误计数等
        }
        
        // 可以在这里添加数据处理回调
        // 例如:如果收到特定字符,立即处理
        if (data == '\r' || data == '\n') {
            // 触发数据处理
        }
    }
    
    // 可以处理其他UART中断(发送完成、错误等)
    if (USART1->SR & USART_SR_TC) {
        // 发送完成中断
        USART1->SR &= ~USART_SR_TC;  // 清除标志
    }
    
    if (USART1->SR & USART_SR_ORE) {
        // 溢出错误
        USART1->SR &= ~USART_SR_ORE;  // 清除标志
        // 处理错误...
    }
}

// 从队列获取数据(消费者)
bool uart_get_byte(uint8_t *byte) {
    return enhanced_queue_dequeue(&uart_rx_queue, byte);
}

// 获取队列中可用的数据数量
uint16_t uart_available(void) {
    return uart_rx_queue.count;
}

// 清空接收队列
void uart_flush(void) {
    uart_rx_queue.head = uart_rx_queue.tail;
    uart_rx_queue.count = 0;
}

// 发送字节(中断方式,可选)
void uart_send_byte_it(uint8_t byte) {
    // 等待发送缓冲区空
    while (!(USART1->SR & USART_SR_TXE)) {
        // 空循环等待
    }
    
    // 发送数据
    USART1->DR = byte;
}

// 批量发送数据
void uart_send_buffer(const uint8_t *buffer, uint16_t length) {
    for (uint16_t i = 0; i < length; i++) {
        uart_send_byte_it(buffer[i]);
    }
}

第三部分:通信协议实现(初学者版)

3.1 简单协议设计

3.1.1 协议帧格式设计

对于入门项目,我们设计一个简单的协议:

text

复制代码
帧格式:
[起始符] [长度] [命令] [数据...] [CRC] [结束符]

具体:
+--------+--------+--------+-----------+-------+--------+
|  起始  |  长度  |  命令  |   数据    |  CRC  |  结束  |
+--------+--------+--------+-----------+-------+--------+
|  1字节 |  1字节 |  1字节 |  N字节    | 2字节 |  1字节 |
+--------+--------+--------+-----------+-------+--------+
|  0xAA  |  N+3   |  CMD   |  DATA     | CRC16 |  0x55  |
+--------+--------+--------+-----------+-------+--------+

说明:
1. 起始符:0xAA(固定)
2. 长度:从命令开始到CRC结束的字节数(不包括起始符和结束符)
3. 命令:表示操作类型
4. 数据:可变长度,由长度字段决定
5. CRC:CRC-16校验,校验范围:长度+命令+数据
6. 结束符:0x55(固定)
3.1.2 命令定义

c

复制代码
// protocol_commands.h - 协议命令定义
#ifndef PROTOCOL_COMMANDS_H
#define PROTOCOL_COMMANDS_H

// 系统命令(0x00-0x0F)
#define CMD_PING           0x01  // 测试连接
#define CMD_GET_VERSION    0x02  // 获取版本
#define CMD_RESET          0x03  // 复位设备
#define CMD_GET_STATUS     0x04  // 获取状态

// 数据命令(0x10-0x1F)
#define CMD_SEND_DATA      0x10  // 发送数据
#define CMD_READ_DATA      0x11  // 读取数据
#define CMD_WRITE_DATA     0x12  // 写入数据
#define CMD_CLEAR_DATA     0x13  // 清除数据

// 控制命令(0x20-0x2F)
#define CMD_SET_LED        0x20  // 设置LED
#define CMD_SET_RELAY      0x21  // 设置继电器
#define CMD_GET_ADC        0x22  // 获取ADC值
#define CMD_SET_PWM        0x23  // 设置PWM

// 响应码
#define RESPONSE_OK        0x00  // 成功
#define RESPONSE_ERROR     0x01  // 错误
#define RESPONSE_BUSY      0x02  // 忙
#define RESPONSE_TIMEOUT   0x03  // 超时
#define RESPONSE_CRC_ERROR 0x04  // CRC错误
#define RESPONSE_INVALID_CMD 0x05  // 无效命令
#define RESPONSE_INVALID_DATA 0x06  // 无效数据

#endif // PROTOCOL_COMMANDS_H

3.2 协议解析器实现

3.2.1 状态机解析器

c

复制代码
// protocol_parser.c - 协议解析器(状态机实现)
#include "protocol_parser.h"

// 协议解析器状态
typedef enum {
    STATE_IDLE,          // 空闲状态
    STATE_START,         // 收到起始符
    STATE_LENGTH,        // 接收长度
    STATE_COMMAND,       // 接收命令
    STATE_DATA,          // 接收数据
    STATE_CRC_LOW,       // 接收CRC低字节
    STATE_CRC_HIGH,      // 接收CRC高字节
    STATE_END,           // 接收结束符
    STATE_COMPLETE,      // 帧接收完成
    STATE_ERROR          // 错误状态
} parser_state_t;

// 协议解析器上下文
typedef struct {
    parser_state_t state;     // 当前状态
    uint8_t buffer[MAX_FRAME_SIZE];  // 接收缓冲区
    uint16_t index;           // 缓冲区索引
    uint16_t expected_length; // 期望的数据长度
    uint16_t crc_calculated;  // 计算的CRC值
    uint16_t crc_received;    // 接收的CRC值
    uint32_t last_byte_time;  // 最后字节接收时间
    uint32_t timeout_ms;      // 超时时间
    
    // 统计信息
    uint32_t frames_received;   // 接收帧数
    uint32_t frames_processed;  // 处理帧数
    uint32_t crc_errors;        // CRC错误数
    uint32_t timeout_errors;    // 超时错误数
    uint32_t format_errors;     // 格式错误数
} protocol_parser_t;

// 初始化解析器
void parser_init(protocol_parser_t *parser, uint32_t timeout_ms) {
    parser->state = STATE_IDLE;
    parser->index = 0;
    parser->expected_length = 0;
    parser->crc_calculated = 0xFFFF;
    parser->crc_received = 0;
    parser->timeout_ms = timeout_ms;
    
    parser->frames_received = 0;
    parser->frames_processed = 0;
    parser->crc_errors = 0;
    parser->timeout_errors = 0;
    parser->format_errors = 0;
}

// 处理接收到的字节
parser_result_t parser_process_byte(protocol_parser_t *parser, uint8_t byte) {
    parser_result_t result = {PARSER_CONTINUE, 0};
    
    // 更新最后接收时间
    parser->last_byte_time = get_system_tick();
    
    // 状态机处理
    switch (parser->state) {
        case STATE_IDLE:
            if (byte == FRAME_START) {
                // 收到起始符,开始接收帧
                parser->state = STATE_START;
                parser->index = 0;
                parser->buffer[parser->index++] = byte;
                parser->crc_calculated = 0xFFFF;  // 重置CRC
            }
            break;
            
        case STATE_START:
            // 接收长度字段
            parser->buffer[parser->index++] = byte;
            
            // 长度字段就是期望的数据长度(不包括CRC和结束符)
            parser->expected_length = byte;
            
            // 验证长度(不能超过最大帧长)
            if (parser->expected_length > MAX_FRAME_SIZE - 3) {
                // 长度无效,回到空闲状态
                parser->state = STATE_IDLE;
                parser->format_errors++;
                result.status = PARSER_ERROR;
                result.error_code = ERROR_INVALID_LENGTH;
            } else if (parser->expected_length >= 3) {
                // 长度字段包含:命令(1) + 数据(N) + CRC(2)
                // 所以数据长度 = expected_length - 3
                parser->state = STATE_COMMAND;
            } else {
                // 长度太小(至少要有命令+CRC)
                parser->state = STATE_IDLE;
                parser->format_errors++;
                result.status = PARSER_ERROR;
                result.error_code = ERROR_INVALID_LENGTH;
            }
            break;
            
        case STATE_COMMAND:
            // 接收命令字段
            parser->buffer[parser->index++] = byte;
            
            // 开始计算CRC(从长度字段开始)
            parser->crc_calculated = crc16_update(parser->crc_calculated, 
                                                 parser->buffer[1]);  // 长度
            parser->crc_calculated = crc16_update(parser->crc_calculated, byte);  // 命令
            
            if (parser->expected_length > 3) {
                // 还有数据要接收
                parser->state = STATE_DATA;
            } else {
                // 没有数据,直接接收CRC
                parser->state = STATE_CRC_LOW;
            }
            break;
            
        case STATE_DATA:
            // 接收数据字段
            parser->buffer[parser->index++] = byte;
            
            // 更新CRC
            parser->crc_calculated = crc16_update(parser->crc_calculated, byte);
            
            // 检查是否接收完所有数据
            // 已接收字节数 = index - 2(减去起始符和长度)
            // 期望的数据长度 = expected_length - 3(命令+CRC)
            if ((parser->index - 2) >= parser->expected_length - 1) {
                // 数据接收完成,接下来是CRC
                parser->state = STATE_CRC_LOW;
            }
            break;
            
        case STATE_CRC_LOW:
            // 接收CRC低字节
            parser->crc_received = byte;
            parser->buffer[parser->index++] = byte;
            parser->state = STATE_CRC_HIGH;
            break;
            
        case STATE_CRC_HIGH:
            // 接收CRC高字节
            parser->crc_received |= (byte << 8);
            parser->buffer[parser->index++] = byte;
            parser->state = STATE_END;
            break;
            
        case STATE_END:
            // 接收结束符
            if (byte == FRAME_END) {
                parser->buffer[parser->index++] = byte;
                
                // 验证CRC
                if (parser->crc_calculated == parser->crc_received) {
                    // CRC正确,帧接收完成
                    parser->state = STATE_COMPLETE;
                    result.status = PARSER_COMPLETE;
                    result.frame_length = parser->index;
                    
                    // 更新统计
                    parser->frames_received++;
                } else {
                    // CRC错误
                    parser->state = STATE_IDLE;
                    parser->crc_errors++;
                    result.status = PARSER_ERROR;
                    result.error_code = ERROR_CRC;
                }
            } else {
                // 结束符错误
                parser->state = STATE_IDLE;
                parser->format_errors++;
                result.status = PARSER_ERROR;
                result.error_code = ERROR_INVALID_END;
            }
            break;
            
        case STATE_COMPLETE:
            // 帧已接收完成,等待上层处理
            // 这里不处理新字节,需要调用parser_reset重置状态
            break;
            
        case STATE_ERROR:
            // 错误状态,等待重置
            break;
    }
    
    return result;
}

// 检查超时
void parser_check_timeout(protocol_parser_t *parser) {
    if (parser->state != STATE_IDLE && 
        parser->state != STATE_COMPLETE &&
        parser->state != STATE_ERROR) {
        
        uint32_t current_time = get_system_tick();
        uint32_t elapsed = current_time - parser->last_byte_time;
        
        if (elapsed > parser->timeout_ms) {
            // 超时,重置解析器
            parser->state = STATE_IDLE;
            parser->timeout_errors++;
        }
    }
}

// 重置解析器
void parser_reset(protocol_parser_t *parser) {
    parser->state = STATE_IDLE;
    parser->index = 0;
    parser->expected_length = 0;
    parser->crc_calculated = 0xFFFF;
    parser->crc_received = 0;
}

// 获取解析器状态
parser_stats_t parser_get_stats(protocol_parser_t *parser) {
    parser_stats_t stats;
    
    stats.frames_received = parser->frames_received;
    stats.frames_processed = parser->frames_processed;
    stats.crc_errors = parser->crc_errors;
    stats.timeout_errors = parser->timeout_errors;
    stats.format_errors = parser->format_errors;
    
    // 计算错误率
    uint32_t total_errors = parser->crc_errors + 
                           parser->timeout_errors + 
                           parser->format_errors;
    uint32_t total_frames = parser->frames_received + total_errors;
    
    if (total_frames > 0) {
        stats.error_rate = (float)total_errors / total_frames * 100.0f;
    } else {
        stats.error_rate = 0.0f;
    }
    
    return stats;
}
3.2.2 协议处理器

c

复制代码
// protocol_handler.c - 协议处理器(消费者)
#include "protocol_handler.h"

// 全局解析器实例
static protocol_parser_t protocol_parser;

// 全局接收队列(从UART中断填充)
extern enhanced_queue_t uart_rx_queue;

// 初始化协议处理器
void protocol_handler_init(void) {
    // 初始化解析器
    parser_init(&protocol_parser, PROTOCOL_TIMEOUT_MS);
    
    // 初始化其他组件...
}

// 协议处理任务(在主循环中调用)
void protocol_process_task(void) {
    uint8_t byte;
    
    // 从队列中取出所有可用的字节
    while (enhanced_queue_dequeue(&uart_rx_queue, &byte)) {
        // 处理每个字节
        parser_result_t result = parser_process_byte(&protocol_parser, byte);
        
        switch (result.status) {
            case PARSER_COMPLETE:
                // 帧接收完成,处理帧
                protocol_handle_frame(&protocol_parser.buffer[0], 
                                     result.frame_length);
                
                // 重置解析器以接收下一帧
                parser_reset(&protocol_parser);
                break;
                
            case PARSER_ERROR:
                // 处理错误
                protocol_handle_error(result.error_code);
                
                // 重置解析器
                parser_reset(&protocol_parser);
                break;
                
            case PARSER_CONTINUE:
                // 继续接收,不做特殊处理
                break;
        }
    }
    
    // 检查超时
    parser_check_timeout(&protocol_parser);
}

// 处理接收到的完整帧
void protocol_handle_frame(uint8_t *frame, uint16_t length) {
    // 解析帧
    protocol_frame_t parsed_frame;
    
    if (!protocol_parse_frame(frame, length, &parsed_frame)) {
        // 解析失败
        protocol_send_error_response(ERROR_INVALID_FRAME);
        return;
    }
    
    // 根据命令处理
    switch (parsed_frame.command) {
        case CMD_PING:
            protocol_handle_ping(&parsed_frame);
            break;
            
        case CMD_GET_VERSION:
            protocol_handle_get_version(&parsed_frame);
            break;
            
        case CMD_GET_STATUS:
            protocol_handle_get_status(&parsed_frame);
            break;
            
        case CMD_SET_LED:
            protocol_handle_set_led(&parsed_frame);
            break;
            
        case CMD_GET_ADC:
            protocol_handle_get_adc(&parsed_frame);
            break;
            
        default:
            // 未知命令
            protocol_send_error_response(ERROR_INVALID_CMD);
            break;
    }
    
    // 更新统计
    protocol_parser.frames_processed++;
}

// 解析帧
bool protocol_parse_frame(uint8_t *frame, uint16_t length, 
                         protocol_frame_t *parsed) {
    if (length < MIN_FRAME_SIZE) {
        return false;
    }
    
    // 验证起始符和结束符
    if (frame[0] != FRAME_START || frame[length - 1] != FRAME_END) {
        return false;
    }
    
    // 提取长度
    uint8_t frame_length = frame[1];
    
    // 验证长度是否匹配
    if (frame_length + 2 != length) {  // +2是起始符和结束符
        return false;
    }
    
    // 提取命令
    parsed->command = frame[2];
    
    // 计算数据长度
    // 总长度 = 命令(1) + 数据(N) + CRC(2)
    // 所以数据长度 = frame_length - 3
    parsed->data_length = frame_length - 3;
    
    // 提取数据
    if (parsed->data_length > 0) {
        parsed->data = &frame[3];
    } else {
        parsed->data = NULL;
    }
    
    // 提取CRC(帧的最后两个字节,在结束符之前)
    parsed->crc = (frame[length - 3] << 8) | frame[length - 2];
    
    return true;
}

// 处理PING命令
void protocol_handle_ping(protocol_frame_t *frame) {
    // 构建响应
    uint8_t response[MAX_FRAME_SIZE];
    uint16_t response_length;
    
    // 响应数据:时间戳
    uint32_t timestamp = get_system_tick();
    uint8_t data[4];
    data[0] = (timestamp >> 24) & 0xFF;
    data[1] = (timestamp >> 16) & 0xFF;
    data[2] = (timestamp >> 8) & 0xFF;
    data[3] = timestamp & 0xFF;
    
    // 构建响应帧
    response_length = protocol_build_response(response, 
                                             CMD_PING, 
                                             RESPONSE_OK,
                                             data, 4);
    
    // 发送响应
    uart_send_buffer(response, response_length);
}

// 处理获取版本命令
void protocol_handle_get_version(protocol_frame_t *frame) {
    uint8_t response[MAX_FRAME_SIZE];
    uint16_t response_length;
    
    // 版本信息
    uint8_t version_data[] = {
        1,  // 主版本
        0,  // 次版本
        0   // 修订版本
    };
    
    response_length = protocol_build_response(response,
                                             CMD_GET_VERSION,
                                             RESPONSE_OK,
                                             version_data, 3);
    
    uart_send_buffer(response, response_length);
}

// 处理设置LED命令
void protocol_handle_set_led(protocol_frame_t *frame) {
    if (frame->data_length < 2) {
        protocol_send_error_response(ERROR_INVALID_DATA);
        return;
    }
    
    uint8_t led_id = frame->data[0];
    uint8_t led_state = frame->data[1];
    
    // 控制LED(这里以PC13为例)
    if (led_id == 0) {
        if (led_state) {
            GPIOC->BSRR = GPIO_BSRR_BR13;  // 点亮
        } else {
            GPIOC->BSRR = GPIO_BSRR_BS13;  // 熄灭
        }
        
        // 发送成功响应
        uint8_t response[MAX_FRAME_SIZE];
        uint16_t response_length;
        uint8_t response_data[] = {led_id, led_state};
        
        response_length = protocol_build_response(response,
                                                 CMD_SET_LED,
                                                 RESPONSE_OK,
                                                 response_data, 2);
        
        uart_send_buffer(response, response_length);
    } else {
        protocol_send_error_response(ERROR_INVALID_DATA);
    }
}

// 处理获取ADC命令
void protocol_handle_get_adc(protocol_frame_t *frame) {
    // 读取ADC值(假设使用ADC1通道0,PA0)
    // 这里需要根据实际硬件配置ADC
    
    // 模拟读取ADC值
    uint16_t adc_value = 1234;  // 示例值
    
    // 构建响应
    uint8_t response[MAX_FRAME_SIZE];
    uint16_t response_length;
    uint8_t adc_data[2];
    
    adc_data[0] = (adc_value >> 8) & 0xFF;
    adc_data[1] = adc_value & 0xFF;
    
    response_length = protocol_build_response(response,
                                             CMD_GET_ADC,
                                             RESPONSE_OK,
                                             adc_data, 2);
    
    uart_send_buffer(response, response_length);
}

// 构建响应帧
uint16_t protocol_build_response(uint8_t *buffer, uint8_t command,
                                uint8_t status, const uint8_t *data,
                                uint16_t data_length) {
    uint16_t index = 0;
    
    // 起始符
    buffer[index++] = FRAME_START;
    
    // 长度字段(命令1 + 状态1 + 数据N + CRC2)
    uint8_t length = 1 + 1 + data_length + 2;
    buffer[index++] = length;
    
    // 命令(原命令)
    buffer[index++] = command;
    
    // 状态
    buffer[index++] = status;
    
    // 数据
    if (data_length > 0) {
        for (uint16_t i = 0; i < data_length; i++) {
            buffer[index++] = data[i];
        }
    }
    
    // 计算CRC(从长度字段开始到数据结束)
    uint16_t crc = 0xFFFF;
    for (uint16_t i = 1; i < index; i++) {  // 从长度字段开始
        crc = crc16_update(crc, buffer[i]);
    }
    
    // CRC(低字节在前)
    buffer[index++] = crc & 0xFF;
    buffer[index++] = crc >> 8;
    
    // 结束符
    buffer[index++] = FRAME_END;
    
    return index;
}

// 发送错误响应
void protocol_send_error_response(uint8_t error_code) {
    uint8_t response[MAX_FRAME_SIZE];
    uint16_t response_length;
    
    // 错误响应使用特殊命令码(原命令+0x80)
    // 这里简化处理,只发送错误码
    
    uint8_t error_data[] = {error_code};
    response_length = protocol_build_response(response,
                                             0x00,  // 通用错误命令
                                             RESPONSE_ERROR,
                                             error_data, 1);
    
    uart_send_buffer(response, response_length);
}

第四部分:完整项目整合

4.1 主程序实现

c

复制代码
// main.c - 主程序(整合所有模块)
#include "stm32f1xx.h"
#include "uart_interrupt.h"
#include "protocol_handler.h"
#include "crc16.h"
#include "queue_enhanced.h"

// 系统状态
typedef struct {
    uint32_t system_uptime;      // 系统运行时间(毫秒)
    uint8_t system_status;       // 系统状态
    uint32_t protocol_errors;    // 协议错误计数
    uint32_t uart_errors;        // UART错误计数
    bool led_state;              // LED状态
    uint16_t adc_value;          // ADC值
} system_state_t;

// 全局变量
static system_state_t system_state;
static enhanced_queue_t uart_rx_queue;
static uint8_t uart_rx_buffer[256];

// 系统时钟(SysTick)中断,用于计时
volatile uint32_t system_tick = 0;

void SysTick_Handler(void) {
    system_tick++;
}

// 获取系统时间(毫秒)
uint32_t get_system_tick(void) {
    return system_tick;
}

// 系统初始化
void system_init(void) {
    // 1. 配置系统时钟(使用内部8MHz时钟,倍频到72MHz)
    // 这里简化,实际需要配置时钟树
    
    // 2. 配置SysTick定时器(1ms中断)
    SysTick_Config(SystemCoreClock / 1000);
    
    // 3. 初始化LED GPIO(PC13)
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
    GPIOC->CRH |= GPIO_CRH_MODE13_1;  // 输出模式,最大速度2MHz
    
    // 4. 初始化ADC(PA0)
    // 这里简化,实际需要配置ADC
    
    // 5. 初始化系统状态
    system_state.system_uptime = 0;
    system_state.system_status = 0;
    system_state.protocol_errors = 0;
    system_state.uart_errors = 0;
    system_state.led_state = false;
    system_state.adc_value = 0;
    
    // 6. 初始化UART和协议处理器
    enhanced_queue_init(&uart_rx_queue, uart_rx_buffer, 
                       sizeof(uart_rx_buffer), false);
    uart_interrupt_init(115200);
    protocol_handler_init();
    
    // 7. 启用全局中断
    __enable_irq();
}

// 主循环
int main(void) {
    // 系统初始化
    system_init();
    
    // 开机闪烁LED3次
    for (int i = 0; i < 3; i++) {
        GPIOC->BSRR = GPIO_BSRR_BR13;  // 点亮
        delay_ms(100);
        GPIOC->BSRR = GPIO_BSRR_BS13;  // 熄灭
        delay_ms(100);
    }
    
    // 主循环
    while (1) {
        // 1. 处理协议(消费者)
        protocol_process_task();
        
        // 2. 更新系统状态
        system_state.system_uptime = get_system_tick();
        
        // 3. 周期性读取ADC(如果需要)
        static uint32_t last_adc_read = 0;
        if (get_system_tick() - last_adc_read > 1000) {  // 每秒读取一次
            // 读取ADC值
            // system_state.adc_value = read_adc();
            last_adc_read = get_system_tick();
        }
        
        // 4. 系统监控
        static uint32_t last_status_report = 0;
        if (get_system_tick() - last_status_report > 5000) {  // 每5秒
            // 可以在这里发送系统状态报告
            last_status_report = get_system_tick();
        }
        
        // 5. 空闲任务(可以进入低功耗模式)
        // __WFI();  // 等待中断(进入低功耗)
    }
}

// 简单延时函数(实际项目中使用定时器)
void delay_ms(uint32_t ms) {
    uint32_t start = get_system_tick();
    while (get_system_tick() - start < ms) {
        // 空循环
    }
}

4.2 项目配置文件

c

复制代码
// config.h - 项目配置文件
#ifndef CONFIG_H
#define CONFIG_H

// 系统配置
#define SYSTEM_CLOCK_FREQ     72000000  // 72MHz
#define SYSTICK_FREQ          1000      // 1kHz (1ms)

// UART配置
#define UART_BAUDRATE         115200
#define UART_RX_BUFFER_SIZE   256
#define UART_TX_BUFFER_SIZE   256

// 协议配置
#define PROTOCOL_TIMEOUT_MS   1000      // 协议解析超时时间
#define MAX_FRAME_SIZE        128       // 最大帧长度
#define MIN_FRAME_SIZE        6         // 最小帧长度(起始1+长度1+命令1+CRC2+结束1)

// 帧定义
#define FRAME_START           0xAA
#define FRAME_END             0x55

// CRC配置
#define CRC16_INIT_VALUE      0xFFFF
#define CRC16_POLYNOMIAL      0x8005

// 队列配置
#define QUEUE_OVERWRITE       false     // 队列满时是否覆盖

// 调试配置
#define DEBUG_ENABLED         1
#define DEBUG_UART            1

#if DEBUG_ENABLED
    #define DEBUG_PRINT(...)  printf(__VA_ARGS__)
#else
    #define DEBUG_PRINT(...)
#endif

// 硬件引脚定义(STM32F103C8T6)
#define LED_PIN               GPIO_Pin_13
#define LED_PORT              GPIOC

#define UART_TX_PIN           GPIO_Pin_9
#define UART_RX_PIN           GPIO_Pin_10
#define UART_PORT             GPIOA
#define UART_PERIPH           USART1

#define ADC_PIN               GPIO_Pin_0
#define ADC_PORT              GPIOA
#define ADC_CHANNEL           ADC_Channel_0

#endif // CONFIG_H

4.3 Makefile构建脚本

makefile

复制代码
# Makefile - 项目构建脚本

# 工具链定义
PREFIX = arm-none-eabi-
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

# 项目名称
TARGET = protocol_project

# 编译目录
BUILD_DIR = build

# 源文件目录
C_SOURCES = \
src/main.c \
src/uart_simple.c \
src/uart_interrupt.c \
src/crc_simple.c \
src/crc16.c \
src/queue_simple.c \
src/queue_enhanced.c \
src/protocol_parser.c \
src/protocol_handler.c

# ASM源文件
ASM_SOURCES = \
startup_stm32f103xb.s

# 包含目录
C_INCLUDES = \
-Iinc \
-Idrivers/CMSIS/Device/ST/STM32F1xx/Include \
-Idrivers/CMSIS/Include \
-Idrivers/STM32F1xx_HAL_Driver/Inc

# 编译选项
MCU = -mcpu=cortex-m3 -mthumb
CFLAGS = $(MCU) $(C_INCLUDES) -Wall -fdata-sections -ffunction-sections
CFLAGS += -DSTM32F103xB -DUSE_HAL_DRIVER
CFLAGS += -Og -g3

# 链接选项
LDSCRIPT = STM32F103C8Tx_FLASH.ld
LIBDIR = 
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR)
LDFLAGS += -Wl,--gc-sections -static
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map

# 默认目标
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

# 目标文件列表
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))

# 编译规则
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
	$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
	$(AS) -c $(CFLAGS) $< -o $@

# 链接
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
	$(CC) $(OBJECTS) $(LDFLAGS) -o $@
	$(SZ) $@

# 生成Hex和Bin文件
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(HEX) $< $@
	
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
	$(BIN) $< $@
	
# 创建构建目录
$(BUILD_DIR):
	mkdir $@

# 清理
clean:
	rm -rf $(BUILD_DIR)

# 烧录(使用OpenOCD)
flash: $(BUILD_DIR)/$(TARGET).elf
	openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \
	-c "program $(BUILD_DIR)/$(TARGET).elf verify reset exit"

# 调试
debug: $(BUILD_DIR)/$(TARGET).elf
	arm-none-eabi-gdb $(BUILD_DIR)/$(TARGET).elf

.PHONY: all clean flash debug

第五部分:调试与测试

5.1 调试技巧

5.1.1 使用LED调试

c

复制代码
// debug_led.c - LED调试工具
#include "debug_led.h"

// LED调试状态
typedef enum {
    DEBUG_IDLE,          // 空闲
    DEBUG_RX_DATA,       // 收到数据
    DEBUG_TX_DATA,       // 发送数据
    DEBUG_CRC_ERROR,     // CRC错误
    DEBUG_FRAME_ERROR,   // 帧错误
    DEBUG_TIMEOUT        // 超时
} debug_state_t;

static debug_state_t debug_state = DEBUG_IDLE;
static uint32_t debug_timer = 0;

// LED调试初始化
void debug_led_init(void) {
    // 初始化调试LED(例如使用PC14)
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    GPIOC->CRH &= ~(GPIO_CRH_MODE14 | GPIO_CRH_CNF14);
    GPIOC->CRH |= GPIO_CRH_MODE14_1;  // 输出模式
}

// 设置调试状态
void debug_set_state(debug_state_t state) {
    debug_state = state;
    debug_timer = get_system_tick();
    
    // 根据状态控制LED
    switch (state) {
        case DEBUG_IDLE:
            // LED慢闪(1Hz)
            break;
        case DEBUG_RX_DATA:
            // 收到数据时闪烁一次
            GPIOC->BSRR = GPIO_BSRR_BR14;  // 点亮
            break;
        case DEBUG_TX_DATA:
            // 发送数据时闪烁两次
            for (int i = 0; i < 2; i++) {
                GPIOC->BSRR = GPIO_BSRR_BR14;
                delay_ms(50);
                GPIOC->BSRR = GPIO_BSRR_BS14;
                delay_ms(50);
            }
            break;
        case DEBUG_CRC_ERROR:
            // CRC错误时快速闪烁
            for (int i = 0; i < 5; i++) {
                GPIOC->BSRR = GPIO_BSRR_BR14;
                delay_ms(100);
                GPIOC->BSRR = GPIO_BSRR_BS14;
                delay_ms(100);
            }
            break;
        default:
            break;
    }
}

// 调试LED任务(在主循环中调用)
void debug_led_task(void) {
    uint32_t current_time = get_system_tick();
    
    switch (debug_state) {
        case DEBUG_IDLE:
            // 空闲状态:1Hz慢闪
            if (current_time - debug_timer > 1000) {
                GPIOC->ODR ^= GPIO_ODR_ODR14;  // 翻转LED
                debug_timer = current_time;
            }
            break;
            
        case DEBUG_RX_DATA:
            // 收到数据后,LED点亮500ms后熄灭
            if (current_time - debug_timer > 500) {
                GPIOC->BSRR = GPIO_BSRR_BS14;  // 熄灭
                debug_state = DEBUG_IDLE;
            }
            break;
            
        default:
            // 其他状态自动返回空闲
            if (current_time - debug_timer > 1000) {
                debug_state = DEBUG_IDLE;
            }
            break;
    }
}

// 通过LED显示二进制数据(调试用)
void debug_led_show_byte(uint8_t data) {
    // 使用多个LED显示字节的二进制形式
    // 例如:LED0-7分别对应bit0-7
    for (int i = 0; i < 8; i++) {
        if (data & (1 << i)) {
            // 点亮对应LED
            // 具体实现取决于硬件连接
        } else {
            // 熄灭对应LED
        }
    }
    delay_ms(1000);  // 显示1秒
}
5.1.2 使用串口打印调试信息

c

复制代码
// debug_uart.c - 串口调试工具
#include "debug_uart.h"

// 调试信息级别
typedef enum {
    DEBUG_LEVEL_NONE = 0,    // 无调试信息
    DEBUG_LEVEL_ERROR = 1,   // 错误信息
    DEBUG_LEVEL_WARN = 2,    // 警告信息
    DEBUG_LEVEL_INFO = 3,    // 一般信息
    DEBUG_LEVEL_DEBUG = 4,   // 调试信息
    DEBUG_LEVEL_VERBOSE = 5  // 详细信息
} debug_level_t;

static debug_level_t debug_level = DEBUG_LEVEL_INFO;

// 设置调试级别
void debug_set_level(debug_level_t level) {
    debug_level = level;
}

// 格式化打印(简化版)
void debug_printf(const char *format, ...) {
    // 简化实现,实际项目可能需要更完整的实现
    char buffer[128];
    va_list args;
    
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    // 发送到UART
    uart_send_string(buffer);
}

// 带级别的调试打印
void debug_print(debug_level_t level, const char *tag, const char *format, ...) {
    if (level > debug_level) {
        return;  // 低于当前调试级别,不打印
    }
    
    char buffer[256];
    va_list args;
    
    // 添加级别前缀
    const char *level_str;
    switch (level) {
        case DEBUG_LEVEL_ERROR:   level_str = "ERROR"; break;
        case DEBUG_LEVEL_WARN:    level_str = "WARN"; break;
        case DEBUG_LEVEL_INFO:    level_str = "INFO"; break;
        case DEBUG_LEVEL_DEBUG:   level_str = "DEBUG"; break;
        case DEBUG_LEVEL_VERBOSE: level_str = "VERBOSE"; break;
        default:                  level_str = "UNKNOWN"; break;
    }
    
    // 添加时间戳
    uint32_t timestamp = get_system_tick();
    
    // 格式化消息
    int len = snprintf(buffer, sizeof(buffer), "[%lu][%s][%s] ", 
                      timestamp, level_str, tag);
    
    if (len < sizeof(buffer)) {
        va_start(args, format);
        vsnprintf(buffer + len, sizeof(buffer) - len, format, args);
        va_end(args);
    }
    
    // 添加换行
    strcat(buffer, "\r\n");
    
    // 发送
    uart_send_string(buffer);
}

// 打印十六进制数据
void debug_hex_dump(const char *tag, const uint8_t *data, uint16_t length) {
    if (debug_level < DEBUG_LEVEL_DEBUG) {
        return;
    }
    
    char buffer[64];
    char hex_buffer[16 * 3 + 1];
    char ascii_buffer[16 + 1];
    
    for (uint16_t i = 0; i < length; i += 16) {
        // 每行显示16字节
        uint16_t line_length = (length - i) > 16 ? 16 : (length - i);
        
        // 生成十六进制字符串
        hex_buffer[0] = '\0';
        ascii_buffer[0] = '\0';
        
        for (uint16_t j = 0; j < line_length; j++) {
            // 十六进制部分
            uint8_t byte = data[i + j];
            char hex[4];
            snprintf(hex, sizeof(hex), "%02X ", byte);
            strcat(hex_buffer, hex);
            
            // ASCII部分
            if (byte >= 32 && byte <= 126) {
                ascii_buffer[j] = byte;
            } else {
                ascii_buffer[j] = '.';
            }
        }
        ascii_buffer[line_length] = '\0';
        
        // 补全十六进制部分
        for (uint16_t j = line_length; j < 16; j++) {
            strcat(hex_buffer, "   ");
        }
        
        // 打印
        snprintf(buffer, sizeof(buffer), "[%s] %04X: %s %s\r\n", 
                tag, i, hex_buffer, ascii_buffer);
        uart_send_string(buffer);
    }
}

// 打印队列状态
void debug_print_queue_stats(const char *tag, enhanced_queue_t *queue) {
    if (debug_level < DEBUG_LEVEL_DEBUG) {
        return;
    }
    
    char buffer[128];
    snprintf(buffer, sizeof(buffer), 
            "[%s] Queue: size=%u, count=%u, head=%u, tail=%u, usage=%.1f%%\r\n",
            tag, queue->size, queue->count, queue->head, queue->tail,
            (float)queue->count / (queue->size - 1) * 100.0f);
    uart_send_string(buffer);
}

// 打印协议解析器状态
void debug_print_parser_stats(const char *tag, protocol_parser_t *parser) {
    if (debug_level < DEBUG_LEVEL_INFO) {
        return;
    }
    
    char buffer[128];
    snprintf(buffer, sizeof(buffer),
            "[%s] Parser: state=%d, frames=%lu, errors=%lu (CRC:%lu, Timeout:%lu)\r\n",
            tag, parser->state, parser->frames_received,
            parser->crc_errors + parser->timeout_errors + parser->format_errors,
            parser->crc_errors, parser->timeout_errors);
    uart_send_string(buffer);
}

5.2 测试程序

5.2.1 单元测试

c

复制代码
// test_queue.c - 队列单元测试
#include "test_queue.h"

// 测试队列基本功能
bool test_queue_basic(void) {
    printf("=== Testing Queue Basic Functions ===\n");
    
    // 1. 初始化队列
    enhanced_queue_t queue;
    uint8_t buffer[10];
    
    if (!enhanced_queue_init(&queue, buffer, 10, false)) {
        printf("FAIL: Queue initialization failed\n");
        return false;
    }
    printf("PASS: Queue initialization\n");
    
    // 2. 测试空队列检查
    if (!queue_is_empty(&queue)) {
        printf("FAIL: New queue should be empty\n");
        return false;
    }
    printf("PASS: Empty queue check\n");
    
    // 3. 测试入队
    for (int i = 0; i < 5; i++) {
        if (!enhanced_queue_enqueue(&queue, i)) {
            printf("FAIL: Failed to enqueue %d\n", i);
            return false;
        }
    }
    printf("PASS: Enqueue 5 elements\n");
    
    // 4. 测试队列数量
    if (queue_count(&queue) != 5) {
        printf("FAIL: Queue count should be 5, got %u\n", queue_count(&queue));
        return false;
    }
    printf("PASS: Queue count check\n");
    
    // 5. 测试出队
    for (int i = 0; i < 5; i++) {
        uint8_t data;
        if (!enhanced_queue_dequeue(&queue, &data)) {
            printf("FAIL: Failed to dequeue\n");
            return false;
        }
        if (data != i) {
            printf("FAIL: Dequeued data mismatch: expected %d, got %d\n", i, data);
            return false;
        }
    }
    printf("PASS: Dequeue 5 elements\n");
    
    // 6. 测试队列再次为空
    if (!queue_is_empty(&queue)) {
        printf("FAIL: Queue should be empty after dequeuing all\n");
        return false;
    }
    printf("PASS: Queue empty after dequeuing all\n");
    
    // 7. 测试队列满
    for (int i = 0; i < 9; i++) {  // 最大容量是size-1=9
        if (!enhanced_queue_enqueue(&queue, i)) {
            printf("FAIL: Failed to enqueue when not full\n");
            return false;
        }
    }
    
    // 第10次入队应该失败(队列满)
    if (enhanced_queue_enqueue(&queue, 10)) {
        printf("FAIL: Should not be able to enqueue when full\n");
        return false;
    }
    printf("PASS: Queue full detection\n");
    
    printf("=== All Queue Tests PASSED ===\n\n");
    return true;
}

// 测试队列覆盖模式
bool test_queue_overwrite(void) {
    printf("=== Testing Queue Overwrite Mode ===\n");
    
    enhanced_queue_t queue;
    uint8_t buffer[5];  // 小队列,更容易测试覆盖
    
    enhanced_queue_init(&queue, buffer, 5, true);  // 启用覆盖
    
    // 填充队列
    for (int i = 0; i < 5; i++) {
        enhanced_queue_enqueue(&queue, i);
    }
    
    // 现在队列已满,再入队应该覆盖最旧的数据
    enhanced_queue_enqueue(&queue, 10);
    
    // 第一个元素应该是1(0被覆盖了)
    uint8_t data;
    enhanced_queue_dequeue(&queue, &data);
    if (data != 1) {
        printf("FAIL: Expected 1 after overwrite, got %d\n", data);
        return false;
    }
    
    printf("PASS: Queue overwrite test\n");
    return true;
}

// 运行所有队列测试
void run_all_queue_tests(void) {
    printf("Running Queue Tests...\n");
    
    int passed = 0;
    int total = 0;
    
    if (test_queue_basic()) passed++;
    total++;
    
    if (test_queue_overwrite()) passed++;
    total++;
    
    printf("\nQueue Tests Summary: %d/%d passed\n", passed, total);
}
5.2.2 CRC测试

c

复制代码
// test_crc.c - CRC测试
#include "test_crc.h"

// 测试CRC-16计算
bool test_crc16_calculation(void) {
    printf("=== Testing CRC-16 Calculation ===\n");
    
    // 测试用例1:空数据
    uint8_t empty_data[] = {};
    uint16_t crc1 = crc16_calculate(empty_data, 0);
    if (crc1 != 0xFFFF) {  // 初始值
        printf("FAIL: Empty data CRC should be 0xFFFF, got 0x%04X\n", crc1);
        return false;
    }
    printf("PASS: Empty data CRC\n");
    
    // 测试用例2:单个字节
    uint8_t single_byte[] = {0x01};
    uint16_t crc2 = crc16_calculate(single_byte, 1);
    // 预计算的值
    uint16_t expected_crc2 = 0xC0C1;  // 从表中查得
    if (crc2 != expected_crc2) {
        printf("FAIL: Single byte CRC mismatch: expected 0x%04X, got 0x%04X\n", 
               expected_crc2, crc2);
        return false;
    }
    printf("PASS: Single byte CRC\n");
    
    // 测试用例3:字符串 "123456789"
    uint8_t test_string[] = "123456789";
    uint16_t crc3 = crc16_calculate(test_string, 9);
    // 已知的CRC-16/CCITT值
    uint16_t expected_crc3 = 0x31C3;
    if (crc3 != expected_crc3) {
        printf("FAIL: String CRC mismatch: expected 0x%04X, got 0x%04X\n",
               expected_crc3, crc3);
        return false;
    }
    printf("PASS: String CRC\n");
    
    // 测试用例4:逐步计算
    uint16_t crc = crc16_init();
    for (int i = 0; i < 9; i++) {
        crc = crc16_update(crc, test_string[i]);
    }
    crc = crc16_final(crc);
    
    if (crc != expected_crc3) {
        printf("FAIL: Incremental CRC mismatch\n");
        return false;
    }
    printf("PASS: Incremental CRC calculation\n");
    
    printf("=== All CRC Tests PASSED ===\n\n");
    return true;
}

// 测试CRC验证
bool test_crc16_verification(void) {
    printf("=== Testing CRC-16 Verification ===\n");
    
    // 测试数据
    uint8_t data[] = {0x01, 0x02, 0x03, 0x04};
    
    // 生成带CRC的数据
    uint8_t buffer_with_crc[6];
    uint16_t length = crc16_append(buffer_with_crc, data, 4);
    
    if (length != 6) {
        printf("FAIL: CRC append returned wrong length: %u\n", length);
        return false;
    }
    
    // 验证应该通过
    if (!crc16_verify(buffer_with_crc, length)) {
        printf("FAIL: CRC verification should pass for valid data\n");
        return false;
    }
    printf("PASS: Valid CRC verification\n");
    
    // 修改数据,验证应该失败
    buffer_with_crc[2] = 0xFF;  // 修改一个字节
    
    if (crc16_verify(buffer_with_crc, length)) {
        printf("FAIL: CRC verification should fail for corrupted data\n");
        return false;
    }
    printf("PASS: Invalid CRC detection\n");
    
    printf("=== All Verification Tests PASSED ===\n\n");
    return true;
}
5.2.3 集成测试

c

复制代码
// test_integration.c - 集成测试
#include "test_integration.h"

// 模拟UART接收(用于测试)
static enhanced_queue_t test_rx_queue;
static uint8_t test_rx_buffer[256];

// 模拟发送(用于验证)
static enhanced_queue_t test_tx_queue;
static uint8_t test_tx_buffer[256];

// 测试数据生成器
void generate_test_frame(uint8_t *buffer, uint8_t command, 
                        const uint8_t *data, uint8_t data_length) {
    uint16_t index = 0;
    
    // 起始符
    buffer[index++] = FRAME_START;
    
    // 长度(命令1 + 数据N + CRC2)
    buffer[index++] = 1 + data_length + 2;
    
    // 命令
    buffer[index++] = command;
    
    // 数据
    if (data_length > 0) {
        for (int i = 0; i < data_length; i++) {
            buffer[index++] = data[i];
        }
    }
    
    // 计算CRC(从长度字段开始)
    uint16_t crc = 0xFFFF;
    for (int i = 1; i < index; i++) {
        crc = crc16_update(crc, buffer[i]);
    }
    
    // CRC
    buffer[index++] = crc & 0xFF;
    buffer[index++] = crc >> 8;
    
    // 结束符
    buffer[index++] = FRAME_END;
}

// 测试完整协议流程
bool test_protocol_integration(void) {
    printf("=== Testing Protocol Integration ===\n");
    
    // 初始化测试队列
    enhanced_queue_init(&test_rx_queue, test_rx_buffer, 256, false);
    enhanced_queue_init(&test_tx_queue, test_tx_buffer, 256, false);
    
    // 初始化协议解析器
    protocol_parser_t parser;
    parser_init(&parser, 1000);
    
    // 测试用例1:PING命令
    printf("Test 1: PING command...\n");
    
    // 生成PING命令帧
    uint8_t ping_frame[32];
    generate_test_frame(ping_frame, CMD_PING, NULL, 0);
    
    // 模拟接收(将帧数据放入队列)
    for (int i = 0; i < 7; i++) {  // PING帧长度是7字节
        enhanced_queue_enqueue(&test_rx_queue, ping_frame[i]);
    }
    
    // 处理接收到的数据
    uint8_t byte;
    while (enhanced_queue_dequeue(&test_rx_queue, &byte)) {
        parser_result_t result = parser_process_byte(&parser, byte);
        
        if (result.status == PARSER_COMPLETE) {
            printf("PASS: PING frame received and parsed\n");
            break;
        } else if (result.status == PARSER_ERROR) {
            printf("FAIL: PING frame parsing error: %d\n", result.error_code);
            return false;
        }
    }
    
    // 测试用例2:带数据的命令
    printf("Test 2: Command with data...\n");
    
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint8_t data_frame[32];
    generate_test_frame(data_frame, CMD_SEND_DATA, test_data, 3);
    
    // 重置解析器
    parser_reset(&parser);
    
    // 模拟接收
    for (int i = 0; i < 10; i++) {  // 3字节数据的帧长度是10字节
        enhanced_queue_enqueue(&test_rx_queue, data_frame[i]);
    }
    
    // 处理
    while (enhanced_queue_dequeue(&test_rx_queue, &byte)) {
        parser_result_t result = parser_process_byte(&parser, byte);
        
        if (result.status == PARSER_COMPLETE) {
            printf("PASS: Data frame received and parsed\n");
            break;
        } else if (result.status == PARSER_ERROR) {
            printf("FAIL: Data frame parsing error\n");
            return false;
        }
    }
    
    // 测试用例3:CRC错误检测
    printf("Test 3: CRC error detection...\n");
    
    uint8_t corrupted_frame[32];
    generate_test_frame(corrupted_frame, CMD_PING, NULL, 0);
    
    // 修改CRC字节,制造错误
    corrupted_frame[5] ^= 0x01;  // 修改CRC低字节
    
    parser_reset(&parser);
    
    for (int i = 0; i < 7; i++) {
        enhanced_queue_enqueue(&test_rx_queue, corrupted_frame[i]);
    }
    
    bool crc_error_detected = false;
    while (enhanced_queue_dequeue(&test_rx_queue, &byte)) {
        parser_result_t result = parser_process_byte(&parser, byte);
        
        if (result.status == PARSER_ERROR && 
            result.error_code == ERROR_CRC) {
            crc_error_detected = true;
            break;
        }
    }
    
    if (!crc_error_detected) {
        printf("FAIL: CRC error not detected\n");
        return false;
    }
    printf("PASS: CRC error detected\n");
    
    // 测试用例4:超时检测
    printf("Test 4: Timeout detection...\n");
    
    parser_reset(&parser);
    
    // 发送起始符
    parser_process_byte(&parser, FRAME_START);
    
    // 等待超过超时时间
    // 这里需要模拟时间流逝
    // 在实际测试中,可以调整系统时间或使用模拟的get_system_tick函数
    
    printf("SKIP: Timeout test requires time simulation\n");
    
    printf("=== Integration Tests PASSED ===\n\n");
    return true;
}

// 性能测试
void test_performance(void) {
    printf("=== Performance Testing ===\n");
    
    // 测试CRC计算性能
    uint8_t test_data[1024];
    for (int i = 0; i < sizeof(test_data); i++) {
        test_data[i] = i & 0xFF;
    }
    
    uint32_t start_time = get_system_tick();
    uint32_t iterations = 1000;
    
    for (uint32_t i = 0; i < iterations; i++) {
        uint16_t crc = crc16_calculate(test_data, sizeof(test_data));
        (void)crc;  // 避免未使用变量警告
    }
    
    uint32_t end_time = get_system_tick();
    uint32_t elapsed = end_time - start_time;
    
    printf("CRC-16 Performance:\n");
    printf("  Data size: %u bytes\n", sizeof(test_data));
    printf("  Iterations: %u\n", iterations);
    printf("  Total time: %lu ms\n", elapsed);
    printf("  Time per iteration: %.2f ms\n", (float)elapsed / iterations);
    printf("  Throughput: %.2f KB/s\n", 
           (float)(sizeof(test_data) * iterations) / elapsed);
    
    // 测试队列性能
    enhanced_queue_t queue;
    uint8_t queue_buffer[100];
    enhanced_queue_init(&queue, queue_buffer, 100, false);
    
    start_time = get_system_tick();
    iterations = 10000;
    
    for (uint32_t i = 0; i < iterations; i++) {
        enhanced_queue_enqueue(&queue, i & 0xFF);
        uint8_t data;
        enhanced_queue_dequeue(&queue, &data);
    }
    
    end_time = get_system_tick();
    elapsed = end_time - start_time;
    
    printf("\nQueue Performance:\n");
    printf("  Iterations: %u\n", iterations);
    printf("  Total time: %lu ms\n", elapsed);
    printf("  Time per enqueue+dequeue: %.2f us\n", 
           (float)elapsed * 1000 / iterations);
    
    printf("\n=== Performance Tests Complete ===\n\n");
}

第六部分:实际应用案例

6.1 温度监控系统

c

复制代码
// temperature_monitor.c - 温度监控系统
#include "temperature_monitor.h"

// 温度传感器数据结构
typedef struct {
    uint8_t sensor_id;          // 传感器ID
    float temperature;          // 温度值(℃)
    float humidity;            // 湿度值(%)
    uint32_t last_read_time;   // 最后读取时间
    uint8_t status;            // 传感器状态
    uint8_t error_count;       // 错误计数
} temperature_sensor_t;

// 温度监控系统
typedef struct {
    temperature_sensor_t sensors[MAX_SENSORS];
    uint8_t sensor_count;
    uint32_t sample_interval;   // 采样间隔(毫秒)
    uint32_t report_interval;   // 报告间隔(毫秒)
    uint32_t last_sample_time;
    uint32_t last_report_time;
    
    // 报警阈值
    float temp_high_alarm;      // 高温报警阈值
    float temp_low_alarm;       // 低温报警阈值
    float hum_high_alarm;       // 高湿报警阈值
    
    // 统计信息
    uint32_t samples_taken;
    uint32_t reports_sent;
    uint32_t alarms_triggered;
    
    // 回调函数
    void (*alarm_callback)(uint8_t sensor_id, uint8_t alarm_type);
    void (*report_callback)(temperature_sensor_t *sensor);
} temperature_monitor_t;

// 初始化温度监控系统
void temp_monitor_init(temperature_monitor_t *monitor,
                      uint32_t sample_interval,
                      uint32_t report_interval) {
    memset(monitor, 0, sizeof(temperature_monitor_t));
    
    monitor->sample_interval = sample_interval;
    monitor->report_interval = report_interval;
    
    // 默认报警阈值
    monitor->temp_high_alarm = 40.0f;   // 40℃
    monitor->temp_low_alarm = 0.0f;     // 0℃
    monitor->hum_high_alarm = 80.0f;    // 80%
    
    monitor->last_sample_time = get_system_tick();
    monitor->last_report_time = get_system_tick();
}

// 添加温度传感器
bool temp_monitor_add_sensor(temperature_monitor_t *monitor,
                            uint8_t sensor_id) {
    if (monitor->sensor_count >= MAX_SENSORS) {
        return false;
    }
    
    temperature_sensor_t *sensor = &monitor->sensors[monitor->sensor_count];
    
    sensor->sensor_id = sensor_id;
    sensor->temperature = 0.0f;
    sensor->humidity = 0.0f;
    sensor->last_read_time = 0;
    sensor->status = SENSOR_STATUS_OK;
    sensor->error_count = 0;
    
    monitor->sensor_count++;
    
    return true;
}

// 读取传感器数据(模拟)
bool temp_monitor_read_sensor(temperature_monitor_t *monitor,
                             uint8_t sensor_id) {
    temperature_sensor_t *sensor = NULL;
    
    // 查找传感器
    for (int i = 0; i < monitor->sensor_count; i++) {
        if (monitor->sensors[i].sensor_id == sensor_id) {
            sensor = &monitor->sensors[i];
            break;
        }
    }
    
    if (!sensor) {
        return false;
    }
    
    // 模拟读取温度传感器(例如DHT11、DS18B20)
    // 实际项目中这里会调用具体的传感器驱动
    
    // 模拟温度值:20.0℃ ± 5℃
    float temperature = 20.0f + (rand() % 100) / 10.0f - 5.0f;
    
    // 模拟湿度值:50% ± 20%
    float humidity = 50.0f + (rand() % 400) / 10.0f - 20.0f;
    
    // 模拟传感器故障(1%概率)
    if ((rand() % 100) == 0) {
        sensor->status = SENSOR_STATUS_ERROR;
        sensor->error_count++;
        return false;
    }
    
    // 更新传感器数据
    sensor->temperature = temperature;
    sensor->humidity = humidity;
    sensor->last_read_time = get_system_tick();
    sensor->status = SENSOR_STATUS_OK;
    
    monitor->samples_taken++;
    
    return true;
}

// 检查报警条件
void temp_monitor_check_alarms(temperature_monitor_t *monitor,
                              uint8_t sensor_id) {
    temperature_sensor_t *sensor = NULL;
    
    for (int i = 0; i < monitor->sensor_count; i++) {
        if (monitor->sensors[i].sensor_id == sensor_id) {
            sensor = &monitor->sensors[i];
            break;
        }
    }
    
    if (!sensor || sensor->status != SENSOR_STATUS_OK) {
        return;
    }
    
    // 检查温度报警
    if (sensor->temperature > monitor->temp_high_alarm) {
        if (monitor->alarm_callback) {
            monitor->alarm_callback(sensor_id, ALARM_TEMP_HIGH);
        }
        monitor->alarms_triggered++;
    }
    
    if (sensor->temperature < monitor->temp_low_alarm) {
        if (monitor->alarm_callback) {
            monitor->alarm_callback(sensor_id, ALARM_TEMP_LOW);
        }
        monitor->alarms_triggered++;
    }
    
    // 检查湿度报警
    if (sensor->humidity > monitor->hum_high_alarm) {
        if (monitor->alarm_callback) {
            monitor->alarm_callback(sensor_id, ALARM_HUM_HIGH);
        }
        monitor->alarms_triggered++;
    }
}

// 温度监控任务(在主循环中调用)
void temp_monitor_task(temperature_monitor_t *monitor) {
    uint32_t current_time = get_system_tick();
    
    // 检查是否到达采样时间
    if (current_time - monitor->last_sample_time >= monitor->sample_interval) {
        // 读取所有传感器
        for (int i = 0; i < monitor->sensor_count; i++) {
            uint8_t sensor_id = monitor->sensors[i].sensor_id;
            
            if (temp_monitor_read_sensor(monitor, sensor_id)) {
                // 检查报警
                temp_monitor_check_alarms(monitor, sensor_id);
                
                // 调用报告回调(如果有)
                if (monitor->report_callback) {
                    monitor->report_callback(&monitor->sensors[i]);
                }
            }
        }
        
        monitor->last_sample_time = current_time;
    }
    
    // 检查是否到达报告时间
    if (current_time - monitor->last_report_time >= monitor->report_interval) {
        // 发送报告(通过协议)
        temp_monitor_send_report(monitor);
        
        monitor->last_report_time = current_time;
    }
}

// 发送温度报告
void temp_monitor_send_report(temperature_monitor_t *monitor) {
    // 构建报告数据
    uint8_t report_data[64];
    uint16_t data_index = 0;
    
    // 报告头
    report_data[data_index++] = monitor->sensor_count;
    report_data[data_index++] = (monitor->alarms_triggered >> 24) & 0xFF;
    report_data[data_index++] = (monitor->alarms_triggered >> 16) & 0xFF;
    report_data[data_index++] = (monitor->alarms_triggered >> 8) & 0xFF;
    report_data[data_index++] = monitor->alarms_triggered & 0xFF;
    
    // 每个传感器的数据
    for (int i = 0; i < monitor->sensor_count; i++) {
        temperature_sensor_t *sensor = &monitor->sensors[i];
        
        // 传感器ID
        report_data[data_index++] = sensor->sensor_id;
        
        // 温度(16位整数,放大10倍)
        int16_t temp_int = (int16_t)(sensor->temperature * 10.0f);
        report_data[data_index++] = (temp_int >> 8) & 0xFF;
        report_data[data_index++] = temp_int & 0xFF;
        
        // 湿度(16位整数,放大10倍)
        int16_t hum_int = (int16_t)(sensor->humidity * 10.0f);
        report_data[data_index++] = (hum_int >> 8) & 0xFF;
        report_data[data_index++] = hum_int & 0xFF;
        
        // 状态
        report_data[data_index++] = sensor->status;
        
        // 只发送前几个传感器(防止数据包太大)
        if (data_index > 50) {
            break;
        }
    }
    
    // 通过协议发送报告
    uint8_t frame[MAX_FRAME_SIZE];
    uint16_t frame_length = protocol_build_response(frame,
                                                   CMD_SEND_DATA,
                                                   RESPONSE_OK,
                                                   report_data,
                                                   data_index);
    
    uart_send_buffer(frame, frame_length);
    
    monitor->reports_sent++;
}

// 处理温度控制命令
void temp_monitor_handle_command(temperature_monitor_t *monitor,
                                uint8_t command, uint8_t *data,
                                uint16_t data_length) {
    switch (command) {
        case CMD_GET_TEMPERATURE:
            // 获取温度
            temp_monitor_send_report(monitor);
            break;
            
        case CMD_SET_ALARM_THRESHOLD:
            // 设置报警阈值
            if (data_length >= 6) {
                uint8_t alarm_type = data[0];
                uint16_t threshold = (data[1] << 8) | data[2];
                float threshold_float = threshold / 10.0f;
                
                switch (alarm_type) {
                    case ALARM_TEMP_HIGH:
                        monitor->temp_high_alarm = threshold_float;
                        break;
                    case ALARM_TEMP_LOW:
                        monitor->temp_low_alarm = threshold_float;
                        break;
                    case ALARM_HUM_HIGH:
                        monitor->hum_high_alarm = threshold_float;
                        break;
                }
            }
            break;
            
        case CMD_GET_ALARM_THRESHOLD:
            // 获取报警阈值
            temp_monitor_send_thresholds(monitor);
            break;
    }
}

// 发送报警阈值
void temp_monitor_send_thresholds(temperature_monitor_t *monitor) {
    uint8_t threshold_data[12];
    uint16_t data_index = 0;
    
    // 高温报警阈值
    uint16_t temp_high = (uint16_t)(monitor->temp_high_alarm * 10.0f);
    threshold_data[data_index++] = (temp_high >> 8) & 0xFF;
    threshold_data[data_index++] = temp_high & 0xFF;
    
    // 低温报警阈值
    uint16_t temp_low = (uint16_t)(monitor->temp_low_alarm * 10.0f);
    threshold_data[data_index++] = (temp_low >> 8) & 0xFF;
    threshold_data[data_index++] = temp_low & 0xFF;
    
    // 高湿报警阈值
    uint16_t hum_high = (uint16_t)(monitor->hum_high_alarm * 10.0f);
    threshold_data[data_index++] = (hum_high >> 8) & 0xFF;
    threshold_data[data_index++] = hum_high & 0xFF;
    
    // 发送
    uint8_t frame[MAX_FRAME_SIZE];
    uint16_t frame_length = protocol_build_response(frame,
                                                   CMD_GET_ALARM_THRESHOLD,
                                                   RESPONSE_OK,
                                                   threshold_data,
                                                   data_index);
    
    uart_send_buffer(frame, frame_length);
}

6.2 简单的数据记录仪

c

复制代码
// data_logger.c - 简单数据记录仪
#include "data_logger.h"

// 数据记录条目
typedef struct {
    uint32_t timestamp;      // 时间戳
    uint16_t data_type;      // 数据类型
    uint16_t data_value;     // 数据值
    uint8_t  data_quality;   // 数据质量(0-100%)
} data_log_entry_t;

// 数据记录器
typedef struct {
    data_log_entry_t *buffer;      // 缓冲区
    uint16_t buffer_size;          // 缓冲区大小
    uint16_t write_index;          // 写索引
    uint16_t read_index;           // 读索引
    uint16_t entry_count;          // 条目数量
    
    uint32_t log_interval;         // 记录间隔(毫秒)
    uint32_t last_log_time;        // 最后记录时间
    
    // 统计信息
    uint32_t total_entries;        // 总条目数
    uint32_t lost_entries;         // 丢失条目数(缓冲区满时)
    uint32_t read_requests;        // 读取请求数
    uint32_t transmitted_entries;  // 传输条目数
} data_logger_t;

// 初始化数据记录器
bool data_logger_init(data_logger_t *logger, 
                     data_log_entry_t *buffer,
                     uint16_t buffer_size,
                     uint32_t log_interval) {
    if (buffer == NULL || buffer_size == 0) {
        return false;
    }
    
    logger->buffer = buffer;
    logger->buffer_size = buffer_size;
    logger->write_index = 0;
    logger->read_index = 0;
    logger->entry_count = 0;
    
    logger->log_interval = log_interval;
    logger->last_log_time = get_system_tick();
    
    logger->total_entries = 0;
    logger->lost_entries = 0;
    logger->read_requests = 0;
    logger->transmitted_entries = 0;
    
    return true;
}

// 记录数据
bool data_logger_log(data_logger_t *logger,
                    uint16_t data_type,
                    uint16_t data_value,
                    uint8_t data_quality) {
    // 检查缓冲区是否已满
    if (logger->entry_count >= logger->buffer_size) {
        logger->lost_entries++;
        return false;
    }
    
    // 创建记录条目
    data_log_entry_t *entry = &logger->buffer[logger->write_index];
    
    entry->timestamp = get_system_tick();
    entry->data_type = data_type;
    entry->data_value = data_value;
    entry->data_quality = data_quality;
    
    // 更新索引和计数
    logger->write_index = (logger->write_index + 1) % logger->buffer_size;
    logger->entry_count++;
    logger->total_entries++;
    
    return true;
}

// 获取下一个记录条目
bool data_logger_get_next(data_logger_t *logger,
                         data_log_entry_t *entry) {
    // 检查是否有数据
    if (logger->entry_count == 0) {
        return false;
    }
    
    // 读取条目
    *entry = logger->buffer[logger->read_index];
    
    // 更新索引和计数
    logger->read_index = (logger->read_index + 1) % logger->buffer_size;
    logger->entry_count--;
    logger->read_requests++;
    
    return true;
}

// 数据记录任务
void data_logger_task(data_logger_t *logger) {
    uint32_t current_time = get_system_tick();
    
    // 检查是否到达记录时间
    if (current_time - logger->last_log_time >= logger->log_interval) {
        // 这里可以读取传感器数据并记录
        // 例如:
        // uint16_t adc_value = read_adc();
        // data_logger_log(logger, DATA_TYPE_ADC, adc_value, 100);
        
        logger->last_log_time = current_time;
    }
}

// 发送记录的数据
void data_logger_send_data(data_logger_t *logger, uint16_t max_entries) {
    uint8_t tx_buffer[MAX_FRAME_SIZE];
    uint16_t tx_index = 0;
    uint16_t entries_sent = 0;
    
    // 帧头
    tx_buffer[tx_index++] = FRAME_START;
    tx_buffer[tx_index++] = 0;  // 长度占位,后面填充
    
    // 命令
    tx_buffer[tx_index++] = CMD_SEND_DATA;
    
    // 发送尽可能多的条目
    while (entries_sent < max_entries) {
        data_log_entry_t entry;
        
        if (!data_logger_get_next(logger, &entry)) {
            break;  // 没有更多数据
        }
        
        // 检查是否有足够空间
        if (tx_index + 9 > MAX_FRAME_SIZE - 3) {  // -3为CRC和结束符
            // 帧已满,先发送这一帧
            break;
        }
        
        // 添加条目到帧
        // 时间戳
        tx_buffer[tx_index++] = (entry.timestamp >> 24) & 0xFF;
        tx_buffer[tx_index++] = (entry.timestamp >> 16) & 0xFF;
        tx_buffer[tx_index++] = (entry.timestamp >> 8) & 0xFF;
        tx_buffer[tx_index++] = entry.timestamp & 0xFF;
        
        // 数据类型
        tx_buffer[tx_index++] = (entry.data_type >> 8) & 0xFF;
        tx_buffer[tx_index++] = entry.data_type & 0xFF;
        
        // 数据值
        tx_buffer[tx_index++] = (entry.data_value >> 8) & 0xFF;
        tx_buffer[tx_index++] = entry.data_value & 0xFF;
        
        // 数据质量
        tx_buffer[tx_index++] = entry.data_quality;
        
        entries_sent++;
        logger->transmitted_entries++;
    }
    
    if (entries_sent > 0) {
        // 更新长度字段(命令1 + 数据 + CRC2)
        uint8_t data_length = 1 + (entries_sent * 9);
        tx_buffer[1] = data_length + 2;  // +CRC
        
        // 计算CRC(从长度字段开始到数据结束)
        uint16_t crc = 0xFFFF;
        for (int i = 1; i < tx_index; i++) {
            crc = crc16_update(crc, tx_buffer[i]);
        }
        
        // 添加CRC
        tx_buffer[tx_index++] = crc & 0xFF;
        tx_buffer[tx_index++] = crc >> 8;
        
        // 添加结束符
        tx_buffer[tx_index++] = FRAME_END;
        
        // 发送帧
        uart_send_buffer(tx_buffer, tx_index);
    }
}

// 获取记录器统计信息
data_logger_stats_t data_logger_get_stats(data_logger_t *logger) {
    data_logger_stats_t stats;
    
    stats.total_entries = logger->total_entries;
    stats.lost_entries = logger->lost_entries;
    stats.read_requests = logger->read_requests;
    stats.transmitted_entries = logger->transmitted_entries;
    stats.current_entries = logger->entry_count;
    stats.buffer_usage = (float)logger->entry_count / logger->buffer_size * 100.0f;
    
    // 计算丢失率
    if (logger->total_entries + logger->lost_entries > 0) {
        stats.loss_rate = (float)logger->lost_entries / 
                         (logger->total_entries + logger->lost_entries) * 100.0f;
    } else {
        stats.loss_rate = 0.0f;
    }
    
    return stats;
}

第七部分:进阶主题

7.1 优化技巧

7.1.1 内存优化

c

复制代码
// memory_optimization.c - 内存优化技巧
#include "memory_optimization.h"

// 技巧1:使用位域节省内存
typedef struct {
    uint8_t led_state : 1;      // 1位:LED状态
    uint8_t relay_state : 1;    // 1位:继电器状态
    uint8_t motor_state : 2;    // 2位:电机状态(00=停止,01=正转,10=反转,11=错误)
    uint8_t sensor_status : 4;  // 4位:传感器状态
} device_status_compact_t;      // 总共8位(1字节)

// 对比:普通结构体
typedef struct {
    uint8_t led_state;          // 1字节
    uint8_t relay_state;        // 1字节
    uint8_t motor_state;        // 1字节
    uint8_t sensor_status;      // 1字节
} device_status_normal_t;       // 总共4字节

// 技巧2:使用联合体节省内存
typedef union {
    struct {
        uint16_t temperature;   // 温度(放大10倍)
        uint16_t humidity;      // 湿度(放大10倍)
        uint16_t pressure;      // 压力(Pa)
    } sensor_data;
    
    uint8_t raw_data[6];        // 原始字节数组(用于传输)
} sensor_packet_t;              // 总共6字节

// 技巧3:使用编译时常量
#define BUFFER_SIZE 128  // 使用宏定义,编译器会优化

// 或者使用枚举
enum {
    TX_BUFFER_SIZE = 256,
    RX_BUFFER_SIZE = 256,
    MAX_FRAME_SIZE = 128
};

// 技巧4:使用const关键字
const uint16_t crc16_table[256] = { /* ... */ };  // 表放在Flash中,节省RAM

// 技巧5:内存池管理(避免内存碎片)
#define MEMORY_POOL_SIZE 1024
#define BLOCK_SIZE 32
#define NUM_BLOCKS (MEMORY_POOL_SIZE / BLOCK_SIZE)

typedef struct {
    uint8_t pool[MEMORY_POOL_SIZE];
    uint8_t used[NUM_BLOCKS];  // 使用位图
} memory_pool_t;

void* memory_pool_alloc(memory_pool_t *pool, uint16_t size) {
    uint16_t blocks_needed = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
    
    for (int i = 0; i <= NUM_BLOCKS - blocks_needed; i++) {
        bool free = true;
        
        // 检查连续的块是否空闲
        for (int j = 0; j < blocks_needed; j++) {
            if (pool->used[i + j]) {
                free = false;
                break;
            }
        }
        
        if (free) {
            // 标记为已使用
            for (int j = 0; j < blocks_needed; j++) {
                pool->used[i + j] = 1;
            }
            
            return &pool->pool[i * BLOCK_SIZE];
        }
    }
    
    return NULL;  // 内存不足
}

void memory_pool_free(memory_pool_t *pool, void *ptr, uint16_t size) {
    uint16_t block_index = ((uint8_t*)ptr - pool->pool) / BLOCK_SIZE;
    uint16_t blocks_used = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
    
    for (int i = 0; i < blocks_used; i++) {
        pool->used[block_index + i] = 0;
    }
}
7.1.2 性能优化

c

复制代码
// performance_optimization.c - 性能优化技巧
#include "performance_optimization.h"

// 技巧1:内联函数
static inline uint8_t queue_is_empty_fast(enhanced_queue_t *q) {
    return (q->head == q->tail);
}

// 技巧2:循环展开
uint16_t crc16_calculate_fast(const uint8_t *data, uint32_t length) {
    uint16_t crc = 0xFFFF;
    
    // 处理4字节对齐的部分
    uint32_t word_count = length / 4;
    const uint32_t *words = (const uint32_t *)data;
    
    for (uint32_t i = 0; i < word_count; i++) {
        uint32_t word = words[i];
        
        // 处理4个字节(手动展开)
        crc = (crc >> 8) ^ crc16_table[(crc ^ (word >> 24)) & 0xFF];
        crc = (crc >> 8) ^ crc16_table[(crc ^ (word >> 16)) & 0xFF];
        crc = (crc >> 8) ^ crc16_table[(crc ^ (word >> 8)) & 0xFF];
        crc = (crc >> 8) ^ crc16_table[(crc ^ word) & 0xFF];
    }
    
    // 处理剩余字节
    const uint8_t *bytes = (const uint8_t *)(words + word_count);
    uint32_t remaining = length % 4;
    
    for (uint32_t i = 0; i < remaining; i++) {
        crc = (crc >> 8) ^ crc16_table[(crc ^ bytes[i]) & 0xFF];
    }
    
    return crc;
}

// 技巧3:使用寄存器变量
void fast_memcpy(uint8_t *dest, const uint8_t *src, uint16_t length) {
    // 使用寄存器变量加速
    register uint8_t *d = dest;
    register const uint8_t *s = src;
    register uint16_t len = length;
    
    while (len--) {
        *d++ = *s++;
    }
}

// 技巧4:查表法替代复杂计算
// 例如:快速计算平方根(近似)
static const uint16_t sqrt_table[256] = {
    0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
    // ... 预计算的平方根表
};

uint16_t fast_sqrt(uint16_t x) {
    if (x < 256) {
        return sqrt_table[x];
    }
    // 对于更大的数,使用其他方法
    // ...
}

// 技巧5:减少函数调用开销
// 不好的做法:频繁调用小函数
void process_data_slow(uint8_t *data, uint16_t length) {
    for (int i = 0; i < length; i++) {
        uint8_t processed = process_byte(data[i]);  // 函数调用
        data[i] = processed;
    }
}

// 好的做法:内联处理
void process_data_fast(uint8_t *data, uint16_t length) {
    for (int i = 0; i < length; i++) {
        // 内联处理,避免函数调用
        uint8_t byte = data[i];
        byte = (byte >> 4) | (byte << 4);  // 字节反转示例
        byte ^= 0xAA;                      // 简单加密
        data[i] = byte;
    }
}

// 技巧6:使用DMA传输
void uart_dma_transmit(const uint8_t *data, uint16_t length) {
    // 配置DMA
    DMA1_Channel4->CCR &= ~DMA_CCR_EN;  // 禁用DMA
    
    // 设置源地址(内存)
    DMA1_Channel4->CMAR = (uint32_t)data;
    
    // 设置目标地址(UART数据寄存器)
    DMA1_Channel4->CPAR = (uint32_t)&USART1->DR;
    
    // 设置传输数量
    DMA1_Channel4->CNDTR = length;
    
    // 配置DMA:内存到外设,内存递增,8位数据
    DMA1_Channel4->CCR = DMA_CCR_MINC |    // 内存递增
                         DMA_CCR_DIR |     // 内存到外设
                         DMA_CCR_TCIE;     // 传输完成中断
    
    // 使能UART的DMA发送
    USART1->CR3 |= USART_CR3_DMAT;
    
    // 启动DMA
    DMA1_Channel4->CCR |= DMA_CCR_EN;
}

// DMA传输完成中断
void DMA1_Channel4_IRQHandler(void) {
    if (DMA1->ISR & DMA_ISR_TCIF4) {
        // 传输完成
        DMA1->IFCR |= DMA_IFCR_CTCIF4;  // 清除标志
        
        // 可以在这里处理传输完成事件
    }
}

7.2 错误处理与恢复

c

复制代码
// error_handling.c - 错误处理与恢复
#include "error_handling.h"

// 错误码定义
typedef enum {
    ERROR_NONE = 0,
    ERROR_UART_OVERFLOW,
    ERROR_UART_FRAMING,
    ERROR_UART_NOISE,
    ERROR_CRC_MISMATCH,
    ERROR_FRAME_TIMEOUT,
    ERROR_FRAME_TOO_LONG,
    ERROR_FRAME_TOO_SHORT,
    ERROR_INVALID_COMMAND,
    ERROR_INVALID_PARAMETER,
    ERROR_QUEUE_FULL,
    ERROR_QUEUE_EMPTY,
    ERROR_MEMORY_ALLOC,
    ERROR_SENSOR_READ,
    ERROR_SENSOR_CALIBRATION,
    ERROR_MAX
} error_code_t;

// 错误信息
static const char* error_messages[] = {
    "No error",
    "UART overflow error",
    "UART framing error",
    "UART noise error",
    "CRC mismatch",
    "Frame timeout",
    "Frame too long",
    "Frame too short",
    "Invalid command",
    "Invalid parameter",
    "Queue full",
    "Queue empty",
    "Memory allocation failed",
    "Sensor read error",
    "Sensor calibration error"
};

// 错误上下文
typedef struct {
    error_code_t last_error;
    uint32_t error_timestamp;
    uint32_t error_count[ERROR_MAX];
    uint32_t total_errors;
    
    // 错误处理回调
    void (*error_handler)(error_code_t error, const char* file, int line);
    void (*recovery_handler)(error_code_t error);
} error_context_t;

static error_context_t error_ctx;

// 初始化错误处理
void error_handler_init(void) {
    memset(&error_ctx, 0, sizeof(error_context_t));
}

// 报告错误
void error_report(error_code_t error, const char* file, int line) {
    // 记录错误
    error_ctx.last_error = error;
    error_ctx.error_timestamp = get_system_tick();
    error_ctx.error_count[error]++;
    error_ctx.total_errors++;
    
    // 调用错误处理回调
    if (error_ctx.error_handler) {
        error_ctx.error_handler(error, file, line);
    }
    
    // 根据错误类型采取恢复措施
    switch (error) {
        case ERROR_UART_OVERFLOW:
            // UART溢出,清空接收寄存器
            USART1->SR &= ~USART_SR_ORE;
            break;
            
        case ERROR_CRC_MISMATCH:
            // CRC错误,可以请求重传
            protocol_request_retransmission();
            break;
            
        case ERROR_FRAME_TIMEOUT:
            // 帧超时,重置协议解析器
            parser_reset(&protocol_parser);
            break;
            
        case ERROR_QUEUE_FULL:
            // 队列满,可以增加队列大小或丢弃旧数据
            // 这里选择丢弃最旧的数据
            if (uart_rx_queue.count > 0) {
                uint8_t dummy;
                enhanced_queue_dequeue(&uart_rx_queue, &dummy);
            }
            break;
            
        default:
            break;
    }
    
    // 调用恢复回调
    if (error_ctx.recovery_handler) {
        error_ctx.recovery_handler(error);
    }
}

// 错误报告宏
#define ERROR_REPORT(error) \
    do { \
        error_report((error), __FILE__, __LINE__); \
    } while (0)

// 带错误检查的函数调用
#define CHECK_ERROR(func) \
    do { \
        bool result = (func); \
        if (!result) { \
            ERROR_REPORT(ERROR_##func); \
            return false; \
        } \
    } while (0)

// 示例:带错误处理的队列操作
bool queue_enqueue_safe(enhanced_queue_t *q, uint8_t data) {
    if (!enhanced_queue_enqueue(q, data)) {
        ERROR_REPORT(ERROR_QUEUE_FULL);
        return false;
    }
    return true;
}

bool queue_dequeue_safe(enhanced_queue_t *q, uint8_t *data) {
    if (!enhanced_queue_dequeue(q, data)) {
        ERROR_REPORT(ERROR_QUEUE_EMPTY);
        return false;
    }
    return true;
}

// 错误统计
error_stats_t error_get_stats(void) {
    error_stats_t stats;
    
    stats.last_error = error_ctx.last_error;
    stats.last_error_time = error_ctx.error_timestamp;
    stats.total_errors = error_ctx.total_errors;
    
    // 计算错误率(基于时间)
    uint32_t uptime = get_system_tick() / 1000;  // 转换为秒
    if (uptime > 0) {
        stats.error_rate = (float)error_ctx.total_errors / uptime;
    } else {
        stats.error_rate = 0.0f;
    }
    
    // 找出最常见的错误
    stats.most_common_error = ERROR_NONE;
    uint32_t max_count = 0;
    
    for (int i = 0; i < ERROR_MAX; i++) {
        if (error_ctx.error_count[i] > max_count) {
            max_count = error_ctx.error_count[i];
            stats.most_common_error = i;
        }
    }
    
    return stats;
}

// 错误恢复策略
void error_recovery_strategy(error_code_t error) {
    static uint32_t consecutive_errors = 0;
    static uint32_t last_error_time = 0;
    
    uint32_t current_time = get_system_tick();
    uint32_t time_since_last_error = current_time - last_error_time;
    
    if (time_since_last_error > 1000) {  // 1秒内没有错误
        consecutive_errors = 0;  // 重置连续错误计数
    }
    
    consecutive_errors++;
    last_error_time = current_time;
    
    // 根据连续错误数量采取不同措施
    if (consecutive_errors >= 10) {
        // 连续10次错误,重启系统
        NVIC_SystemReset();
    } else if (consecutive_errors >= 5) {
        // 连续5次错误,降低波特率
        uart_change_baudrate(9600);
    } else if (consecutive_errors >= 3) {
        // 连续3次错误,增加重试间隔
        protocol_increase_retry_interval();
    }
}

// 看门狗定时器(防止系统死锁)
void watchdog_init(void) {
    // 启用独立看门狗
    IWDG->KR = 0xCCCC;  // 启用看门狗
    IWDG->KR = 0x5555;  // 允许访问PR和RLR寄存器
    
    // 设置预分频和重载值
    // 时钟频率 = 40kHz / 64 = 625Hz
    // 超时时间 = (重载值 + 1) / 625Hz
    IWDG->PR = IWDG_PR_PR_2;  // 64分频
    IWDG->RLR = 624;          // 约1秒超时
    
    // 等待寄存器更新
    while (IWDG->SR & IWDG_SR_PVU);
    while (IWDG->SR & IWDG_SR_RVU);
    
    // 启动看门狗
    IWDG->KR = 0xAAAA;  // 喂狗
}

// 喂狗函数(在主循环中定期调用)
void watchdog_feed(void) {
    IWDG->KR = 0xAAAA;
}

// 系统健康检查
bool system_health_check(void) {
    static uint32_t last_check_time = 0;
    uint32_t current_time = get_system_tick();
    
    // 每10秒检查一次
    if (current_time - last_check_time < 10000) {
        return true;
    }
    
    last_check_time = current_time;
    
    // 检查1:队列使用率
    float queue_usage = (float)uart_rx_queue.count / (uart_rx_queue.size - 1) * 100.0f;
    if (queue_usage > 90.0f) {
        ERROR_REPORT(ERROR_QUEUE_FULL);
        return false;
    }
    
    // 检查2:协议错误率
    parser_stats_t parser_stats = parser_get_stats(&protocol_parser);
    if (parser_stats.error_rate > 10.0f) {  // 错误率超过10%
        ERROR_REPORT(ERROR_CRC_MISMATCH);
        return false;
    }
    
    // 检查3:内存使用(如果使用了动态内存)
    // ...
    
    // 检查4:传感器状态
    // ...
    
    return true;
}

总结

本指南从入门工程师的角度,详细介绍了如何基于CRC校验的通信协议设计文档,使用生产者-消费者模式和队列等基础概念,编写C语言单片机代码。主要内容包括:

1. 基础概念理解

  • 生产者-消费者模式:解决数据生产与消费速度不匹配的问题

  • 队列(环形缓冲区):实现数据的缓冲和异步处理

  • CRC校验:保证数据传输的可靠性

2. 模块化实现

  • 队列模块:实现了简单队列和增强型队列

  • CRC模块:实现了CRC-8和CRC-16校验

  • UART模块:实现了轮询和中断两种方式的UART驱动

  • 协议模块:实现了完整的协议解析和处理

3. 完整项目整合

  • 展示了如何将各个模块整合成一个完整的系统

  • 提供了主程序框架和配置文件

  • 包含了Makefile构建脚本

4. 调试与测试

  • LED调试和串口调试工具

  • 单元测试和集成测试框架

  • 性能测试方法

5. 实际应用案例

  • 温度监控系统

  • 数据记录仪

6. 进阶主题

  • 内存和性能优化技巧

  • 错误处理与恢复策略

给入门工程师的建议:

  1. 从简单开始:先实现最基本的功能,再逐步增加复杂性

  2. 模块化编程:每个模块只负责一个功能,便于调试和重用

  3. 充分测试:编写测试代码,验证每个模块的正确性

  4. 理解原理:不要只复制代码,要理解每行代码的作用

  5. 利用调试工具:熟练使用调试器、逻辑分析仪等工具

  6. 文档和注释:写好代码注释,记录设计思路

  7. 持续学习:单片机开发涉及硬件和软件,需要不断学习

通过本指南的学习,你应该能够:

  • 理解通信协议的基本原理和实现方法

  • 掌握生产者-消费者模式在单片机中的应用

  • 实现可靠的CRC校验机制

  • 构建完整的单片机通信系统

  • 编写可维护、可扩展的单片机代码

记住,实践是最好的学习方式。尝试修改代码、添加新功能、解决遇到的问题,你会在这个过程中快速成长。祝你在单片机开发的道路上取得成功!

相关推荐
亓才孓2 小时前
【homework1】彩票奖金问题(苛刻条件变松弛条件需要避免条件重复)
java·开发语言
wbs_scy2 小时前
C++:unordered_map/unordered_set 使用指南(差异、性能与场景选择)
开发语言·c++·哈希算法
没有bug.的程序员2 小时前
微服务网关:从“必选项”到“思考题”的深度剖析
java·开发语言·网络·jvm·微服务·云原生·架构
csbysj20202 小时前
Python3 urllib 使用指南
开发语言
小此方2 小时前
Re: ゼロから学ぶ C++ 入門(八)类和对象·第五篇:時間计算器
开发语言·c++
无限进步_2 小时前
C++ Vector 全解析:从使用到深入理解
开发语言·c++·ide·windows·git·github·visual studio
秋邱2 小时前
Java数组与二维数组:创建、初始化、遍历与实操案例全解析
java·开发语言
wangxingps2 小时前
phpmyadmin版本对应的各php版本
服务器·开发语言·php
独自破碎E2 小时前
消息队列如何处理重复消息?
java·开发语言·rocketmq