CRC16执行过程uint16_t calc_crc; calc_crc CRC16(firmware, 1024); if(calc_crc recv_crc) { printf(CRC OK\n); } else { printf(CRC ERROR\n); }通常最稳健的做法是完成一次bootloader进行两次CRC16校验从云端下载固件完成时防止UART 丢字节、WiFi 丢包写入 Flash 后再校验防止写入失败CRC源码// CRC16 查找表256个值 // 这个表是提前计算好的 CRC16 结果用来加快计算速度 // 如果不用表每一位都要计算速度很慢 uint16_t CRC16_Table[256] { ... }; // CRC16 计算函数 // data : 数据指针要计算CRC的数据 // len : 数据长度 uint16_t CRC16(uint8_t *data, uint32_t len) { // CRC 初始值一般 CRC16 常用 0xFFFF uint16_t crc 0xFFFF; // 遍历每一个字节的数据 while(len--) { // 计算查表索引 // crc 当前低8位 与 当前数据字节异或 uint8_t index crc ^ *data; // 更新CRC值 // 1 右移8位 // 2 再与查表得到的值异或 crc (crc 8) ^ CRC16_Table[index]; } // 返回最终CRC校验值 return crc; }XMODEM#include stdint.h #define SOH 0x01 #define EOT 0x04 #define ACK 0x06 #define NAK 0x15 #define CAN 0x18 #define PACKET_SIZE 128 extern uint8_t uart_getchar(void); extern void uart_putchar(uint8_t c); extern uint16_t crc16(uint8_t *buf, uint16_t len); /* 接收一个XMODEM包 */ int xmodem_receive(uint8_t *buffer) { uint8_t c; uint8_t block; uint8_t block_inv; uint8_t data[PACKET_SIZE]; uint16_t crc_recv; uint16_t crc_calc; while (1) { /* 通知PC开始发送 */ uart_putchar(C); c uart_getchar(); /* 收到数据包 */ if (c SOH) { block uart_getchar(); block_inv uart_getchar(); /* 校验块号 */ if ((block block_inv) ! 0xFF) { uart_putchar(NAK); continue; } /* 接收128字节数据 */ for (int i 0; i PACKET_SIZE; i) { data[i] uart_getchar(); } /* 接收CRC */ crc_recv uart_getchar() 8; crc_recv | uart_getchar(); /* 计算CRC */ crc_calc crc16(data, PACKET_SIZE); if (crc_calc ! crc_recv) { uart_putchar(NAK); continue; } /* 拷贝数据 */ for (int i 0; i PACKET_SIZE; i) { buffer[i] data[i]; } uart_putchar(ACK); return PACKET_SIZE; } /* 传输结束 */ else if (c EOT) { uart_putchar(ACK); return 0; } /* 取消 */ else if (c CAN) { return -1; } } }