位移与阵列索引,更适合于32位MCU上的usart接口

时间:2019-02-20 01:42:02

标签: c embedded bit-shift usart

我有一个带有USART HAL的嵌入式项目。该USART一次只能发送或接收8或16位(取决于我选择的usart寄存器,即单/双输入/输出)。由于它是32位MCU,因此我认为我最好绕过32位字段,因为(据我所知)这是对MPU的一种更有效的使用。同样适用于64位MPU,即传递64位整数。也许那是误导的建议,或者是脱离上下文的建议。

考虑到这一点,我已经通过移位将8位压缩为32位字段。我在usart上为TX和RX都这样做。

仅8位寄存器的代码如下(16位寄存器只有一半的移位位数):

int zg_usartTxdataWrite(USART_data*         MPI_buffer,
                        USART_frameconf*    MPI_config,
                        USART_error*        MPI_error)
{

MPI_error = NULL;

if(MPI_config != NULL){
    zg_usartFrameConfWrite(MPI_config);
}

HPI_usart_data.txdata = MPI_buffer->txdata;

    for (int i = 0; i < USART_TXDATA_LOOP; i++){
        if((USART_STATUS_TXC & usart->STATUS) > 0){
            usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
        }
        usart->IFC |= USART_STATUS_TXC;
    }
    return 0;
}

编辑:重新输入上述代码的逻辑,并在注释部分中讨论了三元算子隐式提升问题的清晰度,并添加了定义

(HPI_usart和USART_data结构是相同的,只是级别不同,此后,我删除了HPI_usart层,但是为了这个示例,我将其保留在其中)

#define USART_TXDATA_LOOP 4
#define SINGLE_BYTE_SHIFT 8

typedef struct HPI_USART_DATA{

   ...
   uint32_t txdata;
   ...

}HPI_usart

HPI_usart HPI_usart_data = {'\0'};

const uint8_t USART_TXDATA_DATABITS = 0xFF;

int zg_usartTxdataWrite(USART_data*         MPI_buffer,
                        USART_frameconf*    MPI_config,
                        USART_error*        MPI_error)
{

MPI_error = NULL;

if(MPI_config != NULL){
    zg_usartFrameConfWrite(MPI_config);
}

HPI_usart_data.txdata = MPI_buffer->txdata;

    for (int i = 0; i < USART_TXDATA_LOOP; i++){
        if((USART_STATUS_TXC & usart->STATUS) > 0){
            usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
        }
        usart->IFC |= USART_STATUS_TXC;
    }
    return 0;
}

但是,我现在意识到这可能导致比解决方案更多的问题,因为我本质上是对这些位进行内部编码,然后当它们传入/传出不同的数据层时几乎必须立即对其进行解码。我觉得这是一个聪明而性感的解决方案,但是我现在正试图解决一个我本不应该创建的问题。就像如何在存在偏移量时提取变量位字段,即在gps nmea句子中,前8位可能是一个相关字段,然后其余是32位字段。所以最终变成这样:

32位数组成员0:

 bits 24-31      bits 15-23          bits 8-15            bits 0-7

| 8位值| 32位值A,位24-31 | 32位值A,位16-23 | 32位值A,第8-15位|

32位数组成员1:

 bits 24-31             bits 15-23           bits 8-15               bits 0-7

| 32位值A,位0-7 | 32位值B,位24-31 | 32位值B,位16-23 | 32位值B,位8-15 |

32位数组成员2:

 bits 24-31        15-23 8-15 ...

| 32位值B,位0-7 |等... | .... | .... |

上面的示例需要手动解码,我想这很好,但是每个nmea语句都不同,并且感觉比编程更具手动性。

我的问题是:位移位与数组索引比较合适?

是否应该将每个传入/传出的值分配给32位数组成员,然后以这种方式进行索引?我觉得这是解决方案,因为它不仅使遍历其他层上的数据更加容易,而且我将能够消除所有这些移位逻辑,然后rx或tx函数之间的唯一区别就是数据走向的方向。

这确实意味着对接口和所得到的gps模块层进行了少量重写,但这听起来像是工作量少了,而且在我的项目初​​期也很便宜。

关于此的任何想法和一般经验也将很棒。

1 个答案:

答案 0 :(得分:2)

  

由于它是32位MCU,所以我认为我也应该绕过32位字段

这并不是程序员真正的使命。将8位或16位变量放入结构中。如果需要,让编译器添加填充。另外,您可以使用uint_fast8_tuint_fast16_t

  

我的问题是:位移位与数组索引比较合适?

数组索引用于访问数组。如果有数组,请使用它。如果没有,那就不要。

虽然可以逐字节检查较大的数据块,但是必须更加仔细地编写此类代码,以免遇到各种细微的类型转换和指针别名错误。

通常,在访问最大为CPU字大小的数据(在这种情况下为32位)时,最好使用位移。它既快速又可移植,因此您不必考虑端倪。这是首选的整数序列化/反序列化方法。

相关问题