本帖最后由 bant 于 2023-12-30 22:46 编辑
ModBus数据CRC计算小工具/* 20231230 */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <windows.h> #define INPUT_BUF_SIZE 1024 #define OUTPUT_BUF_SIZE (1024 + 1) void input_data(char *input); void deblank(char *str); uint8_t string_to_hex(char *str, uint8_t *out, uint16_t output_buf_size, uint16_t *outlen); uint16_t ModBusCRC16(uint8_t *data, uint16_t len); uint8_t modbus_data_calc(char *input, uint8_t *output, uint16_t output_buf_size, uint16_t *outlen); void output_data(uint8_t *output, uint16_t outlen); int main(void) { char input[INPUT_BUF_SIZE] = { 0 }; uint8_t output[OUTPUT_BUF_SIZE] = { 0 }; uint16_t outlen = 0; uint8_t ret; SetConsoleTitle("modbus_data_calc"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); printf("\t\t\t\tmodbus_data_calc\t\t\t\t\n"); printf(":02 03 04 00 EA FD C9\n"); printf("02 03 04 00 EA FD C9 68 01\n\n"); while(1) { printf(":"); input_data(input); ret = modbus_data_calc(input, output, sizeof(output)/sizeof(*output), &outlen); if(ret != 0) { printf("err:%X\n", ret); getchar(); return ret; } SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 6); printf("data length:%u\n", outlen); output_data(output, outlen); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); printf("\n-----------------------\n\n"); } return 0; } /* 输入字符串 input:输入buf指针 */ void input_data(char *input) { char ch; while ((ch = getchar()) != '\n') { *input = ch; ++input; } *input = '\0'; } /* 输出数据 output:数组指针 outlen:数组大小 */ void output_data(uint8_t *output, uint16_t outlen) { uint16_t i; for (i = 0; i < outlen; ++i) { printf("%02X ", output[i]); } } /* modbus_data_calc input:输入字符串buf指针 output:输出uin8_t类型数组buf指针 output_buf_size:输出uin8_t类型数组buf大小 outlen:最终结果数据长度 返回: ok(0) err(!0) */ uint8_t modbus_data_calc(char *input, uint8_t *output, uint16_t output_buf_size, uint16_t *outlen) { uint16_t crc16; uint16_t tmplen; uint8_t ret; if(input == NULL || output == NULL) { return 0xFF; } memset(output, 0, output_buf_size); //清空输出buf ret = string_to_hex(input, output, output_buf_size, &tmplen); //输入字符串转数字放入数组 if(ret != 0) { return ret; } crc16 = ModBusCRC16(output, tmplen); //计算CRC16 output[tmplen] = (uint8_t)crc16; //结果数组添加CRC16校验 output[tmplen+1] = (uint8_t)(crc16 >> 8); (*outlen) = tmplen + 2; //加2字节的CRC校验 return 0; } /* 计算CRC16校验 data:数据buf len:数据长度 返回 CRC16校验结果 */ uint16_t ModBusCRC16(uint8_t *data, uint16_t len) { uint16_t i, j, tmp, CRC16; CRC16 = 0xFFFF; // CRC寄存器初始值 for (i = 0; i < len; i++) { CRC16 ^= data[i]; for (j = 0; j < 8; j++) { tmp = (uint16_t)(CRC16 & 0x0001); CRC16 >>= 1; if (tmp == 1) { CRC16 ^= 0xA001; // 异或多项式 } } } return CRC16; } /* 删除字符串中的空格 str:字符串 返回:去除所有空格后的字符串 */ void deblank(char *str) { int i, j = 0; for (i = 0; str[i] != '\0'; i++) // 循环条件也可以写为 i<strlen(str) { if (str[i] != ' ') // 也可以写为:if(str[i]==' ') str[j++] = str[i]; // continue; } // str[j++]=str[i]; str[j] = '\0'; } /* 字符串转16进制数据 str:输入字符串 out:输出字符串 output_buf_size:输出buf大小 outlen:输出有效长度 返回: ok(0) err(!0) */ uint8_t string_to_hex(char *str, uint8_t *out, uint16_t output_buf_size, uint16_t *outlen) { char *p = str; char high = 0, low = 0; uint16_t tmplen = strlen(p), cnt = 0; deblank(str); // 去除字符串中所有的空格 tmplen = strlen(p); if(tmplen > output_buf_size) // 输入字符超过输出buf大小 { return 0xFE; } while (cnt < (tmplen / 2)) { high = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; low = (*(++p) > '9' && ((*p <= 'F') || (*p <= 'f'))) ? *(p)-48 - 7 : *(p)-48; out[cnt] = ((high & 0x0f) << 4 | (low & 0x0f)); p++; cnt++; } if (tmplen % 2 != 0) out[cnt] = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; if (outlen != NULL) *outlen = tmplen / 2 + tmplen % 2; //return tmplen / 2 + tmplen % 2; return 0; }
|