【问题标题】:Need to convert data (byte value into hex and hex characters as ASCII characters)需要转换数据(字节值转换成十六进制和十六进制字符作为ASCII字符)
【发布时间】:2018-03-31 11:15:29
【问题描述】:

工作: 我正在从内存(EEPROM/FLASH 等)中读取一个字节,然后我想将此字节发送到计算机,而不是作为实际值,而是作为其十六进制值的 ascii 字符。 例如,我从内存中读取 160,即十六进制的 0xA0,现在我想发送这个数字不是 160,而是“A”和“0”(即 0x41 和 0x30), 为此,我在 MPLAB IDE 中使用这种类型的 c 代码,

    //Here is the code for Parity:
    uint8_t unAddParitytoByte(uint8_t unByte)
    { 
           uint8_t unNumberofOnes = 0;
           for(uint8_t unI = 0x80; unI ; unI>>=1)
           {
                 if((unByte & unI) != 0)
                {
                     unNumberofOnes++;
                }
          }
          if((unNumberofOnes%2) == 0)
          {
                  return unByte;
          }
          else
          {
               return (unByte|BIT7);
          }
    }
    void vSendByteToSoftware(uint8_t unDataByte)
    {
        uint8_t unTemp = 0, unHalfByte = 0;
        unTemp = (unDataByte >> 4) & 0x0F;
        unHalfByte = unReturnASCII(unTemp);
    /*Ignore vSerialTransmitCharacter(); as it transmit through uart and unAddParitytoByte(); to add 8th bit parity*/
        vSerialTransmitCharacter(unAddParitytoByte(unHalfByte)); 
        unBCCByte ^= unAddParitytoByte(unHalfByte);
        unTemp = unDataByte & 0x0F;
        unHalfByte = unReturnASCII(unTemp);
        vSerialTransmitCharacter(unAddParitytoByte(unHalfByte));
        unBCCByte ^= unAddParitytoByte(unHalfByte);
    }
    uint8_t unReturnASCII(uint8_t unNibble)
    {
         uint8_t unChar = 0;
         switch(unNibble)
         {
            case 0:
                 unChar = '0';
                 break;
            case 1:
                 unChar = '1';
                 break;
            case 2:
                 unChar = '2';
                 break;
            case 3:
                 unChar = '3';
                 break;
            case 4:
                 unChar = '4';
                 break;
            case 5:
                 unChar = '5';
                 break;
            case 6:
                 unChar = '6';
                 break;
            case 7:
                 unChar = '7';
                 break;
            case 8:
                 unChar = '8';
                 break;
            case 9:
                 unChar = '9';
                 break;
            case 10:
                 unChar = 'A';
                 break;
            case 11:
                 unChar = 'B';
                 break;
            case 12:
                unChar = 'C';
                break;
            case 13:
                unChar = 'D';
                break;
            case 14:
                unChar = 'E';
                break;
            case 15:
                unChar = 'F';
                break;
            default:
                break;
        }
        return unAddParitytoByte(unChar);
    }
    vSendByteToSoftware(unReadBytesfromTargetFlash());

我希望这是可以理解的。 问题: 我担心的是我有一个频率为 3.6864MHz 的控制器,我必须在近 1M 字节或更多字节上执行此操作,因此非常耗时。

我想知道对于每个字节是否有先进且最快的方法可以使我的操作非常快?

注意:(波特率为 115200,这非常快,我希望处理字节的速度而不是发送它们的时间。)

【问题讨论】:

  • IIRC,执行一条指令需要 PIC 四个时钟周期,因此如果您想以每秒 115200 个字符的速度发送,则每个字符的预算只有 8 条指令。这是相当严格的,特别是如果你正在计算奇偶校验和东西,你似乎这样做了(尽管你还没有发布那段特定的代码)。如果你想实现这一点,那么这可能是时候改用手写汇编了,而不是试图让编译器做正确的事情。
  • 为什么需要以这种形式发送?
  • 这是我试图与之交流的软件的需求..
  • 添加校验码
  • 如果我提高 Fosc 速度,它会起作用吗?它可能会减少一些时间,但我认为这不是一个很好的解决方案??

标签: c microcontroller pic data-conversion mplab


【解决方案1】:

每个半字节有 16 个可能的值,它们是连续的,从零开始。这是查找表的理想选择。

    uint8_t const ascii_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    void vSendByteToSoftware(uint8_t unDataByte)
    {
        uint8_t unTemp = 0, unHalfByte = 0;
        unTemp = (unDataByte >> 4) & 0x0F;
        unHalfByte = ascii_hex[unTemp];
    /*Ignore vSerialTransmitCharacter(); as it transmit through uart and unAddParitytoByte(); to add 8th bit parity*/
        vSerialTransmitCharacter(unAddParitytoByte(unHalfByte)); 
        unBCCByte ^= unAddParitytoByte(unHalfByte);
        unTemp = unDataByte & 0x0F;
        unHalfByte = ascii_hex[unTemp];
        vSerialTransmitCharacter(unAddParitytoByte(unHalfByte));
        unBCCByte ^= unAddParitytoByte(unHalfByte);
    }

更新: 由于您要传输的字符仅限于 16 个字符的集合,因此您可以预先计算这 16 个字符的奇偶校验,然后使用查找表来获取奇偶校验值。 (请仔细检查我是否正确完成了奇偶校验计算。)

uint8_t const ascii_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
uint8_t const ascii_hex_with_parity[16] = { 0x30, 0xB1, 0xB2, 0x33, 0xB4, 0x35, 0x36, 0xB7, 0xB8, 0x39, 0x41, 0x42, 0xC3, 0x44, 0xC5, 0xC6};

void vSendByteToSoftware(uint8_t unDataByte)
{
    uint8_t unTemp = 0, unHalfByte = 0;
    unTemp = (unDataByte >> 4) & 0x0F;
    unHalfByte = ascii_hex[unTemp];
/*Ignore vSerialTransmitCharacter(); as it transmit through uart and unAddParitytoByte(); to add 8th bit parity*/
    vSerialTransmitCharacter(unAddParitytoByte(unHalfByte)); 
    unBCCByte ^= ascii_hex_with_parity[unTemp];
    unTemp = unDataByte & 0x0F;
    unHalfByte = ascii_hex[unTemp];
    vSerialTransmitCharacter(unAddParitytoByte(unHalfByte));
    unBCCByte ^= ascii_hex_with_parity[unTemp];
}

【讨论】:

  • 这个查找表是否比使用 switch 调用函数更快?我认为它可能会节省调用时间和返回调用时间..uint8_t const ascii_hex[16] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  • 感谢您提供的单段代码..因为我是编程初学者,所以我一直在使用函数或开关来做这件事..您的代码确实简化了我的代码并且很容易理解..
  • 我相信这种查找表方法很可能比函数/切换方法更快。但要证明或量化它,您必须静态分析编译器生成的汇编指令或动态分析可执行代码。我也同意查找表简单易懂,这是一个额外的好处。 Profiling 是您在尝试加速代码时应该考虑的问题。分析可以帮助确定最有效的代码部分。
  • @BetaEngineer 您可以用另一个查找表替换您的奇偶校验函数。请参阅我的更新答案。
猜你喜欢
  • 2015-05-22
  • 2011-11-21
  • 2019-07-27
  • 2018-01-22
  • 1970-01-01
  • 2017-03-11
  • 2017-08-23
  • 2018-01-31
  • 2017-06-17
相关资源
最近更新 更多