1. CRC 循环冗余校验在线计算器
http://www.ip33.com/crc.html
2. 代码
uint16_t CRC16_ModBus(const uint8_t *data, uint16_t length)
{
const uint16_t POLY = 0xA001;
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++)
{
crc ^= data[i];
for (uint16_t j = 0; j < 8; j++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= POLY;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
3. 主函数调用
int main(void)
{
u8 USART_RX_BUF_2[7] = {0x06, 0x00, 0x06, 0x31, 0x02, 0x24, 0x01};
uint16_t ret = CRC16_ModBus(USART_RX_BUF_2, 7);
printf("ret:0x%x *******************\r\n", ret);
}
4. 串口日志
5. 串口中断服务函数
/*
* CRC-16/MODBUS (x16+x15+x2+1): USART_RX_BUF[2 ~ len - 2] -> USART_RX_BUF[len], USART_RX_BUF[len - 1]
* eg. receive data: 55 AA 06 00 06 31 02 24 01 FC 80
* 55 AA: header
* 06: data len (00 06 31 02 24 01)
* 01: 1Hz freq
* FC 80: CRC16-MODBUS calculate by data (00 06 31 02 24 01)
*/
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // determine if it is a receive interrupt, RXNE: RX not empty
{
uint8_t data = USART_ReceiveData(USART1);
if (rx_index == 0 && data != 0x55) // USART_RX_BUF[0] must be 0x55
{
return;
}
else if (rx_index == 1 && data != 0xAA) // USART_RX_BUF[1] must be 0xAA
{
rx_index = 0;
return;
}
else if (rx_index == 2) // USART_RX_BUF[2] is receive data length
{
if (data == 0 || data > (USART_REC_LEN - 5)) // data len is illegal
{
rx_index = 0;
return;
}
}
USART_RX_BUF[rx_index] = data; // save the received data to a buffer (USART_RX_BUF)
rx_index++;
if (rx_index == (USART_RX_BUF[2] + 5)) // received data len is expected, 5 = 0x55 + 0xAA + buff[2] + CRC(buf[len - 1], buf[len - 2])
{
// 进行 CRC 校验
uint16_t crc = 0xFFFF;
for (uint16_t i = 2; i < (rx_index - 2); i++)
{
crc ^= USART_RX_BUF[i];
for (uint16_t j = 0; j < 8; j++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
uint16_t crc_received = USART_RX_BUF[rx_index - 2] | (USART_RX_BUF[rx_index - 1] << 8);
if (crc_received != crc) // CRC 校验失败
{
rx_index = 0;
return;
}
// 处理接收到的数据
for (uint16_t i = 3; i < (rx_index - 2); i++)
{
// 进行相应的处理
}
rx_index = 0; // 重置数组下标,为下次接收做准备
}
}
}
6. 使用C 在线编程工具测试CRC接口 – 菜鸟工具
6.1 C 在线工具 | 菜鸟工具
https://c.runoob.com/compile/11/
6.2 在线编程测试CRC 接口
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// 06 00 06 31 02 33 01
uint8_t array[] = {0x06, 0x00, 0x06, 0x31, 0x02, 0x33, 0x01};
uint16_t ret;
uint16_t CRC16_ModBus(const uint8_t *data, uint16_t length)
{
const uint16_t POLY = 0xA001;
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++)
{
crc ^= data[i];
for (uint16_t j = 0; j < 8; j++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= POLY;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
int main()
{
uint8_t len = sizeof(array);
ret = CRC16_ModBus(array, 7);
printf("ret = 0x%x \n", ret);
return 0;
}