串口字符串-HEX格式

2023-11-01

介绍

串口通信过程中 通常涉及一个数据的模拟过程以及数据发送过程, 一般来说, 我们会发送一串指令给下位机

68 05 00 84 01 02 03

例如这种, 我们明白 这是我们 将相应的字符转换成 hex 字符显示,用于表示ascii 字母的使用, 但是在程序中 我们可以直接使用 字符串表示我们想写入的字符, 容纳后转换之后 串口数据相应的ASCII码的过程,

下面 介绍一下常用的转换函数

数据格式

在我们的描述中,
首先给出一个 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9HJatAcd-1585144100245)(./串口字符串-HEX格式/ASCII.png)] 或者参考 Wikipedia ACII 的详细介绍
此处我们均使用 “abc123” 作为字符串在各个里面的显示来表示

  1. 字符串 string 指的是 “abc 123” 这种能用ascii 表示的 能够打出来的字符, 由于我们部分字符不能打出来,或者说是 不可显示字符,只用于控制指令, 存在缺陷 string str = “abc123”
  2. 字符串数组 char [] uchar[] 指 cpp 中 的一种数据, 存放的char 型或者 uchar 的字符, 我们可以使用 -128-127 或者 0-255的数字表示, 我们暂时均认为是 uchar 的数组 便于后续处理 uchar buffer= {97,98,99,49,50,51}
  3. 字符串指针 char* uchar * 是类型指针,一般指向的是字符串数据的首地址,由于我们处理过程中 很多函数 认为 0x00 ‘\0’ 是结束,所以处理的时候尽量传入 长度 uchar *buffer = buffer
  4. hex 字符串 将字符串数组里面的值转换成16进制的两位值,然后使用空格分割, 便于输入指令, 例如 string command=“61 62 63 31 32 33”

这种合适各有优劣, 比如我们在常用的 Modbus 控制中 使用 这种控制命令发送到下位机, 一般直接在串口输入, 然后使用 hex 发送即可, 但是如果我们测试过程中 需要将相应的数据按照两位的段, 填入txt 文本中, 每次读取一行数据, 然后将数据转换成 ascii 便能模拟 二进制流的输入输出

68 13 00 85 11 12 21 22 31 32 00 00 01 00 00 02 00 00 03 88 FF 01 02 03 04 05 0F

数据格式转换

1. uchar 数据和 char 字节数据的相互转换

char 类型的数据 -128-127, uchar 类型数据 0-255, 均是一个字节, char 类型的首位数据为符号位, 所以会存在从 127(0111 1111) +1 之后变成 -128(1000 0000) 的变换, 然后也会存在从-1(1111 1111) 到 0(0000 0000) 的变换, 详细可以搜索 char 溢出数据补码 的相关内容,

所以 uchar -char 的相互变换可以考虑成 两个部分
uchar 的 [0, 127] == char [0,127]
ucahr 的 [128, 255] == char [-128,-1]

// uchar 数据转换 char  >127   c1-256
char Utils_String::UChar2Char(uchar c1)
{
    return static_cast<char>(c1 > 127 ? c1 - 256 : c1);
}

// char 类型转换 uchar  <0 -- c1 +256
uchar Utils_String::Char2UChar(char c1)
{
    return static_cast<uchar>((c1 < 0 ? 256 + c1 : c1));
}

2. hex 与数字的相互转换

一般的 hex 表示的 16进制字符, 由于为了便于我们进行显示, 16进制由 0-9 a-f 供给16个字符依次表示 0-15 , 此处暂时不考虑 大写字母, 大写的A-F 等同于小写的a-f,

由于 uchar 类型的数据在 0-256之间, 正好可以表示成 2个16进制字符来进行表示, 使用前缀字符0x 表示16进制, 0o 表示8进制 0d 表示10进制 [0,255] ==[0x00,0xff]
我们建立一位字符0-f 与 0-15 之间的转换, 有两种转换方式, 一种就是if 判断进行强制转换, 另外一种 是使用 码表的排列进行一定 的优化处理

1位hex 与num 的相互转换代码
/**
 * @fn  int Utils_String::Hex2Num(const char ch)
 *
 * @brief   根据 各种情况 转换字母  一位字母 大于 48 的 +9  然后取后4位的值
 * *        
 *
 * @author  IRIS_Chen
 * @date    2019/12/16
 *
 * @param   ch  The ch
 *
 * @return  An int
 */
int Utils_String::Hex2Num(const char ch)
{
    //int res = (ch & '@' ? ch + 9 : ch) & 0x0F;
    //LInfo("ch:{},res:{}", ch, res);
    return (ch & '@' ? ch + 9 : ch) & 0x0F;
}

/**
 * @fn  char Utils_String::Num2Hex(int num, bool Up )
 *
 * @brief   将 0-15 转换成 0-F
 *
 * @author  IRIS_Chen
 * @date    2019/12/18
 *
 * @param   num Number of
 * @param   Up  True to up
 *
 * @return  The total number of 2 hexadecimal
 */
char Utils_String::Num2Hex(int num, bool Up /* = true */)
{
    char res;
    if (num >= 10 && num <= 15)
    {
        res = num - 10 + (Up ? 'A' : 'a');
    }
    else
        res = num + '0';
    return res;
}
1位hex 与num 的相互转换代码 2位hex 与 uchar相互转换
/**
 * @fn  uchar Utils_String::Hex2Uchar(const std::string & str)
 *
 * @brief   Hexadecimal 2 uchar 将两个 hex 字符 转换成 0-256
 *
 * @author  IRIS_Chen
 * @date    2019/12/18
 *
 * @param   str The string 默认初始两位字符  FF == 255   00 = 0  0D = 14
 *
 * @return  An uchar
 */
uchar Utils_String::Hex2Uchar(const std::string & str)
{
    uchar res = 0;
    for (const auto &s:str)
    {
        res = (res << 4) + Hex2Num(s);
    }
    return res;
}

/**
 * @fn  std::string Utils_String::Num2Hex(uchar num, bool Up)
 *
 * @brief   Number 2 hexadecimal  得到的结果只有 小写
 *
 * @author  IRIS_Chen
 * @date    2019/12/18
 *
 * @param   num Number of
 * @param   Up  True to up
 *
 * @return  The total number of 2 hexadecimal
 */
std::string Utils_String::Num2Hex(uchar num, bool Up)
{
    std::map<int, char> t_base = { 
    { 8,'o' },
    { 10,'d' },
    { 16,'x' } };
    if (!t_base.count(base))
        return "";

    // 使用 sprintf 格式化输出, 将数字 转换成相应的进制值
    std::string format = "%0" + std::to_string(width) + t_base.find(base)->second;
    char *buf = new char[20];
    sprintf(buf, format.c_str(), num);

    std::string res=std::string(buf);

    // 转换大小写
    return Up ? StringUpper(res) : StringLowwer (res);
}

3. 给定字符串转换成字符串数组

由于 原生的 string 存在字符转指针的转换
可以使用 原生的指针来处理

/**
 * @fn  const uchar * Utils_String::String2Uchar(const std::string & str)
 *
 * @brief   String 2 uchar
 *
 * @author  IRIS_Chen
 * @date    2019/12/16
 *
 * @param   str The string
 *
 * @return  Null if it fails, else a pointer to a const uchar
 */
const uchar * Utils_String::String2Uchar(const std::string & str)
{
    return (uchar*)str.c_str();
}
/**
 * @fn  std::string Utils_String::Uchar2String(const uchar * buffer)
 *
 * @brief   Uchar 2 string
 *
 * @author  IRIS_Chen
 * @date    2019/12/16
 *
 * @param   buffer  The buffer
 *
 * @return  A std::string
 */
std::string Utils_String::Uchar2String(const uchar * buffer)
{   
    std::string str = (char*)buffer;
    return str;
}

4. hex 字符串 转换 字符串数组

依次取两个字符, 转换成一个 ucahr 值 存入数据中即可

hex 字符串 与字符串数组的相互转换
/**
 * @fn  uchar * Utils_String::Hex2CharArr(uchar *&buffer, const std::string & str, bool flg_space)
 *
 * @brief   Hexadecimal 2 character array hex 字符串 转换成 数组
 *
 * @author  IRIS_Chen
 * @date    2019/12/18
 *
 * @param [in,out]  buffer      [in,out] If non-null, the buffer
 * @param           str         The string
 * @param           flg_space   True to flg space hex 是否使用空格分割
 *
 * @return  Null if it fails, else a pointer to an uchar
 */
uchar * Utils_String::Hex2CharArr(uchar *&buffer, const std::string & str, bool flg_space)
{
    // 出错 只有两个值 默认不符合 操作
    if (str.size() < 3)    return nullptr;
    // 默认够长 判断是否存在空格
    if (str[2] == ' ')   flg_space = true;

    int step = flg_space ? 3 : 2;

    buffer = new uchar[(str.size() + 1) / step +1 ];

    std::string str2 = "";

    for (int i = 0; i < static_cast<int>(str.size());)
    {
        uchar ch = Hex2Uchar(str.substr(static_cast<size_t>(i), 2));
        // 根据是否有空格选择 移动
        *(buffer + i/step) = ch;
        i += step;

        str2 += std::to_string((int)ch) + "-";
    }
    // LInfo("charArr:{}", str2);
    return buffer;
}

/**
 * @fn  std::string Utils_String::CharArr2Hex(uchar * buffer, int length, int flg_space)
 *
 * @brief   Character array 2 hexadecimal  数组 转换成 hex 字符
 *          * 将UCHAR 字符串依次转换成 string 字符串
 *
 * @author  IRIS_Chen
 * @date    2019/12/18
 *
 * @param [in,out]  buffer      If non-null, the buffer
 * @param           length      The length
 * @param           flg_space   The flg space
 *
 * @return  A std::string
 */
std::string Utils_String::CharArr2Hex(uchar * buffer, int length, int flg_space)
{
    std::string str = "";
    // 读取数组中所有字符
    for (int i = 0; i < length; i++)
    {
        str += Num2Hex(*buffer++);
        // 如果开启空格的话  每两个字符 之间加入一个空格 最后一个不加
        if (flg_space && i != length - 1)
            str += " ";
    }
    return str;
}

更多

大概就这么多常用的转换过程, 还存在一个 单独 数组转换 字符串的函数, 可以使用 sprintf 格式化输出, 或者使用 暴力循环取余得到最后的结果值

数字与字符串的转换 可多位 多进制
/**
 * @fn  std::string Utils_String::NumToString(int num, int width, int base)
 *
 * @brief   Number to string 整型数据 前补 0 占位符显示 进制 为 8 10 16 如果超过给出的宽度 原始宽度显示
 *
 * @author  IRIS_Chen
 * @date    2019/12/3
 *
 * @param   num     Number of
 * @param   width   The width
 * @param   base    The base
 *
 * @return  The total number of to string
 */
std::string Utils_String::NumToString(int num, int width, int base)
{
#if 0
    // 保证 存在进制 只考虑 2 8 , 10 16 进制
    static std::map<int, char> t_base = {
        { 2,'0' },
        { 8,'o' },
        { 10,'d' },
        { 16,'x' } };
    if (!t_base.count(base))
        return "";
    // 二进制 特殊处理
    if (base == 2)
    {
        std::string str_8 = NumToString(num, width, 8);
        //  设置8进制 转2进制码表, 转换之后 去除前缀0 即可
        static const std::vector<std::string> table = { "000","001","010","011","100","101","110","111" };

        std::string str_2 = "";
        for (auto s : str_8)
        {
            if(s =='0')
                continue;
            str_2 += table[s - '0'];
        }
        // 去掉前面所有的 0值 从1 开始
        int pos = static_cast<int>(str_2.find_first_of('1'));

        // #TODO(Schen00) 处理, 得到的长度小于width 的情况
        return pos == std::string::npos ?"":str_2.substr (pos);
    }

    std::string format = "%0" + std::to_string(width) + t_base.find(base)->second;

    char *buf = new char[20];
    sprintf(buf, format.c_str(), num);
    return std::string(buf);
#else
    std::string res = "";

    while (num)
    {
        res = base == 16 ? Num2Hex(num % base) : (num % base + '0') + res;
        num /= base;
    }

    // 不足位 补0  足位 不删除
    int cnt = width - res.size();
    while (cnt--)
    {
        res = '0' + res;
    }
    return res;
#endif
}

intf(buf, format.c_str(), num);
return std::string(buf);
#else
std::string res = “”;

while (num)
{
    res = base == 16 ? Num2Hex(num % base) : (num % base + '0') + res;
    num /= base;
}

// 不足位 补0  足位 不删除
int cnt = width - res.size();
while (cnt--)
{
    res = '0' + res;
}
return res;

#endif
}

</details>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

串口字符串-HEX格式 的相关文章

随机推荐

  • 10个程序员可以接私活的平台和一些建议,兼职必看

    今天为大家分享一些可以接私单的平台 相信大家学习编程未来是希望成为一个软件工程师或者码农 找到好的工作 有好的发展 但是在还没有找工作之前 大家可以通过一些平台接一些兼职 一来能够赚钱 在主页保持稳定的情况下能够发展自己的副业 二来通过接项
  • 实验 :OSPF综合应用场景

    R1 interface GigabitEthernet0 0 0 ip address 12 1 1 1 255 255 255 0 interface GigabitEthernet0 0 1 interface GigabitEthe
  • ROS仿真小车模型的搭建

    sample sai robot urdf
  • Linux 高可用(HA)集群之heartbeat基于crm进行资源管理详解

    大纲 一 环境准备 二 拓扑准备 三 前提条件 四 安装相关软件 五 配置 heartbeat crm 资源管理器 六 crm资源管理器 七 crm图形界面配置详解 八 高可用集群架构回顾 九 crm配置资源 十 crm资源约束 十一 cr
  • Hyperledger Fabric Java语言Gradle 工程 链码离线安装

    需求 hyperledger fabric 分布式账本 由于其本身的特性 目前主要应用于大型国企和银行 其环境的部署一般是与外部网络隔离的 如果采用docker的部署方式 docker镜像可以通过导入即可 但是在安装和实例化的时候需要下载相
  • Leetcode:单调栈系列

    本人总结的单调栈大概有三类 求右边第一个比该元素大 小 的元素 求左边第一个比该元素大 小 的元素 求两边比该元素大 小 的元素 前两类一般是中等难度的题 完成一次单调栈即可 最后一类是困难难度 需要完成两次单调栈 进一步地 1 求右边第一
  • 二十三种设计模式第二十四篇--访问者模式(完结撒花)

    在访问者模式 Visitor Pattern 中 我们使用了一个访问者类 它改变了元素类的执行算法 通过这种方式 元素的执行算法可以随着访问者改变而改变 这种类型的设计模式属于行为型模式 根据模式 元素对象已接受访问者对象 这样访问者对象就
  • 二、树模型(3)

    GBDT 特征筛选方法 https blog csdn net yangxudong article details 53899260 GBDT 用于分类 树形结构为什么不需要归一化 因为数值缩放不影响分裂点位置 对树模型的结构不造成影响
  • 【Verilog】二、Verilog基础语法

    文章目录 前言 一 简单的Verilog知识 1 1 Verilog端口定义 1 2 Verilog的标识符 1 3 Verilog的逻辑值 1 4 Verilog的数字进制 1 5 Verilog的数据类型 1 5 1 reg型 1 5
  • 吴恩达《深度学习专项》笔记(十二):目标检测与语义分割简介 (YOLO, U-Net)

    这节课中 我们要学习计算机视觉中最重要的任务之一 目标检测任务 我们会先认识目标定位和关键点检测这两个比较简单的任务 慢慢过度到目标检测任务 之后 我们会详细学习目标检测的经典算法YOLO 最后 我们会稍微认识一下语义分割任务及适用于此问题
  • 老猿Python部分代码样例

    专栏 Python基础教程目录 专栏 使用PyQt开发图形界面Python应用 专栏 PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 PyQt编程实战 通过eventFilter监视QScrollArea的widget 的P
  • Vue3 基础语法

    文章目录 1 创建Vue项目 1 1创建项目 1 2 初始项目 2 vue3 语法 2 1 复杂写法 2 2 简易写法 2 3 reactive 对象类型 2 4 ref 简单类型 2 5 computed 计算属性 2 6 watch 监
  • python并发编程学习笔记--初识多线程 day01

    请求网页信息 blog spider py import requests 生成列表 from bs4 import BeautifulSoup urls f http www cnblogs com p page f https www
  • AD20——批量快速放置元件管脚

    在使用Altium Designer 20创建元件库时 对于管脚较多的元件可采用批量放置的操作以节省时间 具体操作如下 1 首先放置第1个管脚 选中该管脚并Ctrl C将其复制 2 点击编辑 E gt 阵列式粘贴 Y 弹出如下界面 参数说明
  • android中的(singleLine)单行显示 none start middle

    http www cnblogs com firecode archive 2012 04 23 2466711 html 第一个button 什么都没写 后面省略号 android ellipsize none none就没有省略号了 a
  • QT5.12编译安装

    1 引言 QT是一个跨平台的编译软件 本文将介绍在linux内核操作系统下对于QT5 12的编译安装过程及QT编译程序的配置过程 2 编译安装 2 1 下载源码 推荐使用国内镜像网站下载 国内著名的几个 Qt 镜像网站 中国科学技术大学 h
  • 【ZJCPC2023 第20届 浙江省赛】赛后总结

    感叹 线下比赛环境挺不错的 可以白嫖杭师大一天的饭 还有传统的气球环节 看到别人AC了6道题手上抓着6个气球出考场就大受震撼 尤其是中学生的打星队 实际情况 由于本科和专科分开评奖 所以看起来二本那些落后的 没有教练的学生给人的刻板印象就是
  • 跟我一起写 Makefile(六)

    跟我一起写 Makefile 六 本文来自于CSDN 陈皓博主 网址http blog csdn net haoel article details 2891 详细内容请参考其经典文章 跟我一起写makefile 陈皓
  • 链表面试常见题目

    1 反转链表 头插法 2 合并两个有序链表 3 链表倒数第k个节点 连个节点一个先走 k步 然后两个一起走 走到第一个节点 next为null 4 从尾到头打印 链表 借助栈或者递归 5 复杂链表复制 1 借助map存储 O n 空间 2
  • 串口字符串-HEX格式

    介绍 串口通信过程中 通常涉及一个数据的模拟过程以及数据发送过程 一般来说 我们会发送一串指令给下位机 68 05 00 84 01 02 03 例如这种 我们明白 这是我们 将相应的字符转换成 hex 字符显示 用于表示ascii 字母的