大神论坛

找回密码
快速注册
查看: 352 | 回复: 0

[原创] ModBus数据CRC计算小工具

主题

帖子

0

积分

初入江湖

UID
682
积分
0
精华
威望
0 点
违规
大神币
68 枚
注册时间
2023-10-14 10:55
发表于 2023-12-30 22:46
本帖最后由 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;
}



返回顶部